Unformed Building

width: fit-contentを使った、ちょっとした配置テクニック

公開:

パーマリンク

ウェブページの本文エリア内で、たとえば補足や余談などのデザインを区別して配置したいという場合があります。
その際、そのブロックのレイアウトを次の条件にしたいとします。

  • ブロック全体をインデントする
  • ブロック内テキストの行頭は揃える
  • ブロック内のもっとも長い行の末は本文の行末に揃える

これが実際に使われた場合、表示されるパターンはおおよそ3つ、そしてその複合パターンがあります。

  • 短い1行パターン
    本文レイアウトの概要図です。本文に続いて、インデントされた範囲があります。その範囲内にあるのは、短く、1行で収まる長さの文です。文の行末は本文の行末と同じ位置になりますが、行頭は本文の行頭よりかなり遠い位置にあります。自身の行の長さに応じてインデントの距離を広げています。
  • 長い1行パターン
    本文レイアウトの概要図です。本文に続いて、インデントされた範囲があります。その範囲内にあるのは、少し長いものの、1行で収まる長さの文です。文の行末は本文の行末と同じ位置で、行頭は本文の行頭の近い位置にあります。
  • 複数行パターン
    本文レイアウトの概要図です。本文に続いて、インデントされた範囲があります。その範囲内にあるのは、折り返さなければ範囲内に収まらない長さの文です。概要図では3行目の途中まで到達しています。文の行末は本文の行末と同じ位置で、行頭は本文の行頭の近い位置にあります。
  • 複数行、複数段落のパターン
    本文レイアウトの概要図です。本文に続いて、インデントされた範囲があります。その範囲内には、折り返さなければ範囲内に収まらない長さの文があります。次に、段落をかえて、折り返さなくても収まる程度の長い1文、そして改行を挟んで短い1文があります。もっとも長い文の行末は本文の行末と同じ位置で、すべての行頭は本文の行頭の近い位置に揃えられています。

これらのレイアウトを1つの部品として作成したいと思います。
(この記事のコードには現在は必要だとしてもベンダー接頭辞は記載していません)

<section>
  <h2>見出し</h2>
  <p>本文</p>
  <aside class="digression">
    <p>余談のようなもの</p>
  </aside>
  <p>本文</p>
</section>

このようなHTMLで、レイアウトを作成します。
なお、クラス名digressionの子要素は1つとは限らず、その内容の長さも不定とします。

このレイアウトを実現するためにfit-contentキーワードは非常に優秀で、単純なコードで実現することができます。

.digression {
  margin-left: auto;
  padding-left: 3em;
  width: fit-content;
}

fit-contentを使ったデモ

padding-leftで、最低限確保したい左の空白を指定します。
margin-leftは、要素を右側に移動させる指定です。margin: 0 autoを使った中央寄せや、FlexboxでFlex itemを左や右に寄せるのにも使われているのを頻繁に見かけるので、みなさんご存知でしょう。
そしてwidthfit-contentキーワードを指定します。

たった3行で終了です。

fit-contentについては2013年にも書いていますが、あのころとは状況が違っていて、fit-contentは関数になる予定です
そうなったときには、このコードは動いていない可能性が高いです。
しかし関数としてのfit-contentは、現在ではCSS Gridで見慣れていることでしょうし、そちらのほうが馴染みやすいかもしれません。

それFloatでできるよ!

そうです。近いことはfloatを使えば実現できます。

.digression {
  float: right;
  margin-left: 3em;
}

.digression + * {
  clear: both;
}

Floatを使ったデモ

しかし、この方法ではマージンの相殺が発生する場所としない場所について考える必要があります。
今回のデモの場合はp要素のマージンを下方向に統一することで回避できます(デモページは調整していません)。

こちらのメリットはfit-contentが使えないブラウザーでも対応可能なことです。

それGridでできるよ!

そうです。近いことはdisplay: gridを使えば実現できます。

.digression {
  display: grid;
  justify-content: end;
  margin-left: 3em;
}

Gridを使ったデモ

おや、こちらもたったの3行ですね。

しかし、この方法ではマージンの相殺が発生しないことについて考える必要があります。
今回のデモの場合はクラス名digression要素の前後の要素、または自身の子要素の最初と最後のマージンを調整する必要があります(デモページでは調整していません)。

こちらのメリットは「今後は安定していそう」というところでしょうか。

fit-contentを使ったコードは将来的な不安はあるものの、マージンの相殺について考えなくてもよいというのは非常に楽です。

このレイアウトの場合、対応している環境に向けて@supportsを使って分離し、そうでない環境にはインデントだけしておく、またはtext-align: rightしておくだけでも十分な気がします。
もしくはFloatを使っておくか。

どの方法も一長一短なので、やるなら好きなものを選べばよいと思います。