CSS: only-child擬似クラスを使ってif/elseロジックを置き換える技(翻訳)
Railsフレームワークは面倒なタスクの多くを自動化して、手書きのコーディングを最小限に抑えられるので、Rails開発者は恵まれています。さらにHotwireのおかげで、カスタムJavaScriptの多くを手書きせずに済むようになりました。
しかし近年のCSSも非常に強力になってきているので、可能な場合はロジックを極力CSSで記述するようにしています。
そんな例のひとつは、「空」のステートを表示する場合です。
たとえばメッセージの受信ボックスが以下のようになっているとしましょう。
このときのHTMLは以下のような感じだとします。
<ul class="divide-y divide-gray-100">
<li>
<!-- ここでメッセージのプレビューを表示する -->
</li>
</ul>
編集部注
上のHTMLは以下のようなERBで生成されているとみなすとよいでしょう。
<ul class="divide-y divide-gray-100">
<% @messages.each do |message| %>
<li>
<!-- ここでメッセージのプレビューを表示する -->
</li>
<% end %>
</ul>
従来なら、以下のようにifやelse文を書いて場合分けしていたでしょう。
<ul class="divide-y divide-gray-100">
<li>
<!-- ここでメッセージのプレビューを表示する -->
</li>
<% if @messages.none? %>
<li>
<p class="text-base font-normal leading-tight text-center text-gray-400">
メッセージはありません
</p>
</li>
<% end %>
</ul>
しかしonly-child擬似クラスを使えば、以下のように分岐なしできれいに書けます(なお、ここではTailwind CSSのonlyというユーティリティクラスを使っています)。
<ul class="divide-y divide-gray-100">
<li>
<!-- ここでメッセージのプレビューを表示する -->
</li>
<li class="hidden only:flex">
<p class="text-base font-normal leading-tight text-center text-gray-400">
メッセージはありません
</p>
</li>
</ul>
ここで、周りを囲んでいるli要素はデフォルトで非表示になり、そのli要素が「唯一」の要素の場合に限って表示されるようになります(例: display: flex)。
素のCSSで書けば以下のような感じになります。
.li {
display: none;
}
.li:only-child {
display: flex;
}
このソリューションの大きなメリットのひとつは、メッセージが(Turbo Streamsで)削除されれば、リスト全体(ul要素)を更新しなくてもこのCSSによる「ロジック」が適用されることです。
とてもクールだと思いませんか?
(本記事は、カスタムロジックを置き換えるCSS機能を紹介する最初の記事です)

概要
元サイトの許諾を得て翻訳・公開いたします。
日本語タイトルは内容に即したものにしました。
参考:
:only-child- CSS | MDN