PR

【position: absolute なし】display: gridを使って要素を重ねる

HTML/CSSを学ぶ

こんにちは。今回は、最近見かけたdiplay: gridを使って要素を重ねる方法について考えていこうと思います。

デモ

ブログなどの記事一覧でよく見るカードの形です。左上のタグが画像に重なっています。

デモサイトはこちら。

Document

結論

結論から言えば、gridレイアウトを作り同じセルに複数の要素を置くとそれらが重なります。

シンプルな例を出します。正方形を5個重ねます。

<div class="Container">
  <div class="Child" style="background-color: red"></div>
  <div class="Child" style="background-color: green"></div>
  <div class="Child" style="background-color: blue"></div>
  <div class="Child" style="background-color: yellow"></div>
  <div class="Child" style="background-color: pink"></div>
</div>
.Container {
  width: 500px;
  height: 500px;
  display: grid;
}
.Child {
  grid-area: 1/1;
  width: 100%;
  height: 100%;
}

こうすると、ピンクの正方形が1つ表示されます。

では、どれでも良いのでz-indexを指定します。ここでは青にしてみます。

<div class="Container">
  <div class="Child" style="background-color: red"></div>
  <div class="Child" style="background-color: green"></div>
  <div class="Child" style="background-color: blue: z-index: 10"></div>
  <div class="Child" style="background-color: yellow"></div>
  <div class="Child" style="background-color: pink"></div>
</div>

すると青い正方形が表示されます。

このような形で、gridレイアウトで同じセルの場所に複数要素を置くことで重なりが表現できました。

デモの解説

デモのような実践的な場面でどう使うかを見ていきましょう。display: grid;を使う都合上いくつか気を付けるポイントがあります。

まずはタグ以外のカード部分です。

<article class="Card">
  <img src="./resources/images/logo-css.png" alt="" class="Card-Thumbnail" />
  <div class="Card__Bottom">
    <h2 class="Card-Title">gridで要素を重ねる</h2>
    <p class="Card-Content">
      ダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキスト
    </p>
  </div>
</article>
.Card {
  box-shadow: 0 0 12px 4px rgba(0, 0, 0, 0.4);
  width: 100%;
  max-width: 500px;
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
}

.Card-Thumbnail {
  width: 100%;
}

.Card__Bottom {
  width: 100%;
  padding-left: 16px;
  padding-right: 16px;
  padding-bottom: 16px;
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
}
.Card-Title {
  font-size: 20px;
  font-weight: bold;
}
.Card-Content {
  font-size: 14px;
  line-height: 1.5;
}

.Card__Bottom以下は今回のレイアウトには関係ないので流してOKです。.Cardにgridを適用していることがポイントです。

続いてタグの部分を作りましょう。タグの要素は.Cardの直下、画像と並列になっていればどこでも良いです。

<article class="Card">
  <div class="Card-Tag">HTML/CSS</div>
  <img src="./resources/images/logo-css.png" alt="" class="Card-Thumbnail" />
  <div class="Card__Bottom">
    <!-- 省略 -->
  </div>
</article>
.Card-Tag {
  padding: 4px;
  background-color: #0095d9;
  color: #fff;
}

この時点ではこんな感じ。

では重ねていきます。grid-areaというプロパティで、画像とタグを同じ位置に配置します。

.Card-Tag {
  grid-area: 1 / 1; /* 追加 */
  padding: 4px;
  background-color: #0095d9;
  color: #fff;
}

.Card-Thumbnail {
  grid-area: 1 / 1: /* 追加 */
  width: 100%:
}

grid-areaはgridレイアウトの位置を数字などで明示的に指定するプロパティです。1 / 1とすると左上のセル1つ分の領域を確保します。今回は縦は1列のみなので、一番上に配置されます。

詳しくは以下より。

grid-area - CSS: カスケーディングスタイルシート | MDN
grid-area は CSS の一括指定プロパティで、 grid 内でのグリッドアイテムの寸法と位置を指定するために、線、区間、なし (自動) をグリッド配置に適用することで、グリッド領域の縁を指定します。

またgridレイアウトの数値についてはちらをご覧ください。ざっくりいうと縦横のグリッド線に左上からそれぞれ1、2、3・・・と番号が割り振られています。

Grid Areas (グリッド領域) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN
グリッド領域はグリッド上で一つ以上の グリッドセル からなる長方形の領域です。グリッド領域は ライン指定による配置 や 名前付きグリッド領域で領域を定義すると作成されます。

こうするとタグと画像が重なります。

さて、タグ部分が裏へいってしまったのでz-indexを指定しましょう。

.Card-Tag {
  grid-area: 1/1;
  z-index: 10; /* 追加 */
  padding: 4px;
  background-color: #0095d9;
  color: #fff;
}

するとこうなります。

おっと、タグが大きすぎますね。これがgridレイアウトを使ったことによる注意点で、同じセルに配置した要素は基本的にセルのwidth / height のサイズになります。

これでは要素を重ねられたとしても使えません。何らかの数値で指定する方法もありますが、動的コンテンツの場合はそれだとうまく表示するのは難しいですね。

そこでサイズ指定にfit-contentというキーワードを使います。

.Card-Tag {
  grid-area: 1/1;
  z-index: 10;
  width: fit-content; /* 追加 */
  height: fit-content; /* 追加 */
  padding: 4px;
  background-color: #0095d9;
  color: #fff;
}

こうすると、コンテンツ分だけ領域を確保してくれます。従来のdisplay: inline-block;に近い挙動です。

このfit-contentは、「コンテンツ分の領域だけを確保+親要素をはみ出してしまう場合は折り返しを行う」という大変都合のいい指定方法です。今回の主題とは若干違いますが、ぜひ覚えてみてください。

fit-content - CSS: カスケーディングスタイルシート | MDN
fit-content は fit-content(stretch) として動作します。実際には、ボックスは利用可能な空間を使用しますが、 max-content 以上にはならないことを意味します。

ブラウザ対応もほぼ問題ないでしょう。

CSS property: width: `fit-content` | Can I use... Support tables for HTML5, CSS3, etc
"Can I use" provides up-to-date browser support tables for support of front-end web technologies on desktop and mobile w...

というわけで、gridを使って要素の重ねを表現することができました。

ただし・・・

と、ここまで解説しましたが個人的にはposition: absolute;を使う方法でも別にいい、あるいは場合によってその方法の方が良いこともありそうです。

理由はdisplay: gridの影響範囲の大きさです。今回の場合重ねたいのはタグと画像だけでした。しかし、そのためだけにコンテンツ部分のレイアウトにもgridが影響してしまいます。カードのようなレイアウトの場合はたまたま問題がありませんでしたが、場合によっては面倒ごとが起きることもあるでしょう。

タグと画像部分を要素で囲ってそこをgridにする手もあるでしょうが、単純に余計な要素が増えますし意味的にもそれらがグループかというと今回はちょっと違いますよね。

そういうわけで、あくまで選択肢の1つとして捉えるくらいが良いかなと考えています。もちろんposition: absolute;の扱いづらさは依然としてありますから、使いやすい方、安全な方を選択していきましょう。

ちなみに、gridレイアウトにおいては要素の重なりは想定されているようです。gridの特徴として明確に「コンテンツの重ね合わせや、z-indexによるレイヤーコントロール機能」が挙げられています。

the ability to overlap content and control layering with z-index

https://www.w3.org/TR/css-grid-2/#overview

まとめ

display: grid;による要素の重ね合わせについてでした。これまで要素を重ねる=position: absplute;でしたが、使える場面では使っていきたい方法ですね。

コメント

タイトルとURLをコピーしました