今回のお題は、ハンバーガーメニューのアニメーションだ。ハンバーガーアイコンをクリックすると、メニューが右に向けて広がる(サンプル1 ) 。「 CSS Gooey Menu 」のデザインとアニメーションをもとに、コードは絞り込んでわかりやすく組み立て直した。技術的にむずかしいところは少なく、ただメニューの数だけ細かい設定が増える。なお、SVGを用いたフィルタ は、今回のお題からは外した。
サンプル1 CSS3:Hamburger menu
アイコンWebフォントを使う
サンプル1 のハンバーガーメニューには、文字は使われていない。替わりにアイコンがある。これらのアイコンにはWebフォントのFont Awesome を用いた。たとえば、つぎのようなアイコンがWebフォントとして読み込んで表示できる。
bar-chart
plus
heart
envelope
Font Awesomeは、つぎのコードのとおりBootstrapCDNから読み込んだ。Font Awesomeのページ で、「 Font Awesome CSS」のフィールドの右ボタンを展開すると、「 HTML」のコードが示されるので、それをコピー&ペーストすればよい(図1 ) 。integrity
も含んだ<link>
要素が加えられる。なお、いつものように<script>
要素に-prefix-free を読み込んで、ベンダープレフィックスは省いた(第1回の「ベンダープレフィックスと-prefix-free 」の項参照) 。
<head>要素
<script src="lib/prefixfree.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
図1 BootstrapCDNのFont Awesomeのページ
Font Awesomeのアイコンは、つぎのように<i>
要素にclass
属性で定める(「 Examples」の「Basic Icons 」参照) 。HTMLドキュメントにおけるハンバーガーメニューをつくるための<body>
要素の記述は以下のコード1 のとおりだ。メニューの開け閉じは<input>
要素のチェックボックス(type
属性"checkbox")で行う。もっとも、要素そのものはCSSで隠す。そのため、ハンバーガーボタンの<label>要素にfor
属性 で、チェックボックスのid
属性("menu-open")を指定した。したがって、<label>
属性のクリックでチェックボックスは切り替えられる。
<i class="fa fa-アイコン名"></i>
コード1 ハンバーガーメニューをつくる<body>要素の定め
<body>要素
<nav class="menu">
<input type="checkbox" class="menu-open" name="menu-open" id="menu-open"/>
<label class="menu-open-button" for="menu-open">
<span class="hamburger hamburger-1"></span>
<span class="hamburger hamburger-2"></span>
<span class="hamburger hamburger-3"></span>
</label>
<a href="#" class="menu-item menu-item-1">
<i class="fa fa-bar-chart"></i>
</a>
<a href="#" class="menu-item menu-item-2">
<i class="fa fa-plus"></i>
</a>
<a href="#" class="menu-item menu-item-3">
<i class="fa fa-heart"></i>
</a>
<a href="#" class="menu-item menu-item-4">
<i class="fa fa-envelope"></i>
</a>
</nav>
ハンバーガーメニューを開いたときの静的スタイル
ハンバーガーメニューを開いたときの静的なスタイルは、以下のコード2 のCSSで定めた(図2 ) 。メニュー(class
属性"menu-item")とハンバーガー(class
属性"menu-open-button")のボタンは、border-radius
プロパティで円形にして、それぞれ前掲コード1 のとおりアイコンと3本線(<span>
要素)を加えている。開いたメニューの水平位置は、transform
プロパティにtranslateX()
関数で決めた。なお、メニューを閉じたとき各項目が後ろに隠れるよう、ハンバーガーボタンのz-index
プロパティを高めてある。
図2 ハンバーガーメニューが開いたときのスタイル
コード2 ハンバーガーメニューを開いたときの静的なスタイル
.menu-item, .menu-open-button {
background: darkcyan;
border-radius : 100%;
width: 60px;
height: 60px;
position: absolute;
color: white;
text-align: center;
line-height: 60px;
}
.menu-open {
display: none;
}
.hamburger {
width: 25px;
height: 3px;
background: white;
display: block;
position: absolute;
top: 50%;
left: 50%;
margin-left: -12.5px;
margin-top: -1.5px;
}
.hamburger-1 {
transform : translateY (-8px);
}
.hamburger-3 {
transform : translateY (8px);
}
.menu {
position: absolute;
margin: 10px;
box-sizing: border-box;
font-size: 20px;
text-align: left;
}
.menu-item-1 {
transform : translateX (80px);
}
.menu-item-2 {
transform : translateX (160px);
}
.menu-item-3 {
transform : translateX (240px);
}
.menu-item-4 {
transform : translateX (320px);
}
.menu-open-button {
z-index: 2;
cursor: pointer;
}
ハンバーガーボタンのアニメーション
ハンバーガーボタン(class
属性"menu-open-button")のアニメーションからつくろう。チェックボックス(class
属性"menu-open")がチェックされたら(:checked
擬似クラス ) 、3本線の上下はtransform
プロパティにrotate()
関数で±45度回し、真ん中はscaleX()
関数でつぶした。これで、閉じるボタンの×のかたちができあがる(図3 ) 。
.menu-open:checked + .menu-open-button .hamburger-1 {
transform : rotate (45deg);
}
.menu-open:checked + .menu-open-button .hamburger-2 {
transform : scaleX (0);
}
.menu-open:checked + .menu-open-button .hamburger-3 {
transform : rotate (-45deg);
}
図3 閉じるボタン
それでは、transition
プロパティで滑らかなアニメーションにしよう。つぎのように、アニメーションの時間(transition-duration
プロパティ)やタイミング関数(transition-timing-function
プロパティ)の値の変え方を、細かく調整した。ハンバーガーボタンの大きさもtransform
プロパティで、マウスポインタを重ねたときや、クリックしたときとでscale()
関数により変えている。
.menu-item, .menu-open-button {
transition : ease-out 200ms;
}
.hamburger {
transition : 200ms;
}
.menu-open-button {
transform : scale (1.1, 1.1);
transition-timing-function : cubic-bezier (0.175, 0.885, 0.32, 1.275);
transition-duration : 400ms;
}
.menu-open-button:hover {
transform : scale (1.2, 1.2);
}
.menu-open:checked + .menu-open-button {
transform : scale (0.8, 0.8);
transition-timing-function : linear;
transition-duration : 200ms;
}
cubic-bezier()
関数で定めるタイミング関数の値の変わり方は、「 Cubic Bezier Generator 」で確かめられる(図4 ) 。ここまで書いたCSSを、以下のコード3 にまとめた。
図4 cubic-bezier()関数が定める値の変わり方
コード3 ハンバーガーボタンのアニメーションを加えたメニュー
.menu-item, .menu-open-button {
background: darkcyan;
border-radius : 100%;
width: 60px;
height: 60px;
position: absolute;
color: white;
text-align: center;
line-height: 60px;
transition : ease-out 200ms;
}
.menu-open {
display: none;
}
.hamburger {
width: 25px;
height: 3px;
background: white;
display: block;
position: absolute;
top: 50%;
left: 50%;
margin-left: -12.5px;
margin-top: -1.5px;
transition : 200ms;
}
.hamburger-1 {
transform : translateY (-8px);
}
.hamburger-3 {
transform : translateY (8px);
}
.menu-open:checked + .menu-open-button .hamburger-1 {
transform : rotate (45deg);
}
.menu-open:checked + .menu-open-button .hamburger-2 {
transform : scaleX (0);
}
.menu-open:checked + .menu-open-button .hamburger-3 {
transform : rotate (-45deg);
}
.menu {
position: absolute;
margin: 10px;
box-sizing: border-box;
font-size: 20px;
text-align: left;
}
.menu-item-1 {
transform : translateX (80px);
}
.menu-item-2 {
transform : translateX (160px);
}
.menu-item-3 {
transform : translateX (240px);
}
.menu-item-4 {
transform : translateX (320px);
}
.menu-open-button {
z-index: 2;
transform : scale (1.1, 1.1);
cursor: pointer;
transition-timing-function : cubic-bezier (0.175, 0.885, 0.32, 1.275);
transition-duration : 400ms;
}
.menu-open-button:hover {
transform : scale (1.2, 1.2);
}
.menu-open:checked + .menu-open-button {
transform : scale (0.8, 0.8);
transition-timing-function : linear;
transition-duration : 200ms;
}
メニューの開け閉じのアニメーション
仕上げはメニューを開け閉じするアニメーションだ。はじめはすべての項目を、ハンバーガーボタンの後ろに隠しておく。そして、ボタンがクリックされたら(:checked
擬似クラス) 、つぎのようにそれぞれの定位置に動かせばよい。メニューが開くときのアニメーションの時間(transition-duration
プロパティ)は、動く距離に応じて変えた。また、メニュー項目にマウスポインタを重ねたとき(:hover
擬似クラス)の色も変えている(図5 ) 。これでできあがったので、以下のコード3 にまとめた。
.menu-item:hover {
background: turquoise;
color: darkcyan;
}
.menu-item-1 {
/* transform: translateX(80px); */
transition-duration : 180ms;
}
.menu-item-2 {
/* transform: translateX(160px); */
transition-duration : 180ms;
}
.menu-item-3 {
/* transform: translateX(240px); */
transition-duration : 180ms;
}
.menu-item-4 {
/* transform: translateX(320px); */
transition-duration : 180ms;
}
.menu-open:checked ~ .menu-item {
transition-timing-function : cubic-bezier (0.165, 0.84, 0.44, 1);
}
.menu-open:checked ~ .menu-item-1 {
transform : translateX (80px);
transition-duration : 190ms;
}
.menu-open:checked ~ .menu-item-2 {
transform : translateX (160px);
transition-duration : 290ms;
}
.menu-open:checked ~ .menu-item-3 {
transform : translateX (240px);
transition-duration : 390ms;
}
.menu-open:checked ~ .menu-item-4 {
transform : translateX (320px);
transition-duration : 490ms;
}
図5 メニューにマウスポインタを重ねると色が変わる
コード4 ハンバーガーメニューのアニメーション
.menu-item, .menu-open-button {
background: darkcyan;
border-radius : 100%;
width: 60px;
height: 60px;
position: absolute;
color: white;
text-align: center;
line-height: 60px;
transition : ease-out 200ms;
}
.menu-open {
display: none;
}
.hamburger {
width: 25px;
height: 3px;
background: white;
display: block;
position: absolute;
top: 50%;
left: 50%;
margin-left: -12.5px;
margin-top: -1.5px;
transition : 200ms;
}
.hamburger-1 {
transform : translateY (-8px);
}
.hamburger-3 {
transform : translateY (8px);
}
.menu-open:checked + .menu-open-button .hamburger-1 {
transform : rotate (45deg);
}
.menu-open:checked + .menu-open-button .hamburger-2 {
transform : scaleX (0);
}
.menu-open:checked + .menu-open-button .hamburger-3 {
transform : rotate (-45deg);
}
.menu {
position: absolute;
margin: 10px;
box-sizing: border-box;
font-size: 20px;
text-align: left;
}
.menu-item-1 {
transform : translateX (80px);
}
.menu-item-2 {
transform : translateX (160px);
}
.menu-item-3 {
transform : translateX (240px);
}
.menu-item-4 {
transform : translateX (320px);
}
.menu-open-button {
z-index: 2;
transform : scale (1.1, 1.1);
cursor: pointer;
transition-timing-function : cubic-bezier (0.175, 0.885, 0.32, 1.275);
transition-duration : 400ms;
}
.menu-open-button:hover {
transform : scale (1.2, 1.2);
}
.menu-open:checked + .menu-open-button {
transform : scale (0.8, 0.8);
transition-timing-function : linear;
transition-duration : 200ms;
}