📏

CSS のおれおれ汎用レイアウトクラスのちょっとした問題を修正した話

2021/10/14に公開1

きっかけ

というツイートをしたついでに個人的メモとして、問題と解決策を記事にしてみました。
おれおれ CSS ですが、誰かの役に立てば幸いです。

問題

上記サンプルのような感じで、ネガティブマージンとパディングで折返しのあるフローレイアウトみたいなことをやっているんですが、
ネガティブマージンのせいで、前の要素に見えないスペースが重なってしまって、前のボタンがクリックできなくなっています。

ちなみに CSS は以下のような感じです。

/**
 * リセットCSSとして sanitize.css を読み込んでる前提
 * (なので、全ての要素が box-sizing: border-box )
 */

:root {
  --getup-flex-gap-size: 2em;
}

.o-layout {
  display: flex;
  
  /* 子要素の余白パディングを相殺するためのネガティブマージン */
  margin: calc(var(--getup-flex-gap-size) * -1) 0 0 calc(var(--getup-flex-gap-size) * -1);
  
  /* ul の場合はリスト由来のスタイルを殺しておく */
  list-style: none;
  padding-left: 0;
  
  /* 要素が空の場合の隣接要素への影響を相殺 */
  min-height: var(--getup-flex-gap-size);
}

.o-layout--wrap {
  /* 折返し有効可 */
  flex-wrap: wrap;
}

.o-layout > * {
  /* column レイアウトにした時に親サイズを超えてしまうバグに対応(これ、IE11用だった気がする…もういらないかも。。) */
  max-width: 100%;
  
  /* 子要素のパディングでギャップを実現 */
  padding: var(--getup-flex-gap-size) 0 0 var(--getup-flex-gap-size);
  
  /* 子要素サイズ指定 */
  flex: 0 1 auto;
}

/**
 * 表示用サンプルのスタイル
 */

.c-sample-width {
  width: 33.333%;
}

.c-sample-box {
  background: lightgray;
  height: 100px;
}

解決策

pointer-events で解決しました。

:root {
  --getup-flex-gap-size: 2em;
}

.o-layout > * > * {
  /**
   *【追加】親要素から引き継がれる pointer-events をリセット
   * .o-layout が入れ子になった時のために、こっちの設定を .o-layout より先に書いておく。
   */
  pointer-events: auto;
}

.o-layout {
  display: flex;
  margin: calc(var(--getup-flex-gap-size) * -1) 0 0 calc(var(--getup-flex-gap-size) * -1);
  list-style: none;
  padding-left: 0;
  min-height: var(--getup-flex-gap-size);
  
  /* 【追加】ネガティブマージンによって前の要素がクリック出来なくなる問題を解決 */
  pointer-events: none;
}

/* 以下略 */

余談

  • いまならもう gap が使えるんだからそれ使えばよくない?
    • レイアウトの余白を子要素の padding で実現してあげると、子要素のサイズ(幅)を指定する時に余白分を calc() とかで計算してあげる必要がなくてラク…( width: 25% とかすれば 4 分の 1 になる)
    • ただし、この .o-layout 要素とその直下の子要素は完全にレイアウト用の要素として扱って、装飾とか見た目の調整はその中の要素に対してやるのが無難。
    • このレイアウト用のクラスを入れ子にする時、.o-layout の直下の子要素を .o-layout にするのは NG(gap を使う場合に比べて HTML 要素のネストは増えちゃう)
  • overflow: hidden でもよくない?
    • 見た目の都合上そうしたくない場合もあるから別の解決方法を考えてた

Discussion

_H_R_⓿ᴥ⓿_H_R_⓿ᴥ⓿

すごく今更かもしれませんが親にdivを一つ増やしてdisplay:flow-rootを付与するとpointer-eventsを使わずに解決できるかもしれません。