こなさんみんばんわ。
どうやら世間ではゴールデンウィークに突入したようですが、僕はそろそろ一年半近く続こうかという超長い休暇を今も絶賛満喫中、しかもまだまだ続きそうです。ドヤァ…😭

そんな話はさておき、このサイトの Explore JF.org ってページには年月別アーカイブのリストが置いてあるんですが、年ごとに横 1 列固定のままでは当然スマホなどでは入りきらないので、そういった狭い画面では月のリストが 2 列や 3 列になるように、@media で切り分けて調整しています。

画像 1: 桁揃え処理を入れる前の iPhone 16 Pro Max での見え方を Simulator で確認したもののスクリーンショット

ですが、この月リストの数字部分は liquid タグによる単純な 1 から 12 までの for ループで出力してるだけで、「1〜9 月の場合にはゼロ埋めして常に二桁の値にする」というような処理を入れてないんですね。なので、複数列になると一桁の月と二桁の月(10〜12 月)の縦列が漢字の「月」の位置で揃わないという問題がありました。

画像 2: 単純に右寄せにしたものの iPhone 16 Pro Max での見え方を Simulator で確認したもののスクリーンショット

もちろんこれは text-align: right で右寄せにすれば上の画像のように揃いますが、そうすると今度は左側に広めのすき間ができてしまいます。特に iPhone の Pro Max のような大きな画面だとけっこうな空白になるので、ちょっとバランス的によろしくない(個人の感想です)。かといってゼロ埋めするのもちょっと嫌(これも個人の感想ですが「04 月」とかテキストとして不自然じゃないですか)なのでやりたくないし…

ということで、とりあえず桁揃えはあきらめて、そこそこバランスが良さそうに見えた text-align: center にして長いことごまかしてたんですが😅 先日ふと「::before 擬似要素で 1ch 幅の空白を挿入する」というのを思いつきました。ch というのはその要素に指定されたフォントのグリフ “0” の送り幅を 1 とする CSS の単位なので、テキスト自体には変化を与えることなく実質的にゼロ埋めをするのと同じ効果を得られるんじゃない? という訳です。

See the Pen Alignment using 1ch wide ::before pseudo element by Jeffrey Francesco (@jforg) on CodePen.

☝️ のデモはこのサイトのコードそのままではなくてちょっと簡略化してあるのと、揃えを変えても機能することを示すためにあえて text-align: center を掛けてあったりしますが、キモの部分はまったく同じで次のコードです。

li:nth-last-child(n + 4)::before {
  content: '';
  display: inline-block;
  height: 1em;
  width: 1ch;
}

いちおう解説しておくと li:nth-last-child(n + 4) で最後から 4 番目以前の li 要素を選択して、その ::before 擬似要素を display: inline-block で生成して幅を 1ch に設定。これが li 要素内のテキストの前に挿入されることで「1 月」から「9 月」までのテキストがグリフ “0” の幅分後ろに押し出されるため、「10 月」から「12 月」と縦の位置がざっくり揃う、というロジックです。

注意点があるとすれば、たまに数字部分がデフォルトでプロポーショナルになってるフォントがあるので(このサイトで使ってる Inter がまさにそうですが)もしそのフォントが固定幅数字のグリフを持っているのであれば CSS で font-variant-numeric: tabular-nums と指定しておく必要があります。ない場合は…あきらめて他のフォントに変えるしかないですかね😭

画像 3: 1ch 幅の擬似要素を使って桁揃えしたものの iPhone 16 Pro Max での見え方を Simulator で確認したもののスクリーンショット

という訳で、実際に CSS にコードを加えて確認してみたところ、左右の空間のバランスも含めてけっこううまくいってるように感じましたので、先日よりサイトの方に反映しております。


まぁ :nth-last-child で要素選択している関係上、こういった月のリストのような決まった数字しか並ばないと分かってる場面でないと使えないので汎用性には乏しいですが、とりあえず長年の課題が解決したので個人的には由としておきます。

…全部書き終わってから思いついたけど、li:not(:nth-child(n + 10)) の方がまだ少し汎用的かもしれない。涙