🐾

中身の数が動的に変わる、2 カラム List UI のスタイリング方法

2023/12/01に公開

この記事で分かること

中身の総数が偶数または奇数に変化する、 2 カラム構成の List UI におけるスタイリングで、特に border をきれいに付与する方法が分かります。
API から取得した値をリストに流し込むようなシチュエーションを想定しています。

List UI

先に結論

:nth 判定式 をおすすめします。

ul {
  display: flex;
  flex-wrap: wrap;
  background-color: #f8f8f8;
}

li {
  width: 50%;
  border-bottom: 1px solid #ccc;

  &:last-of-type {
    border-bottom: none;
  }

  &:nth-of-type(odd) {
    border-right: 1px solid #ccc;

    /* 全アイテムが偶数だった場合の、最後から 2 番目の奇数要素 */
    &:nth-last-of-type(2) {
      border-bottom: none;
    }
  }
}

様々な攻略方法

今回のデザインおよび HTML の実装要件は、

  • リスト(コンテナ)の上下左右には border をつけない
  • それぞれのセル同士は border で区切られる
  • リストは背景色を持っている
  • 総数が奇数のときに、最後に空の li を生成してはならない

となっています。この border 処理が曲者なので、いくつかの攻略方法を考案します。

grid 式

display: grid;gap 、そして background-color を用いてみます。
ギミックとしてはこうです。

  1. display: grid; で 2 カラム構成にする
  2. ul に対して、 border にしたい色と同一の background-color を付与する
  3. border にしたい太さと同一の gap を付与する
  4. li に背景色の background-color を持たせる

gap の隙間から下地の background-color を覗かせ、 border っぽく見せてしまおうという技です。
……何か様子がおかしいですね……。
そうです、総数が奇数の場合に ul の background-color が最後に表示されてしまっているんですね。
何も中身がないセルに対しても li と同じ background-color を付与するという技が使えればいいのですが、
記事の公開時点(2023/12/01)では grid はそのようなスキルを保有していないようです…。
必ず総数が偶数になることが確定しているならこの方法も良さそうですが、奇数パターンもある状況であれば、最適な攻略法とは言えません。

::before + absolute 式

擬似要素と absolute を用いてみます。
ギミックはこうです。

  1. ul の ::before に、 border と同一の widthbackground-color 、そして height に 100% を持たせる
  2. ul 自身に position: relative; を付与する
  3. ul の ::beforeposition: absolute; を付与して、 left: 0; right: 0; margin: 0 auto; で左右中央に配置する

::before で縦方向の border を再現してしまおうという実装です。
ぱっと見上手くいっているような…?もしや討伐成功?
しかしデザイン要件を思い出してください……今回は「コンテナの上下左右には border をつけてはいけない」のです。
奇数パターンに至っては、隣に li 要素が存在しないため、なんとも中途半端な下 border が付いてしまっていますね。スタイルデバフです。よって、これも適した攻略法ではありません。

:nth 判定式

最後に、 :nth を用いた border 処理法を試してみましょう。
ギミックの解説をします。

  1. li は、まずは決め打ちで border-bottom を持たせる
  2. li の :last-of-type (最後の要素)には、 border-bottom が付かないようにする
  3. li の :odd (奇数)には、 border-right が付くようにする
  4. li の :nth-last-of-type(2) (最後から 2 番目の要素)が :odd (奇数)だったとき、 border-bottom が付かないようにする

手順 4 が特にポイントです。この指定がないと、総数が偶数だったとき、最後から2番目の要素に border-bottom が付いてしまいます。(ぜひ CodePen でお試しください)

NG border

総数が偶数のとき最後から 2 番目の要素は必ず奇数になり、総数が奇数のときは最後から 2 番目の要素は必ず偶数になることを利用しています。
手順 2 で「最後の要素には border-bottom を付けない」と指定しているため、総数が奇数のときは見た目がきれいに整うのですが、
もし手順 4 を記述しないと、あくまで「最後」の border-bottom しか消されないので、総数が偶数になったとき、最後から 2 番目の要素にはぐれ border-bottom が出現してしまうのですね。
この処理法であれば、偶数奇数どちらのパターンが来てもスタイルが崩れることはなさそうです!
(ここで高らかな勝利のファンファーレ)

おわりに

前提となる要件に沿った結果このような実装方法となりましたが、前提が変われば解法も変わるのではないかなと思います。
同じ要件で border の扱いに困ってしまったとき、ぜひ :nth 判定式 をお試しいただけると嬉しいです。

Discussion