Quantcast
Channel: CSSタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8822

フロートした画像の横に下揃えでテキストを配置する方法

$
0
0

CSSで左側に画像、右側にテキストのブロックをフロートで横並びに配置して、画像のキャプションのテキストを右下に下揃えで表示したい(下図)。簡単にできそうですが、意外な落とし穴があったので解決策のメモです。
fig_01_w600.png

画像出典: Lorem Picsum Images from Unsplash

ダメな例

まずは失敗例から。画像、右側の本文およびキャプションの3つをそれぞれブロック要素で囲んでdiv.boxに入れてみました。キャプションの要素p.captionposition使って、div.boxを基準にbottom/leftで絶対位置指定してやれば実現できそうです(下図)。

fig_sample-ng_w700.png

HTML(要点のみ)
<divclass="content"><divclass="box"><divclass="pic"><imgsrc="https://picsum.photos/id/1059/300/400"alt=""></div><divclass="col-txt"><p>情に棹させば流される。...(略)</p></div><pclass="caption">Lorem ipsum dolor sit amet, ...(略)</p></div></div>


CSS(要点のみ)
.content{width:800px;margin:20pxauto0;}.box{overflow:hidden;position:relative;}.pic{float:left;width:28%;}.picimg{width:100%;height:auto;vertical-align:bottom;}.col-txt{float:right;width:70%}.caption{font-size:0.8rem;line-height:1.2;position:absolute;bottom:0;left:30%;}

なんだ簡単!? では、この画面でブラウザの文字サイズを大きくしていったら何が起きるでしょうか? 画面のズームではないです。文字だけの拡大です。Firefoxの場合、メニューの「表示/ズーム/文字サイズの変更」を有効にすれば文字だけ拡大できます。
fig_02_w400.png
Command+「+」を打ちながら文字を300%まで拡大してみると…
video_sample-ng_trim.gif
ご覧のように、文字サイズを170%以上にすると、上側の本文テキストが“侵食”してきてキャプションの表示に重なってしまいました。これは、position: absoluteを使って配置した要素は通常のフローから外れるため、本文テキスト側はこの要素が存在しないかのように配置されるので発生します。

ちなみに、ウェブアクセシビリティに関するJIS-X8341-3:2010「7.1.4.4 テキストのサイズ変更に関する達成基準 (等級AA)」1によると、テキスト拡大200%までは他のコンテンツと重ならないようにサイズ変更できることを要求しています。

解決策

position: absoluteを使わない方法を考えてみましょう。

まず、要素の構成を変えます。p.captiondiv.boxの外側に出して兄弟要素にします(サンプルでは共通の親はdiv.content)。そして、margin-leftで画像の幅だけ右に寄せて、margin-topにキャプションの行数分の高さのネガティブマージンを指定してテキストの位置を引き上げることで、画像と下揃えにできます(下図)。
fig_sample-1_w700.png

HTML(要点のみ)
<divclass="content"><divclass="box"><divclass="pic"><imgsrc="(略)"alt=""></div><divclass="col-txt"><p>情に棹させば流される。智に働けば角が立つ。...(略)</p></div></div><!-- div.boxの外側にp.captionを移動 --><pclass="caption">Lorem ipsum dolor sit amet, ...(略)</p></div>


CSS(要点のみ)
.content{/* 変更なし */}.box{overflow:hidden;}.pic{/* 変更なし */}.picimg{/* 変更なし */}.col-txt{/* 変更なし */}.col-txtp{padding-bottom:calc(3*1.2*0.8rem);/* 追加 */}.caption{font-size:0.8rem;line-height:1.2;margin-left:30%;/* 追加 */margin-top:calc(-2*1.2*0.8rem);/* 追加 */}

ネガティブマージンの量は、計算式
(キャプションの行数)×(line-height)×(font-size)
で見積もれます。本サンプルでは、キャプションのテキストが2行(ブラウザで文字サイズを変更していない場合)になるという前提で、以下のプロパティを設定しています。

.caption{margin-top:calc(-2*1.2*0.8rem);}

下図はp.captionのコンテント(背景色 ライトブルー)に関して、元の位置から最終的な表示位置までの動きを示したアニメーションです。ラッパーdiv.contentの境界を赤い線で示しました。
video_demo_1_trim.gif
p.captionを通常フローに置いたことにより、文字拡大時の振る舞いは次のようになります。

  1. キャプションのコンテンツボックスは、ネガティブマージンにより2行分div.box食い込んだ状態でページの下側に伸びていく
  2. 本文テキストの領域(背景色 黄色)が膨らんでdiv.boxの高さが増えると、p.captionのボックスもページの下側に流れていく
  3. p.captionの領域が本文テキストと重なる可能性が残るのは、div.boxに食い込んだ2行分の高さ

残る課題は上記3への対応ですが、position: absoluteのときと違って、食い込みの高さが2行分に抑えられることがポイントです。そこで、本文テキストのp要素の下側にpaddingを少なくとも3行分入れてやれば、それがのりしろとなって、p.captionから食い込んだ2行を吸収できます。つまり、paddingの量は余白1行を考慮すると、計算式
(キャプションの行数 + 1)×(line-height)×(font-size)
で見積もれます。本サンプルでは以下のように設定しました(上図で背景色が黄色い領域)。

.col-txtp{/* 本文テキスト */padding-bottom:calc(3*1.2*0.8rem);}

本文テキストが複数のp要素から成る場合は、(1) 最後のp要素にpaddingを設定する、もしくは(2) div.boxの右側float要素に擬似要素で3行分の高さを埋め込む、などの方法で対応できます。

(1)
.col-txtp:last-child{/* 最後のp要素にpadding */padding-bottom:calc(3*1.2*0.8rem);}
(2)
.col-txt:after{/* float要素の後ろに空のブロックを追加 */display:block;content:"";height:calc(3*1.2*0.8rem);}

以上の対策を施した上で、ブラウザで文字サイズを300%まで拡大してみましょう(下図)。
video_sample-1_trim.gif
文字サイズ170%の所で、上側から下りてきた黄色ののりしろがライトブルーの領域に重なり、ライトグリーンで示した領域に2行分のテキストが吸収されたのがわかります。以降、テキストを拡大してもキャプションが下へ押しやられるだけで、テキストの重なりは発生しません。

本記事のサンプルコードはこちら: https://codepen.io/kaz_hashimoto/pen/gOaOXKj


Viewing all articles
Browse latest Browse all 8822

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>