チェックボックスを利用した、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>
ポイントは以下のとおり。
div.wrapper
は必須ではない。body
直下にチェックボックスを置くのが嫌だったので書いたまで。input[type="checkbox"]
に::before
や::after
擬似要素で文字列を追加できない。どうやら「テキストコンテンツを持つ要素じゃないよね」という判断みたい。- チェックボックスは非表示にするので、代わりに
label
要素を置いた。文言をチェック状態に応じて変えるので、中身は空にし、後で::after
擬似要素に文言を入れる。 - 一番大事なのは、隣接セレクタ (
+
) が使えるように、チェックボックスとdiv.contents
を同じ階層に置いておかないといけない、ということ。ついついチェックボックスだけp
要素とかで囲みたくなるけど、そうすると親要素に遡って隣接セレクタを指定しないといけなる。まだ:has()
セレクタは各ブラウザに実装されていないため、それだと実装しきれないのだ。というワケで、input[type="checkbox"]
と、影響を与えたいdiv.contents
は同じ階層に配置する。 - 英語と日本語のコンテンツは、
div.contents
要素内に、それぞれlang
属性を付与して書いておく。ココは自力で両言語のテキストを用意しておくこと。w
チェックボックスとラベルの実装
まずはチェックボックスを非表示にし、ラベルをボタン風に実装する。
今回のサンプルは「チェックされていない初期状態が日本語表示」「チェックされた状態が英語表示」になるようにするので、それを考慮した文言にする。
/* コレがチェックボックス。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 だけでできる幅が広がるんだけどなぁ〜。