おしゃれなデザインでよくある、画像だけコンテナ幅からはみ出して画面端まで広がり、テキストはコンテナ幅の範囲に配置されるデザイン。
position:absoluteなどを駆使して配置することもありますが、今回はpositionなしで実装してみましょう。
HTML構造
今回は以下のようなHTML構造を想定しています。
<div class="c-image-text">
<div class="c-image-text__image">
<img src="~~~" alt="">
</div>
<div class="c-image-text__text">
<h2>タイトル</h2>
<p>テキスト</p>
</div>
</div>
CSSの書き方と考え方
完成品のCSSは以下のようになります。
.c-image-text {
display: grid;
grid-template:
"image gutter text margin" auto /
calc(600/1440 * 100%) 16px 1fr max(calc((100% - 1100px)/2), 32px );
align-items: center;
}
.c-image-text--reverse{
grid-template:
"margin text gutter image" auto /
max(calc((100% - 1100px)/2), 32px ) 1fr 16px calc(600/1440 * 100%);
}
.c-image-text__image{
grid-area:image;
}
.c-image-text__image img{
height:300px;
width:100%;
object-fit:cover;
}
.c-image-text__text{
grid-area:text;
}
どのような考え方で上記のCSSが生まれたのか以下で解説します。
grid-templateの設定を考える
今回は以下の条件で考えます。
- 画像の横幅はデザインデータ上の比率で伸びる
- 画像とテキストの間のガターは、デザイン上のpx固定でよい
- テキスト部分の端はコンテナ幅と同一にしたい
そうすると、引きたいグリッドの幅は以下のように考えられます。
- 画像部分=画像の幅 / デザインの横幅 * 100%
- ガター部分=デザイン上のガターの幅px
- テキスト部分=1fr(その他の幅を計算で出すので、残りをテキスト部分にします)
- テキストの横のマージン=(画面の幅 – コンテナ幅) / 2
そうするとこんな感じ。
.c-image-text02 {
display: grid;
grid-template:
"image gutter text margin" auto /
calc(600/1440 * 100%) 16px 1fr calc((100% - 1100px)/2);
}
ただし、このままだと『テキストの横のマージン=(画面の幅 – コンテナ幅) / 2 』の部分は画面幅がコンテナ幅以下(たとえばコンテナ幅1100pxのときの1000px)のとき、値がマイナスとなりぶっ壊れます。
通常コンテナ幅をとる要素はmax-width+paddingというような感じで画面端になんらか余白を持つものですから…
.c-container {
max-width: 1100px;
margin-inline: auto;
padding-inline: 32px;
box-sizing: content-box;
}
たとえば以下のように、画面端には一定の余白を持ちたいですね。
そこで、テキストの横のマージンは(画面の幅 – コンテナ幅) / 2 または 指定のpx値 のいずれか大きいほう という指定に変えます。 max(calc((100% - 1100px)/2), 32px );
.c-image-text {
display: grid;
grid-template:
"image gutter text margin" auto /
calc(600/1440 * 100%) 16px 1fr max(calc((100% - 1100px)/2), 32px );
align-items: center;
}
※テキストの位置は画像に対して上下中央寄せにしたいためalign-items:center;
も追加しました。
エリアに要素を配置
先ほど定義したimageとtextのエリアに要素をあてはめます。
gutterとmarginのエリアには何も配置しません。
.c-image-text__image{
grid-area:image;
}
.c-image-text__text{
grid-area:text;
}
また、画像はある程度の高さに固定したいので以下のような形で画像のサイズを固定します。
.c-image-text__image img{
height:300px;
width:100%;
object-fit:cover;
}
画像だけコンテナ幅からはみ出て画面端まで広がるレイアウトの完成です。
左右反転したバージョンのレイアウトを作る
次に、左右反転したバージョンのレイアウトですが、今回のレイアウトの場合はgrid-template
の指定だけで事足ります。
.c-image-text--reverse{
grid-template:
"margin text gutter image" auto /
max(calc((100% - 1100px)/2), 32px ) 1fr 16px calc(600/1440 * 100%);
}
画像とテキストが重なり合う形の場合
画像の上にテキストが重なって配置されている場合はどうでしょう。
これもよく似たgrid-templateで実現できます
CSS
※HTMLはclass名以外ひとつめと同様です。
基本的な考え方はひとつめと同様。
画像とテキストの間のガターをなしにして、テキストの要素(__text)を重なりの距離分だけネガティブマージンで動かします。
このデザインの場合、左右反転させる際は親の要素のgrid-template以外に、子の要素(__text)のmarginも変更する必要があり少しコードが長くなります。
まとめると以下。
.c-image-text02 {
display: grid;
align-items: center;
grid-template:
"image text margin" auto /
calc(600/1440 * 100%) 1fr max((100% - 1100px)/2, 32px );
}
.c-image-text02--reverse{
grid-template:
"margin text image" auto /
max((100% - 1100px)/2, 32px ) 1fr calc(600/1440 * 100%);
}
.c-image-text02__image{
grid-area:image;
}
.c-image-text02__image img{
height:300px;
width:100%;
object-fit:cover;
}
.c-image-text02__text{
grid-area:text;
padding:20px 0 20px 20px;
margin-left:-100px;
background:#fff;
}
.c-image-text02--reverse .c-image-text02__text{
padding:20px 20px 20px 0;
margin-left:auto;
margin-right:-100px;
}
Chromeの開発者ツールで確認すると、グリッドから要素が飛び出しているのが確認できます。
まとめ
display:gridを使えば、コンテナ幅から画像だけはみ出したり、画像とテキストが少し重なったりするようなレイアウトもposition要らずで実装できました。
positionを使うときよりHTMLの構造がシンプルで分かりやすいかもしれません。
ぜひdisplay:gridを使って便利にレイアウトしていきましょう!
コメント