チェックボックスを利用した、CSS だけでできる言語切替ページの作り方

チェックボックスのチェック状態に応じて、ページの言語切替を CSS だけで行ってみた。

拙作のライブラリ in-browser-sass のデモページで実際に組み込んでいる。

目次

HTML 構造

今回は JavaScript を使わず CSS だけで別要素に影響を与えたいので、HTML 構造が若干制限される。今回のデモでは以下のような HTML にした。

<div class="wrapper">
  <input type="checkbox" id="language">
  <label for="language"></label>
  <div class="contents">
    <p lang="en">English contents.</p>
    <p lang="ja">日本語のコンテンツ。</p>
  </div>
</div>

ポイントは以下のとおり。

チェックボックスとラベルの実装

まずはチェックボックスを非表示にし、ラベルをボタン風に実装する。

今回のサンプルは「チェックされていない初期状態が日本語表示」「チェックされた状態が英語表示」になるようにするので、それを考慮した文言にする。

/* コレがチェックボックス。label 要素の for 属性で操作できるので、チェックボックス自体は非表示にする */
#language {
  display: none;
}

/* チェックボックスに隣接するラベルの ::after 疑似要素でスタイリング */
#language + label::after {
  display: inline-block;
  content: "English Version";  /* 未チェック時に表示するテキスト */
  border: 1px solid #ccc;      /* あとはボタン風にスタイリングするだけ */
  border-radius: 4px;
  padding: 2px 4px;
  background: #eee;
  cursor: pointer;
}

/* ホバー時の見た目変更 */
#language + label:hover::after {
  border-color: #999;
  background: #ccc;
}

/* チェック時のラベルを変更 */
#language:checked + label::after {
  content: "日本語版にする";
}

コレで、チェックボックスを見せずにボタン風な要素が配置できた。

表示コンテンツの切替

あとは隣接セレクタ (+) と :checked 疑似クラスで、隣接する div.contents 配下の要素を表示切替すれば良い。

/* チェックボックスの直後のラベル要素、の直後にラッパー要素があるので以下のようになる */
#language:not(:checked) + label + .contents *[lang="en"],   /* 未チェック時は英語コンテンツを非表示 */
#language:checked       + label + .contents *[lang="ja"] {  /* チェック時は日本語コンテンツを非表示 */
  display: none;
}

詳細度を同レベルにするため、#language:not(:checked) と書く必要がある。


コレでできあがり。

あとは :has() セレクタが使えるようになればもう少し CSS だけでできる幅が広がるんだけどなぁ〜。