✴️

Stackレイアウトを使ってmarginの負債を回避する

2023/08/24に公開

Stackレイアウトとは

個別の要素にマージン設定は行わず、兄弟要素の間隔を制御することでレイアウトを行う手法。
勝手に名付けましたが、特に新しいものではなく、基本的な考え方は「EVERY LAYOUT」のThe Stackで紹介されています。
UIフレームワークではChakra UIやMaterial UIなどでStackコンポーネントが用意されています。

従来のmarginレイアウト

ここでは要素ごとにmargin-topやmargin-bottomを設定しレイアウトする手法のことをmarginレイアウトと呼ぶことにします。

例えば、見出しとその下に配置されるテキスト要素が存在する場合、まず初めに検討されるレイアウトの方法になると思います。

<h1 class="title">見出し</h1>
<p class="text">テキストテキストテキストテキスト</p>

<style>
.title {
  margin-bottom: 16px;
}
</style>

とてもシンプルで誰にでも理解できる最適なレイアウトです。

marginレイアウトの問題点

では以下のような、よくあるカードコンポーネントの場合はどのようなレイアウトになるでしょうか。

CSSのスキルがある程度あれば、今後発生するであろうバリエーションや運用時に発生する要素の有無などを事前に考え、どこをグルーピングしmargin-top、もしくはmargin-bottomを設定すべきか判断し、適切なレイアウトを行うことができると思います。

ただ開発規模が大きかったり、スキルが高くない人が多い案件などでは先を見据えたマークアップ、スタイリングが行われず、以下のようにすべての要素を並列に、margin-bottomでレイアウトされることがよくあります。

この状態でもデザインの再現はできており見た目上問題はありません。

では運用を行う中で「有効期限」が不要なパターン、「見るボタン」が追加されるパターンが出てきた場合どうなるか。

  • 「有効期限」がなくなることで「有効期限」が持っていたmargin-bottom:24pxが消え、
    「ポイント」と「使うボタン」の間の間隔が8pxになります。改修が必要です。
  • 「見るボタン」が追加されますが、「貯めるボタン」にmargin-bottomがいないため2つのボタンがくっついています。改修が必要です。

運用が行われる中で「有効期限」だけではなく、ボタンの増減、赤字の重要テキストの追加など様々なバリエーションが生まれるはずです。そのたびにこのコンポーネントはCSSやhtmlの構造の修正が行われることになります。

カードコンポーネント1、カードコンポーネント2といったように「ちょっとだけ違うバリエーションコンポーネント」が生まれることもよくあります。

コンポーネント一つだけを見ればそれほど大変な修正ではないですが、一つのコンポーネントがこの状態の場合、大抵はサイト全体が同様の状況になっています。

結果、少しの変更でも大きな改修コストが必要になるとても難しいwebサイトの誕生です。

Stackレイアウト

Stackレイアウトの基本はフクロウセレクタです。身近なところだとリスト要素の間隔設定に使うと楽ができます。

<ul class="stack">
  <li>リンゴ</li>
  <li>みかん</li>
  <li>さる</li>
</ul>

<style>
.stack > * + * {
  margin-top: 8px;
}
</style>

ul要素でフクロウセレクタを利用することで、子のli要素それぞれでスタイルを書く必要はありません。

この状態ではli要素が1個でも100個でもcssに修正は必要なくhtmlを直すだけで終わります。

Stackレイアウトでは、この考え方をul要素など一つの要素に限定させずにサイト全体に適用していきます。

Stackレイアウト例

marginレイアウトの例で使用したカードコンポーネントにStackレイアウトを適用する場合の一例です。

基本的には要素間の間隔ごとにグルーピングします。その他、間隔が同じでもheader、body要素など要素が持つ役割などで追加でグルーピングを行うとhtmlがわかりやすくなります。

青、赤、緑で囲っているところがそれぞれ値の違うstackです。

<div class="stack-24">
  <div class="stack-16">
    <h3>ポイント数</h3>
    <div class="stack-8">
      <p>2023/01/01〜2023/12/31期間の合計ポイント数</p>
    </div>
  </div>
  <div class="stack-8">
    <div>
      <p>1,000 point</p>
    </div>
    <div class="stack-8">
      <p>有効期限:2024/12/31</p>
    </div>
  </div>
  <div class="stack-16">
    <button>使う</button>
    <button>貯める</button>
  </div>
</div>

marginレイアウトで問題が発生した「有効期限」が消えた場合、「ボタン」が増えた場合はStackレイアウトでは以下のようになり適切な間隔が保たれます。

追加、削除された分のhtml修正は必要ですが、cssの修正は不要です。

利用箇所は小さなコンポーネントだけではなく、コンテンツエリアのheader、body、footerの間隔、body内の各要素の間隔設定用にstack利用するなど、サイト全体で考えることができます。

Stackレイアウトの大きなメリット

要素の増減によるcss修正が不要になる、要素変更に強くなるなどのメリットを説明しましたが、さらに大きなメリットととして、開発メンバーのスキルに左右されずらくなる、というところがあります。

marginレイアウトの時の例にあったすべての要素が並列に配置されてしまうなどの問題はStackレイアウトでは発生しなくなります。

もちろんスキルにより適切なグルーピングを行えない場合はあると思いますが、グループごとに要素間隔が限定されるという制約上、一定の構造化は必ず行われます。

またreactなどのJSフレームワークではさらに大きなメリットとして、すべてのレイアウトをコンポーネント化することができるようになります。(この記事ではこれ以上の言及はしません。)

デザイナーと連携が必須、さらなる効率化のために

Stackレイアウトは開発側に大きなメリットをもたらしますが、とても大事な前提条件があります。それがデザインデータ。

デザインデータ側で適切なデザインシステム(トークン)管理が行われていることが必須です。

デザインシステムが存在せず、要素ごとにバラバラな間隔設定、感覚が大事にされた1pxレベルで微調整が行われているようなレイアウトでは利用することができません。

ここは開発側とデザイン側でうまく認識合わせを行いStackレイアウトに適したデザインデータを作成してもらう必要があります。

Figmaでオートレイアウト縛りのデザインデータを作成してくれるデザイナーさんがいると、ほぼそのままStackレイアウト化できるので最高の効率でレイアウトが行えるようになります。最高。

Stackレイアウトを使う

  • CSSを直接書く場合
    • EveryLayoutを参考にする
    • flex、gridでgapを利用する
      • ★gridがサポート状況もよく、手軽でおすすめ
  • JSフレームワーク
  • tailwindならspace between

それではよいStackレイアウトライフを。

Discussion