いずれも同じような動きだったり過去に紹介したものに少し動きを加えたレベルにはなりますが、ハンバーガーメニューをクリックしてクローズボタンへ変化する動きをCSSで実装したサンプル集です。
今回もメニュークリック時にJavaScriptを使って.active
というクラスが追加・削除する動きを実装想定になっています。
共通のHTML
紹介するサンプルはいずれも下記のようなHTMLを使用しており、クリック時にこのbutton
要素に対して.active
というclassが付与されるという想定でCSSの実装コードを紹介していきます。
<button class="menu-trigger">
<span></span>
<span></span>
<span></span>
</button>
ラインが縮小後、クローズボタンを表示
クリックで各ラインが中央に向かって縮小し、その後中央からクローズボタンが表示されます。
実装にはCSSで下記を記述します。
.menu-trigger,
.menu-trigger span {
display: inline-block;
box-sizing: border-box;
}
.menu-trigger {
position: relative;
width: 50px;
height: 44px;
background: none;
border: none;
appearance: none;
cursor: pointer;
}
.menu-trigger:focus:not(:focus-visible) {
outline: none;
}
.menu-trigger::before,
.menu-trigger::after {
content: '';
}
.menu-trigger::before,
.menu-trigger::after,
.menu-trigger span {
position: absolute;
width: 100%;
height: 4px;
background: #fff;
border-radius: 4px;
transform-origin: 50% 50%;
transition: .2s;
}
.menu-trigger::before {
top: 20px;
left: 0;
transform: rotate(45deg) scaleX(0);
}
.menu-trigger::after {
top: 20px;
right: 0;
transform: rotate(-45deg) scaleX(0);
}
.menu-trigger span:nth-of-type(1) {
top: 0;
left: 0;
transition-delay: .2s;
}
.menu-trigger span:nth-of-type(2) {
top: 20px;
left: 0;
transition-delay: .2s;
}
.menu-trigger span:nth-of-type(3) {
bottom: 0;
left: 0;
transition-delay: .2s;
}
.menu-trigger.active::before {
transform: rotate(45deg) scaleX(1);
transition-delay: .2s;
}
.menu-trigger.active::after {
transform: rotate(-45deg) scaleX(1);
transition-delay: .2s;
}
.menu-trigger.active span {
transform: scaleX(0);
transition-delay: 0s;
}
中央ラインが分裂後、上下のラインがクローズボタンに
クリックで中央のラインが分裂して左右に向かってフェードアウトし、その後上下のラインを使ってクローズボタンを表示します。
表示されているラインはパッと見でひとつの要素で表現しているように見えますが、実際には擬似要素を用いてふたつの要素を組み合わせてひとつのラインのように見せており、それをクリック時にそれぞれ動きをつけることでこのような動きを実装しています。
実装にはCSSで下記を記述します。
.menu-trigger,
.menu-trigger span {
display: inline-block;
box-sizing: border-box;
}
.menu-trigger {
position: relative;
width: 50px;
height: 44px;
background: none;
border: none;
appearance: none;
cursor: pointer;
}
.menu-trigger:focus:not(:focus-visible) {
outline: none;
}
.menu-trigger span {
position: absolute;
width: 100%;
height: 4px;
}
.menu-trigger span::before,
.menu-trigger span::after {
content: '';
position: absolute;
width: 51%;
height: 4px;
background: #fff;
transition: .2s;
}
.menu-trigger span::before {
left: 0;
border-radius: 4px 0 0 4px;
}
.menu-trigger span::after {
right: 0;
border-radius: 0 4px 4px 0;
}
.menu-trigger span:nth-of-type(1) {
top: 0;
left: 0;
}
.menu-trigger span:nth-of-type(2) {
top: 20px;
left: 0;
}
.menu-trigger span:nth-of-type(3) {
bottom: 0;
left: 0;
}
.menu-trigger.active span:nth-of-type(1)::before {
transform: translate(4px, 11px) rotate(45deg);
}
.menu-trigger.active span:nth-of-type(1)::after {
transform: translate(-3px, 11px) rotate(-45deg);
}
.menu-trigger.active span:nth-of-type(2)::before {
transform: translateX(-75%);
opacity: 0;
}
.menu-trigger.active span:nth-of-type(2)::after {
transform: translateX(75%);
opacity: 0;
}
.menu-trigger.active span:nth-of-type(3)::before {
transform: translate(4px, -11px) rotate(-45deg);
}
.menu-trigger.active span:nth-of-type(3)::after {
transform: translate(-3px, -11px) rotate(45deg);
}
上下のラインが縮小後、クローズボタンを表示
クリックで上下のラインが縮小し、その後中央のラインも含めてそれぞれを回転させることでクローズボタンとして表示させます。
実装にはCSSで下記を記述します。
.menu-trigger,
.menu-trigger span {
display: inline-block;
box-sizing: border-box;
}
.menu-trigger {
position: relative;
width: 50px;
height: 44px;
background: none;
border: none;
appearance: none;
cursor: pointer;
}
.menu-trigger:focus:not(:focus-visible) {
outline: none;
}
.menu-trigger span {
position: absolute;
width: 100%;
height: 4px;
background: #fff;
border-radius: 4px;
}
.menu-trigger span:nth-of-type(1) {
top: 0;
left: 0;
transform-origin: 0 0;
animation: menu-bar01-close .2s forwards;
}
.menu-trigger span:nth-of-type(2) {
top: 20px;
left: 0;
transition: .2s;
}
.menu-trigger span:nth-of-type(3) {
right: 0;
bottom: 0;
transform-origin: 100% 0;
animation: menu-bar03-close .2s forwards;
}
.menu-trigger.active span:nth-of-type(1) {
animation: menu-bar01-open .4s forwards;
}
.menu-trigger.active span:nth-of-type(2) {
transform: rotate(-45deg);
transition-delay: .2s;
}
.menu-trigger.active span:nth-of-type(3) {
animation: menu-bar03-open .4s forwards;
}
@keyframes menu-bar01-open {
0% {
width: 100%;
transform: rotate(0deg) translate(0);
}
50% {
width: 51%;
transform: rotate(0deg) translate(0);
}
100% {
width: 51%;
transform: rotate(45deg) translate(8px, -4px);
}
}
@keyframes menu-bar01-close {
0% {
width: 51%;
transform: rotate(45deg) translate(8px, -4px);
}
100% {
width: 100%;
transform: rotate(0deg) translate(0);
}
}
@keyframes menu-bar03-open {
0% {
width: 100%;
transform: rotate(0deg) translate(0);
}
50% {
width: 51%;
transform: rotate(0deg) translate(0);
}
100% {
width: 51%;
transform: rotate(45deg) translate(-6px, 3px);
}
}
@keyframes menu-bar03-close {
0% {
width: 51%;
transform: rotate(45deg) translate(-6px, 3px);
}
100% {
width: 100%;
transform: rotate(0deg) translate(0);
}
}
イージング適用 #1
以前全体的にポップな雰囲気のサイトを作成した際、そこまで主張しない程度でハンバーガーボタンにも動きを付けたいと要望があって作成してみたものです。
動き自体は中央のラインを非表示にしつつ上下のラインをクローズボタンとして表示させる単純なものですが、そこにcubic-bezier()
でイージングを適用することでちょっと違う印象を与えることができ、このサンプルの場合はクリック時に上下のラインがバウンドするような動きになっています。
実装にはCSSで下記を記述します。
.menu-trigger,
.menu-trigger span {
display: inline-block;
box-sizing: border-box;
}
.menu-trigger {
position: relative;
width: 50px;
height: 44px;
background: none;
border: none;
appearance: none;
cursor: pointer;
}
.menu-trigger:focus:not(:focus-visible) {
outline: none;
}
.menu-trigger span {
position: absolute;
width: 100%;
height: 4px;
background: #fff;
border-radius: 4px;
}
.menu-trigger span:nth-of-type(1) {
top: 0;
left: 0;
transition: top .3s;
}
.menu-trigger span:nth-of-type(2) {
top: 20px;
left: 0;
transition: opacity .3s;
}
.menu-trigger span:nth-of-type(3) {
bottom: 0;
left: 0;
transition: bottom .3s;
}
.menu-trigger.active span:nth-of-type(1) {
top: 20px;
transform: rotate(-45deg);
transition: top .3s cubic-bezier(.36, -.42, .68, -.56), transform .3s .3s;
}
.menu-trigger.active span:nth-of-type(2) {
opacity: 0;
transition: opacity .05s .3s;
}
.menu-trigger.active span:nth-of-type(3) {
bottom: 20px;
transform: rotate(45deg);
transition: bottom .3s cubic-bezier(.36, -.42, .68, -.56), transform .3s .3s;
}
イージング適用 #2
同じく動き自体はクリックに回転しながらクローズボタンに変化するという単純なものですが、cubic-bezier()
を使ってクリック時に一度左へ若干回転後に右回転しながらクローズボタンに変化する動きになっています。
こちらはウィンドウ左からスライド表示されるドロワーメニューを採用したサイト向けに以前作成しました。
実装にはCSSで下記を記述します。
.menu-trigger,
.menu-trigger span {
display: inline-block;
box-sizing: border-box;
}
.menu-trigger {
position: relative;
width: 50px;
height: 44px;
background: none;
border: none;
appearance: none;
cursor: pointer;
transition: .6s cubic-bezier(.68, -.5, .32, 1.6);
}
.menu-trigger:focus:not(:focus-visible) {
outline: none;
}
.menu-trigger span {
position: absolute;
width: 100%;
height: 4px;
background: #fff;
border-radius: 4px;
transition: .3s .2s;
}
.menu-trigger span:nth-of-type(1) {
top: 0;
left: 0;
}
.menu-trigger span:nth-of-type(2) {
top: 20px;
left: 0;
}
.menu-trigger span:nth-of-type(3) {
bottom: 0;
left: 0;
}
.menu-trigger.active {
transform: rotate(180deg);
}
.menu-trigger.active span:nth-of-type(1) {
transform: translateY(20px) rotate(-45deg);
}
.menu-trigger.active span:nth-of-type(2) {
transform: translateY(0) rotate(45deg);
}
.menu-trigger.active span:nth-of-type(3) {
opacity: 0;
}
各ラインが異なる方向に縮小しながら非表示になり、その後クローズボタンを表示 #1
クリックすると各ラインが左・中央・右とそれぞれ異なる方向に縮小しながら最後は非表示になり、その後クローズボタンが表示されます。
実装にはCSSで下記を記述します。
.menu-trigger,
.menu-trigger span {
display: inline-block;
box-sizing: border-box;
}
.menu-trigger {
position: relative;
width: 50px;
height: 44px;
background: none;
border: none;
appearance: none;
cursor: pointer;
}
.menu-trigger:focus:not(:focus-visible) {
outline: none;
}
.menu-trigger::before,
.menu-trigger::after {
content: '';
}
.menu-trigger::before,
.menu-trigger::after,
.menu-trigger span {
position: absolute;
width: 100%;
height: 4px;
background: #fff;
border-radius: 4px;
transition: .2s;
}
.menu-trigger::before {
top: 3px;
left: 8px;
transform-origin: 0 0;
transform: rotate(45deg) scaleX(0);
transition-delay: 0s;
}
.menu-trigger::after {
bottom: 3px;
left: 8px;
transform-origin: 0 100%;
transform: rotate(-45deg) scaleX(0);
transition-delay: 0s;
}
.menu-trigger span:nth-of-type(1) {
top: 0;
left: 0;
transform-origin: 0 0;
transition-delay: .3s;
}
.menu-trigger span:nth-of-type(2) {
top: 20px;
left: 0;
transform-origin: 50% 50%;
transition-delay: .3s;
}
.menu-trigger span:nth-of-type(3) {
right: 0;
bottom: 0;
transform-origin: 100% 0;
transition-delay: .3s;
}
.menu-trigger.active::before {
transform: rotate(45deg) scaleX(1);
transition-delay: .3s;
}
.menu-trigger.active::after {
transform: rotate(-45deg) scaleX(1);
transition-delay: .3s;
}
.menu-trigger.active span:nth-of-type(-n+3) {
transform: scaleX(0);
transition-delay: 0s;
}
各ラインが異なる方向に縮小しながら非表示になり、その後クローズボタンを表示 #2
基本的な動きは上で紹介したものと同じですが、クローズボタン表示時にラインの表示タイミングをtransition-delay
を使って変更したものです。
実装にはCSSで下記を記述します。
.menu-trigger,
.menu-trigger span {
display: inline-block;
box-sizing: border-box;
}
.menu-trigger {
position: relative;
width: 50px;
height: 44px;
background: none;
border: none;
appearance: none;
cursor: pointer;
}
.menu-trigger:focus:not(:focus-visible) {
outline: none;
}
.menu-trigger::before,
.menu-trigger::after {
content: '';
}
.menu-trigger::before,
.menu-trigger::after,
.menu-trigger span {
position: absolute;
width: 100%;
height: 4px;
background: #fff;
border-radius: 4px;
transition: .2s;
}
.menu-trigger::before {
top: 3px;
left: 8px;
transform-origin: 0 0;
transform: rotate(45deg) scaleX(0);
transition-delay: 0s;
}
.menu-trigger::after {
top: 3px;
right: 9px;
transform-origin: 100% 0;
transform: rotate(-45deg) scaleX(0);
transition-delay: .2s;
}
.menu-trigger span:nth-of-type(1) {
top: 0;
left: 0;
transform-origin: 0 0;
transition-delay: .5s;
}
.menu-trigger span:nth-of-type(2) {
top: 20px;
left: 0;
transform-origin: 50% 50%;
transition-delay: .5s;
}
.menu-trigger span:nth-of-type(3) {
right: 0;
bottom: 0;
transform-origin: 100% 0;
transition-delay: .5s;
}
.menu-trigger.active::before {
transform: rotate(45deg) scaleX(1);
transition-delay: .3s;
}
.menu-trigger.active::after {
transform: rotate(-45deg) scaleX(1);
transition-delay: .5s;
}
.menu-trigger.active span:nth-of-type(-n+3) {
transform: scaleX(0);
transition-delay: 0s;
}
ラインがひとつずつ縮小して非表示になり、その後クローズボタンを表示
クリックで上から順にラインが縮小しつつ非表示になり、その後クローズボタンが表示されます。
各ラインのアニメーションタイミングはtransition-delay
を使ってずらしており、クローズボタン表示時のライン表示タイミングもtransition-delay
を使ってずらしています。
実装にはCSSで下記を記述します。
.menu-trigger,
.menu-trigger span {
display: inline-block;
box-sizing: border-box;
}
.menu-trigger {
position: relative;
width: 50px;
height: 44px;
background: none;
border: none;
appearance: none;
cursor: pointer;
}
.menu-trigger:focus:not(:focus-visible) {
outline: none;
}
.menu-trigger::before,
.menu-trigger::after {
content: '';
}
.menu-trigger::before,
.menu-trigger::after,
.menu-trigger span {
position: absolute;
width: 100%;
height: 4px;
background: #fff;
border-radius: 4px;
transition: .2s;
}
.menu-trigger::before {
top: 3px;
left: 8px;
transform-origin: 0 0;
transform: rotate(45deg) scaleX(0);
transition-delay: 0s;
}
.menu-trigger::after {
top: 3px;
right: 9px;
transform-origin: 100% 0;
transform: rotate(-45deg) scaleX(0);
transition-delay: .2s;
}
.menu-trigger span:nth-of-type(-n+3) {
left: 0;
transform-origin: 100% 0;
transition-delay: .5s;
}
.menu-trigger span:nth-of-type(1) {
top: 0;
}
.menu-trigger span:nth-of-type(2) {
top: 20px;
}
.menu-trigger span:nth-of-type(3) {
bottom: 0;
}
.menu-trigger.active::before {
transform: rotate(45deg) scaleX(1);
transition-delay: .6s;
}
.menu-trigger.active::after {
transform: rotate(-45deg) scaleX(1);
transition-delay: .8s;
}
.menu-trigger.active span:nth-of-type(-n+3) {
transform: scaleX(0);
}
.menu-trigger.active span:nth-of-type(1) {
transition-delay: .1s;
}
.menu-trigger.active span:nth-of-type(2) {
transition-delay: .25s;
}
.menu-trigger.active span:nth-of-type(3) {
transition-delay: .4s;
}
ラインがひとつずつフェードアウトし、その後クローズボタンを表示
こちらも基本的な動きとしてはクリックで上から順にラインが非表示後にクローズボタンが表示されるもので、非表示の動きを右に移動しつつフェードアウトするようにしたものです。
実装にはCSSで下記を記述します。
.menu-trigger,
.menu-trigger span {
display: inline-block;
box-sizing: border-box;
}
.menu-trigger {
position: relative;
width: 50px;
height: 44px;
background: none;
border: none;
appearance: none;
cursor: pointer;
}
.menu-trigger:focus:not(:focus-visible) {
outline: none;
}
.menu-trigger::before,
.menu-trigger::after {
content: '';
}
.menu-trigger::before,
.menu-trigger::after,
.menu-trigger span {
position: absolute;
width: 100%;
height: 4px;
background: #fff;
border-radius: 4px;
transition: .2s;
}
.menu-trigger::before {
top: 3px;
left: 8px;
transform-origin: 0 0;
transform: rotate(45deg) scaleX(0);
transition-delay: 0s;
}
.menu-trigger::after {
top: 3px;
right: 9px;
transform-origin: 100% 0;
transform: rotate(-45deg) scaleX(0);
transition-delay: .2s;
}
.menu-trigger span:nth-of-type(1) {
top: 0;
left: 0;
transition-delay: .4s;
}
.menu-trigger span:nth-of-type(2) {
top: 20px;
left: 0;
transition-delay: .55s;
}
.menu-trigger span:nth-of-type(3) {
bottom: 0;
left: 0;
transition-delay: .7s;
}
.menu-trigger.active::before {
transform: rotate(45deg) scaleX(1);
transition-delay: .6s;
}
.menu-trigger.active::after {
transform: rotate(-45deg) scaleX(1);
transition-delay: .8s;
}
.menu-trigger.active span:nth-of-type(-n+3) {
transform: translateX(20px);
opacity: 0;
}
.menu-trigger.active span:nth-of-type(1) {
transition-delay: .1s;
}
.menu-trigger.active span:nth-of-type(2) {
transition-delay: .25s;
}
.menu-trigger.active span:nth-of-type(3) {
transition-delay: .4s;
}
ラインがひとつずつフェードアウトし、その後クローズボタンを表示+α
こちらは上のサンプルの動きをベースにしつつcubic-bezier()
を組み合わせたもので、クリックした際にラインが若干左にずれた後に右へフェードアウトしていく動きになります。
実装にはCSSで下記を記述します。
.menu-trigger,
.menu-trigger span {
display: inline-block;
box-sizing: border-box;
}
.menu-trigger {
position: relative;
width: 50px;
height: 44px;
background: none;
border: none;
appearance: none;
cursor: pointer;
}
.menu-trigger:focus:not(:focus-visible) {
outline: none;
}
.menu-trigger::before,
.menu-trigger::after {
content: '';
}
.menu-trigger::before,
.menu-trigger::after,
.menu-trigger span {
position: absolute;
width: 100%;
height: 4px;
background: #fff;
border-radius: 4px;
}
.menu-trigger::before {
top: 3px;
left: 8px;
transform-origin: 0 0;
transform: rotate(45deg) scaleX(0);
transition: .2s;
}
.menu-trigger::after {
top: 3px;
right: 9px;
transform-origin: 100% 0;
transform: rotate(-45deg) scaleX(0);
transition: .2s .2s;
}
.menu-trigger span:nth-of-type(-n+3) {
left: 0;
transition: .2s .4s;
}
.menu-trigger span:nth-of-type(1) {
top: 0;
}
.menu-trigger span:nth-of-type(2) {
top: 20px;
}
.menu-trigger span:nth-of-type(3) {
bottom: 0;
}
.menu-trigger.active::before {
transform: rotate(45deg) scaleX(1);
transition-delay: .8s;
}
.menu-trigger.active::after {
transform: rotate(-45deg) scaleX(1);
transition-delay: 1s;
}
.menu-trigger.active span:nth-of-type(-n+3) {
transform: translateX(20px);
transition: .4s cubic-bezier(.68, -2, .32, 1.6);
opacity: 0;
}
.menu-trigger.active span:nth-of-type(2) {
transition-delay: .1s;
}
.menu-trigger.active span:nth-of-type(3) {
transition-delay: .3s;
}
上で紹介した動きをまとめて確認したい場合は以下でご覧になれます。
また、他のエフェクトとしていずれもここでは紹介していないものを以下で紹介しています。
上のものに比べれば比較的シンプルなものになっているので、もう少し簡易的なものが好みであればこちらも併せてご覧ください。