CSSだけでスマホでも使えそうなスライドインするメニューを考えてみた

HTML/CSSコーディング

一週間ほど鼻水が止まらず、咳までで出したごろどくです、どうも。北海道ではまだ花粉の時期ではないので花粉症ではないのですが、ここ数年毎年この時期には同じような症状で体調崩してる気がします。年度末の気の緩みでしょうか。

さて今回はコチラのページを制作するときに色々覚えたCSS小ネタの備忘録です。新しいことを覚えるのはやっぱり楽しいですね。

作りたいもの

スライドインメニューサンプルその3

いきなり「その3」ですみません。別に順番間違えてるわけではないです。

スマホアプリなどで採用されているのでWebでも良く見かけるようになった「横からにゅるっと出てくるメニュー」です。ハンバーガーメニューとかドロワーメニューとかスライドインメニューとかいろいろ呼称があるようです。どれが正しいのかはよくわかりません。

こういうのをjqueryのみならずjavascriptなしで実装してみたいと思います。

ちなみに実際にはこういうものはjqueryで実装する方が多いでしょうから「へーこういうやり方もあるんだね」くらいに考えていただければ良いかと思います。

動作の構想など

まったくどうしていいのかわからないので、いろいろググって参考になりそうなものを探します。例えば出てきたのがコチラ。

CSSのみでハンバーガーメニューを作る – Qiita

サンプルがSCSSで書いてあったのでなんじゃこりゃと言う感じだったんですがコンパイル表示して何とか読み解きます。「ボタンのクリックを検出して画面外に配置してあったメニューを」表示範囲に移動させる」と言う感じです。コードはそっくりそのまま使えるわけではないのですが基本方針は倣って

通常はメニュー部分をデバイスの表示領域の外に配置しておいて、メニューボタンを押すとメニューもコンテンツも全体が右にスライドして、左側からメニューが出てきたように見える、こういうものを作ろうと思います。

メニューボタン、クリックをどう検出するか

CSSだけだと通常の要素はクリック(またはタップ)検出できないのでチェックボックスのオンオフでクリックを検出します。CSS3には「:checked」という擬似要素があります。ここにプロパティと値を用意しておくとその要素がチェックされた時のみそのスタイルが適用されます。チェックが解除されると当然そのスタイルの適用も解除されます。

なのでinput要素でチェックボックスを配置しこれでクリックの検出を行うことにします。ただチェックボックスまんまの見た目だと普通はメニューボタンだと認識できないでしょうから、このチェックボックスに関連付けたラベルを用意し、これをボタンとして使用したいともいます。以下ボタン部分だけのサンプルです。

スライドインメニューサンプルその1

HTML


<input type="checkbox" id="trigger">
<label for="trigger" id="trigger-label"></label>

CSS


#trigger{
display:none;
}
#trigger-label{
position:fixed;
top:12px;
left:12px;
display:block;
width:15px;
height:15px;
background-color:#000;
}
#trigger-label::before,#trigger-label::after{
position:absolute;
content:"";
display:block;
width:15px;
height:3px;
}
#trigger-label::before{
margin-top:3px;
background-color:#f88;
}
#trigger-label::after{
margin-top:9px;
background-color:#8f8;
}
#trigger:checked~#trigger-label{
margin-left:150px;
}
#trigger:checked~#trigger-label:before,#trigger:checked~#trigger-label:after{
margin-top:6px;
border-radius:1px;
transition:transform 1.5s;
}
#trigger:checked~#trigger-label:before{
transform:rotate(45deg);
}
#trigger:checked~#trigger-label:after{
transform:rotate(-45deg);
}

解説

HTMLは必要なとこだけ抜き出してチェックボックスとラベルだけにしてます。CSSの最初の方で書いてますがチェックボックス自身はdisplay:noneで非表示にしています。

clipプロパティでサイズを0に指定してもそれ自身表示しないようにはできる(Qiitaのサンプルではそうしている)のですが、これだとチェックボックスをオンオフするごとにコンテンツ部分がページ先頭に戻される(おそらくサイズ0だけど要素自体は非表示ではないため再描画しようとしている)という不具合があり、例えばページ内リンクに使用するには問題があります。

またQiitaのサンプルはボタンの見栄えをWebフォントを使用して表現していますがこれではちょっとつまらないので多少捻ってみます。

実際にボタンとして表示させるラベルは15pxの正方形ボックスとし、:before/:after擬似要素で「ハンバーガーの隙間」の部分を表現しています。このサンプルでは分かりやすくbeforeを赤、afterを緑に着色してます。

またメニューを開いたときにはtransformプロパティでこの:before/:after擬似要素を45度回転かつtransitionプロパティで時間的変化の効果も与え「ハンバーガーメニューボタンが閉じるボタンに変化するアニメーション」になるようにしてみました。

:before/:after擬似要素とCSSアニメーションについては

劇的!(でもない)before after 擬似要素の使い方まとめ | 56docブログ

CSSのtransformでクルクル回転するパネルのサンプル | 56docブログ

こんな記事も書いてるので良ければ参考にしてください。

