コハム

Webクリエイターのコハムが提供する、Web制作に役立つ情報をまとめたブログです。

1分で分かる!CSSグリッドでposition:absoluteがこんなに楽になる裏ワザ

Absolute positioning with CSS grid

記事は上記記事を意訳したものです。

※当ブログでの翻訳記事は元サイト様に許可を得て掲載しています。


これは、CSSグリッドを使用して要素を重ね合わせることができるという、皆さんへの親切なお知らせです。この機能はグリッドの特徴として常に存在し、広く書かれてきましたが、実際のウェブサイトではほとんど使用されているのを見かけません。なぜでしょうか?グリッドは2017年までに主要なブラウザで使用可能になったので、新しいものではありません。新しいパターンや技術を採用しない私自身の言い訳は、古い習慣は簡単には変わらないということです。

しかし、私たちの技術を見直すことは、小さな範囲に限定すると、時にはそれほど大変ではありません。

実際の変換例

最近、thoughtbot.comのループするビデオコンポーネントの下にキャプションを挿入する機能を追加しました。このビデオコンポーネントには、ビデオの右下に表示される一時停止/再生ボタンも含まれています。このボタンは、ボタン要素とビデオの両方を包む親要素に対して絶対的に配置されていました。

<figure>
  <button>再生/一時停止</button>
  <video autoplay muted loop playsinline src="/">
  <figcaption>ここにキャプションが入ります。</figcaption>
</figure>
figure {
  position: relative;
}

button {
  bottom: 0;
  position: absolute;
  right: 0;
  z-index: 999;
}

video {
  display: block;
  width: 100%;
  height: auto;
}

このコードは、figcaptionがない場合は完璧に動作します!しかし、同じCSSで新しい要素を挿入すると、一時停止/再生ボタンがビデオではなくキャプションと重なってしまいます。

[画像:キャプションの一部がボタンで隠れている携帯電話の画面のモックアップ]

ボタンはfigureコンテナ(figcaptionもその中に含まれています)に対して相対的に配置されているため、右下の角は現在、ビデオ要素ではなくテキストが表示されている場所になっています。

これは、絶対配置を維持できるようにHTMLのネスト構造を調整するなど、いくつかの異なる方法で修正できます。この場合、最も迅速な解決策はCSSグリッドをわずかに調整することでした。

figure {
  display: grid;
}

button {
  grid-area: 1 / 1;
  z-index: 999;
}

video {
  display: block;
  grid-area: 1 / 1;
  width: 100%;
  height: auto;
}

figureをdisplay: grid;と宣言し、videoとbutton要素の両方に同じgrid-areaを設定することで、両方のアイテムをグリッド上の同じ位置に配置するよう指示しました。この例の1 / 1の部分は、grid-column-start: 1grid-row-start: 1の省略形で、アイテムを最初の列と行のラインに配置します。これだけでほとんどの問題は解決しますが、デフォルトでは、ボタンはビデオが占める幅と高さ全体を占めてしまいます。

ボタン要素にplace-self: end;を追加すると、右下の角に配置されます。これはまさに私たちが望んでいた場所です!place-selfalign-self: end;(要素をコンテナの下端に配置)とjustify-self: end;(要素をコンテナの右端に配置)の省略形です。

button {
  grid-area: 1 / 1;
  place-self: end;
  z-index: 999;
}

グリッド化されたループするビデオコンポーネントは、position:absoluteを使用していたときとまったく同じように見えますが、再生ボタンの位置を損なうことなく、より多くの子要素を処理できるようになりました。

ビデオの上に配置されていても、ボタンはまだドキュメントフロー内にあります。絶対配置は要素をフローから取り除き、高さのない要素を作成し、後続の要素が重なる可能性があります。この特定のケースでは必ずしも問題ではありませんが、要素をドキュメントフロー内に保つことで、特に異なるビューポートサイズに適応する必要がある場合に、レイアウトの問題を防ぐことができます。

疑似要素を使用したグリッド

display:grid::beforeおよび::after疑似要素も、子グリッドアイテムのように動作します。Boston Ruby Groupのウェブサイトには、装飾的なグラデーションスクエアをヒーロー画像に重ねたヘッダーがあります。

これらの装飾的なグラデーションは、グリッド内の::beforeおよび::after要素です。

<header class="hero">
  <picture class="hero__media">
    <source media="(min-width: 80em)" srcset="images.jpg">
  </picture>
  <div class="hero__content">
    // 見出しコンテンツ
  </div>
</header>
.hero {
  grid-template-columns: repeat(7, 1fr);
  grid-template-rows: repeat(4, 0.5fr);
}

.hero::before,
.hero::after {
  content: "";
  display: block;
  opacity: 0.75;
}

.hero::before {
  background-image: linear-gradient(to bottom, var(--color-red), var(--color-teal));
  grid-column: 1 / 4;
  grid-row: 1 / 4;
}

.hero::after {
  background-image: linear-gradient(to bottom, var(--color-purple), var(--color-red));
  grid-column: 7 / 8;
  grid-row: 3 / 5;
  transform: translateY(2.5rem);
}

.hero__media {
  grid-column: 2 / 8;
  grid-row: 1 / 5;
}

.hero__content {
  grid-column: 3 / 6;
  grid-row: 4 / 5;
}

この例の各要素は、7列4行のグリッド上に明示的な開始点と終了点を持っています。::beforeグラデーションは左上から始まり、4行目と4列目で終わります。そして、重なり合った外観を本当に際立たせるために、ヒーロー画像は2番目の列線から始まるようにオフセットされています。

transformの助けを借りて、グリッドからわずかに飛び出すこともできます。:afterグラデーションは、translateYの助けを借りて、最後のグリッド行ラインの2.5rem下に押し下げられています。

グリッドラインを使用することで、各要素を正確な位置に移動させることができます。

でも、まだposition:absoluteを使えますよね?

もちろん、あなたの好きなようにしてください。CSSや一般的なWeb開発の素晴らしい点は、通常、何かを達成するための正しい方法が1つだけではないということです。特に今日のCSSは、レイアウトの決定に関して多くの柔軟性と創造的な自由を提供しています。試行錯誤の末に見つけたパターンが十分に機能している場合、必ずしも新しいやり方を採用する必要はありません。

©コハム