HTMLとCSSだけで『開く・閉じる』の切り替えボタンをかんたんに作る方法をご紹介します。
画面を遷移しないでコンテンツを開閉します。JavaScriptは使いません。
これは、コンテンツをコントロールするときWebサーバーにリクエストを送信しないので、Webページのパフォーマンスを上げることができます。
まずは完成したサンプルから。
See the Pen sample switching button - open/close by tadtadya (@tadtadya) on CodePen.
これをHTMLとCSSだけでつくります。少しづつ実装するので、とてもかんたんで分かりやすいと思います。
JavaScriptを使わずにコンテンツを『開く・閉じる』
サンプルをつくっていく前に、JavaScriptを使わないメリットから。
HTMLとCSSだけでボタンをつくるとWebサーバにリクエストする回数を最小限にできます。そのしくみは、
- ブラウザからhttpリクエストを送信。
- Webサーバーから、コンテンツが開いた状態のHTMLを返す。
- CSSでコンテンツの初期表示を設定(初期状態は『開く』『閉じる』のどちらでもよい)
- コンテンツを開いたり閉じたりする切り替えをCSSで行う。
これはコンテンツの表示・非表示の切り替えでページ遷移をしません。
また、コンテンツをリクエストで再取得しないとしても、JavaScriptのDOM操作がいらないので、その分だけブラウザの負荷を軽くできます。
あらかじめ、CSSですべての操作のスタイルが定義されているので、CSSOMの再展開がない。
(CSSOMはCSSのDOMみたいなもの。)
(JavaScriptのDOM, CSSOM操作の分がいらない。)
また、HTML, CSSに任せることでJavaScriptのコードを少なくできる。
切り替えボタンの動作をCSSのみで行なうかんたんな作り方
少しだけHTMLも関係していますが、コンテンツの『開く・閉じる』の動作はほぼすべてCSSだけで行ないます。
CSSの記述はかんたんです。ソースコードのサンプルを少しづつ実装しながら見ていきましょう。
ソースコードサンプルのボックスにタップやマウスを合わせると、右上にコピーボタンが出ます。
慣れないうちは、とりあえずコピー&ペーストで、自分で動かすところから始めると良いです。
開く・閉じるボタン切り替えのソースコードサンプル
まずは次のHTML&CSSを見てください。
<input type="radio" class="radio" id="open" name="btn" /><label class="btn btn-open" for="open">開く</label>
<input type="radio" class="radio" id="close" name="btn" checked="checked" /><label class="btn btn-close" for="close">閉じる</label>
<div class="box">制御されるコンテンツ</div>
.btn {
color: #fff;
background: rgba(127, 194, 239, .5);
padding: .3em .5em;
margin-bottom: .3em;
border-radius: .3em;
text-align: center;
display: table;
}
.btn:hover {
cursor: pointer;
}
.btn:active {
background: rgb(127, 194, 239);
}
.box {
border: 2px solid #d685b0;
border-radius: .3em;
height: 200px;
}
HTMLはラジオボタンとそのラベルの2つずつでボタンを作って、コントロールされるエリアを用意しただけです。
ボタンには、まだボタンとしての機能はありません。
CSSは、ボタンっぽい見た目と押したときのスタイルを入れました。そしてコンテンツが見えやすいように枠をつけました。
まずはこの状態で動かしてみましょう。
ボタンを切り替えるはずが、2つとも表示されています。そして見えてほしくないラジオボタンが見えてしまっています。
また、ボタンを押してもラジオボタンが切り替わるだけで、エリアには何も起きません。
このままでは何の意味もありません。ここでCSSに、ボタンをコントロールする処理を追加します。
まずはHTMLを変更します。
<div class="add-control">
<!-- さっきのHTML -->
</div>
<div class="add-control">
<input type="radio" class="radio" id="open" name="btn" /><label class="btn btn-open" for="open">開く</label>
<input type="radio" class="radio" id="close" name="btn" checked="checked" />
<label class="btn btn-close" for="close">閉じる</label>
<div class="box">制御されるコンテンツ</div>
</div>
ボタンのコントロール用クラスを親要素のdivに追加しただけです。
次に、CSSにadd-controlクラスについてコードを追加します。
/* radio non-display */
.add-control .radio{
display: none;
}
/* button control */
.add-control #close:checked ~ .btn-close {
display: none;
}
.add-control #close:checked ~ .btn-open {
display: table;
}
.add-control #open:checked ~ .btn-close {
display: table;
}
.add-control #open:checked ~ .btn-open {
display: none;
}
/* content control */
.add-control #close:checked ~ .box {
display: none;
}
.add-control #open:checked ~ .box {
display: block;
}
CSSセレクタ(~): 同じ階層を見る
要素と同じ階層にある要素に対してスタイルを適用させるためのセレクタ。
間接セレクタ。兄弟(姉妹)セレクタとも言う。
<div class="parent">親
<div class="child-1">子</div>
<div class="child-2">子</div>
<div class="child-3">子
<div class="child-child">孫</div>
</div>
</div>
CSSサンプル
// child-1, child-2, child-3が対象
.child-1 ~ div {
color: red;
}
処理の内容
- ラジオボタンはいらないのでかくす。
- 閉じるボタンが押された → 閉じるボタンかくす・開くボタン表示。エリアかくす。
- 開くボタンが押された → 開くボタンかくす・閉じるボタン表示。エリア表示。
くわしい説明はあとのほうでします。
まずは動かしてみましょう。
HTMLとCSSだけで開く・閉じるボタンができました。
これまで順を追ってサンプルコードを作りましたが、整理すると最初にみたCodePenのHTML&CSSになります。
初期状態を『閉じるボタン+コンテンツ表示』に変えるのはかんたんです。htmlのラジオボタンで、閉じるボタンのchecked属性をはずして開くボタンにつけるだけ。
HTMLの結果だけを表示します。
【解説】CSSのボタン切り替えのポイント(:checked 疑似クラス)
『開く・閉じる』ボタンの切り替え、コンテンツの表示・非表示には、CSSの:checked疑似クラスを使う
:checked疑似クラスは、HTMLのinput要素のchecked属性と連動しています。
input要素の チェックボタン ラジオボタン など | checked属性 |
---|---|
チェックあり | HTMLに追加 |
チェックなし | 属性なし |
サンプルでは、閉じるボタンのinput要素に初期値としてchecked属性がついてるので、閉じるボタンはかくれ開くボタンを表示します。
<input type="radio" class="radio" id="close" name="btn" checked="checked" />
【解説】HTML文のボタン切り替えのポイント(radioボタンを使用)
HTMLは、radioボタンをカスタマイズして開く・閉じるボタンに使う
ラジオボタンは、複数のボタンのなかで選べるのがひとつだけで、『開く』『閉じる』の一方を選択するのと動きが同じです。
これがラジオボタンを使う理由。
ラジオボタンをクリックすると、input要素のchecked属性が自動的に切り替わるので、開く・閉じるボタンの切り替え、エリアの表示・非表示に流用しました。
ラジオボタンは内部の切り替え機能だけが必要なので、CSSのdisplay:noneでかくし、ボタンの表示はラジオボタンのとなりにあるテキスト部分(label)で表現します。
【解説】CSSのボタン切り替え
ボタンの切り替えはCSSで行う
ラジオボタンのchecked属性(HTML)だけでボタンを切り替えるので、JavaScriptはいりません。
HTML&CSSだけでボタンが切り替えられるのは、HTMLにある機能だけでコントロールするからです。
CSSは見た目をカバーしているだけ。
CSSでのボタンの切り替えの記述は、さっき見たように20行もありません。(checked疑似クラスがついたところ)
- checked属性がついたボタンはかくして、もう一方のボタンを表示。
- 閉じるボタンにchecked属性がついて、連動してコンテンツをかくす。(display: noneを使う)
- 開くボタンにchecked属性がついて、連動してコンテンツを表示。(display:tableで表示)(tableを使うと文字列の長さにボタン幅が自動調整される。inline-blockと同じ。)
ボタンの処理でやっていることはこれだけです。
もうひとつの方法
これまで見てきたサンプルよりも、もっと短いコードでかんたんな方法があります。
ラジオボタンをチェックボックスにするとボタンの数がひとつなので、その分だけCSSのボタンのコントロールが少なくなります。
(20行が10行くらいまで少なくできる。)
こっちを先にいってくれよ!
と思うでしょうが、チェックボックスは機能の拡張がむずかしいです。
(例えば『ボタンを3個以上に増やす』とか。)
(ラジオボタンではボタンを増やすだけ済む。)
チェックボックスは、ボタンがふたつに限定されるオン/オフ機能に向いています。サンプルの『閉じる・開く』もそのひとつ。
処理の内容はほとんど一緒。HTMLとCSSの完成したサンプルコードからHTML結果まで一気に見ていきましょう。
<div class="add-control">
<input type="checkbox" class="chk" id="open-close" name="btn" /><label class="btn btn-open-close" for="open-close"></label>
<div class="box">制御されるコンテンツ</div>
</div>
.btn {
color: #fff;
background: rgba(127, 194, 239, .5);
padding: .3em .5em;
margin-bottom: .3em;
border-radius: .3em;
text-align: center;
display: table;
}
.btn:hover {
cursor: pointer;
}
.btn:active {
background: rgb(127, 194, 239);
}
.box {
border: 2px solid #d685b0;
border-radius: .3em;
height: 200px;
}
/* checkbox non-display */
.add-control .chk{
display: none;
}
/* button control */
.add-control #open-close ~ .btn-open-close::before {
content: "開く" ;
}
.add-control #open-close ~ .box {
display: none ;
}
.add-control #open-close:checked ~ .btn-open-close::before {
content: "閉じる" ;
}
.add-control #open-close:checked ~ .box {
display: block ;
}
.btn {
color: #fff;
background: rgba(127, 194, 239, .5);
padding: .3em .5em;
margin-bottom: .3em;
border-radius: .3em;
text-align: center;
display: table;
}
.btn:hover {
cursor: pointer;
}
.btn:active {
background: rgb(127, 194, 239);
}
.box {
border: 2px solid #d685b0;
border-radius: .3em;
height: 200px;
}
/* checkbox non-display */
.add-control .chk{
display: none;
}
/* button control */
.add-control #open-close ~ .btn-open-close::before {
content: "開く" ;
}
.add-control #open-close ~ .box {
display: none ;
}
.add-control #open-close:checked ~ .btn-open-close::before {
content: "閉じる" ;
}
.add-control #open-close:checked ~ .box {
display: block ;
}
さらにかんたんにできましたね?
チェックボックス版のポイントは、ラベルをHTMLに書かずに、CSSの::before疑似クラスで書いているところ。
あとは、CSSでエリアを切り替えるとき一緒にボタン名を切り替えるだけ。
- HTMLのラベルは空で作る。
- ボタン名はCSSの::before疑似クラス+contentプロパティで作る。
- CSSのボタン切り替えで、エリアのON/OFF, ボタン名を切り替える。
ちなみに、::before疑似クラスではなく、HTMLにボタンをふたつ用意して"display:none"で制御することもできます。
<div class="add-control">
<input type="checkbox" class="chk" id="open-close" name="btn"><label class="btn btn-open-close" for="open-close"><span class="open">開く</span><span class="close">閉じる</span></label>
<div class="box">制御されるコンテンツ</div>
</div>
.btn {
color: #fff;
background: rgba(127, 194, 239, .5);
padding: .3em .5em;
margin-bottom: .3em;
border-radius: .3em;
text-align: center;
display: table;
}
.btn:hover {
cursor: pointer;
}
.btn:active {
background: rgb(127, 194, 239);
}
.box {
border: 2px solid #d685b0;
border-radius: .3em;
height: 200px;
}
/* checkbox non-display */
.add-control .chk{
display: none;
}
/* button control */
.add-control #open-close ~ .box {
display: none ;
}
.add-control #open-close ~ .btn-open-close .open {
display: inline;
}
.add-control #open-close ~ .btn-open-close .close {
display: none;
}
.add-control #open-close:checked ~ .btn-open-close .open {
display: none;
}
.add-control #open-close:checked ~ .btn-open-close .close {
display: inline;
}
.add-control #open-close:checked ~ .box {
display: block ;
}
まとめ
- HTMLはradioボタンのchecked属性を使う
- CSSは:checked疑似クラスを使う
HTMLとCSSだけでコントロールする開く・閉じるボタンは、見た目と動きでむずかしく感じますが、じっさいはかんたんですね?
サンプルコードではデザインをシンプルにしています。もっとオシャレにしたいときは、ラベルとコンテンツエリアのborder, color, backgroundあたりを変えれば劇的に変わります。
:checked疑似クラスはCSS3から実装された機能です。現在のブラウザは対応しているので気にすることはないですが、どうしても動かない場合の知識として押さえておきましょう。
今回ご紹介した開く・閉じるボタンとまったく同じ作り方で、JavaScriptを使わないその他の機能も実装できます。