で、メニューの開閉の前振りとしてオンオフ時の位置の制御も入れてます。制御と言っても単純にmargin-leftの値を変えてるだけですけどね。チルダ「~」で「チェックされたinput要素(ここではid#triggerで指定)の兄弟要素の」を指定することによってクリック(タップ)で位置を変化する要素を指定しています。

メニューの表示・非表示

だいたい上のサンプルでほぼ動きは理解できたと思います。あとはメニューとコンテンツ全体に同じように移動の制御をかければよいわけです。

スライドインメニューサンプルその2

なおここでは先に解説したボタン表示上の演出は省略してます。

HTML


<input type="checkbox" id="trigger">
<label for="trigger" id="trigger-label"></label>
<header><h1>Slide in menu sample page</h1></header>
<nav>
<ul>
<li>menu list item 1</li>
<li>menu list item 2</li>
<li>menu list item 3</li>
</ul>
</nav>
<section>
<article>
<p> Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo.</p>
</article>
</section>
<footer><p>Thank you for reading !!</p></footer>

CSS


/*----- 簡易なリセット -----*/
*{
margin:0px;
padding:0px;
}
/*----- チェックボックスとラベル -----*/
#trigger{
display:none;
}
#trigger-label{
position:fixed;
z-index:3;
top:12px;
left:12px;
display:block;
width:15px;
height:15px;
background-color:#fff;
}
/*----- ヘッダー -----*/
header{
position:fixed;
z-index:2;
top:0px;
width:100%;
height:40px;
background-color:#222;
}
header h1{
display:block;
padding:12px 0px 12px 40px;
font-size:16px;
color:#fff;
}
/*----- メニュー -----*/
nav{
position:fixed;
top:0px;
z-index:1;
margin-left:-150px;
width:150px;
height:100%;
background-color:#444;
}
nav ul{
display:flex;
display:-webkit-flex;
flex-flow:column;
-webkit-flex-flow:column;
}
nav ul li{
padding:5px;
font-size:12px;
color:#fff;
}
/*----- メインコンテンツ -----*/
section{
position:relative;
z-index:1;
margin-top:40px;
width:100%;
min-height:100%;
background-color:#fff;
}
section article{
box-sizing:border-box;
padding:10px;
max-width:780px;
margin-left:auto;
margin-right:auto;
}
section article p{
letter-spacing:0.05em;
line-height:1.5em;
}
/*----- フッター -----*/
footer{
position:relative;
z-index:1;
width:100%;
height:20px;
background-color:#222;
text-align:center;
}
footer p{
padding:4px 0px 4px 0px;
font-size:12px;
color:#fff;
}
/*----- チェックボックスON時の挙動 -----*/
#trigger:checked~#trigger-label,#trigger:checked~header,#trigger:checked~section,#trigger:checked~footer{
margin-left:150px;
}
#trigger:checked~nav{
margin-left:0px;
}

解説

通常の装飾のためのスタイルも少なからず含んでいますがボタンだけのサンプルと見比べていただければどこが動作に必要なところかはおおよそ想像がつくと思います。

HTMLは書いてある通り(非表示にする)チェックボックスの共通の親要素を持つラベル、メニュー、ヘッダー、セクション、フッターが並列に並んでます。なので:cheched擬似要素にチルダでこれらをつないでボタンを押した時の位置制御≒メニュー開閉(に見えるもの)としています。メニューをネガティブマージンでメニュー幅と同じだけ外に出しておき、メニューボタンクリック時に全体をその幅だけ右になるようマージンを変化させています。

ヘッダーとメニュー、そしてボタンとして使用するラベルはfixedとして位置を固定します。またこれらの描画の上下関係を明示的に指定するために他の並列要素にもpositionプロパティを指定してz-indexで互いの関係を整理しています。

メニューの高さは表示領域全高にしておくといいと思います。またこの例ではメニューのリストをflex-boxで制御していますが

これからのCSSレイアウトはFlexboxで決まり! | Webクリエイターボックス

CSS3のFlexboxを基本から理解して、使い倒そう! | 株式会社LIG

この辺りの記事が大変わかりやすく解説していますので参考にしていただければと思います。

ちなみにメニュー以外のコンテンツボリュームが少ないと、サンプルページの通りメニューの高さが全高なのにフッターが上の方に表示されるというちょっと間の抜けた感じになります。これもflex-boxを使ってラップすると解決するのですが、そもそもコンテンツボリュームが一画面に満たないというのもレアケースでしょうから今回はサンプルとしての分かりやすさを優先させて作ってますので解説は割愛しますね。

まとめ

久々にCSSネタを書いてみました。そもそもWeb製作ネタを年単位で書いてないような気もします。需要があるのかないのか微妙な感じの内容ですみません。本業が忙しと言うのは有りがたいことではありますが(明日もご飯が食べられるという意味で)。

年度末の繁忙期を今年度も無事に乗り切れた様なので、本業での資料整理も兼ねて作ってみましたがいかがでしょうか。

これはいつも思うのですが、どうやってWebページなりサイトを作るか、というのはやっぱり具体的なテーマがないとなかなか身につかないので、特にそちらの界隈を学んでいこうという方は、本読みも大事ですが実際に手を動かして上手くいかないこと、あるいは「なんかこれじゃない」というのを体験してみるのが一番の勉強になると思います。

コメント

タイトルとURLをコピーしました