【CSS】ハンバーガーメニュー実装サンプル集(クリック時のエフェクトも集めました)
- 更新
- デザインのメモ



クリックエフェクト サンプル集
いろんなハンバーガーメニューのクリック時のエフェクトを作ってみる。
動きがわかりやすいようにゆっくり動くように指定。
スピードを変えたいときは、transitionを変更する。
ボタンを押すと形が変わって、もう一度押すと、もとに戻ります。
(2026年10月に、見本を新しくしました)
HTML は、ボタン1つ分です。id を btn01〜btn19 に変えると、それぞれの動きになります。04 だけは、ボタンの親に perspective: 1000px; を付けてください。
コードを見る(HTML・CSS・JavaScript)
HTML
<button class="btn-trigger" id="btn01" aria-label="メニュー">
<span></span>
<span></span>
<span></span>
</button>
CSS
/*=============================
.btn-trigger(共通)
=============================*/
.btn-trigger {
position: relative;
width: 50px;
height: 44px;
padding: 0;
border: 0;
background: none;
cursor: pointer;
}
.btn-trigger span {
position: absolute;
left: 0;
width: 100%;
height: 4px;
background-color: #2b2a27;
border-radius: 4px;
}
.btn-trigger,
.btn-trigger span {
display: inline-block;
transition: all .5s;
box-sizing: border-box;
}
.btn-trigger span:nth-of-type(1) { top: 0; }
.btn-trigger span:nth-of-type(2) { top: 20px; }
.btn-trigger span:nth-of-type(3) { bottom: 0; }
@keyframes bar-hide { 100% { height: 0; } }
/* 01 */
#btn01.active span:nth-of-type(1) { transform: translateY(20px) rotate(-45deg); }
#btn01.active span:nth-of-type(2) { opacity: 0; }
#btn01.active span:nth-of-type(3) { transform: translateY(-20px) rotate(45deg); }
/* 02 */
#btn02.active span:nth-of-type(1) { transform: translateY(20px) rotate(45deg); }
#btn02.active span:nth-of-type(2) { opacity: 0; }
#btn02.active span:nth-of-type(3) { transform: translateY(-20px) rotate(-45deg); }
/* 03 */
#btn03.active { transform: rotate(360deg); }
#btn03.active span:nth-of-type(1) { transform: translateY(20px) rotate(-45deg); }
#btn03.active span:nth-of-type(2) { transform: translateY(0) rotate(45deg); }
#btn03.active span:nth-of-type(3) { opacity: 0; }
/* 04(親に perspective: 1000px) */
#btn04 span:nth-of-type(3) { transition: none; }
#btn04.active { transform: rotateX(720deg); }
#btn04.active span:nth-of-type(1) { transform: translateY(20px) rotate(-45deg); }
#btn04.active span:nth-of-type(2) { transform: translateY(0) rotate(45deg); }
#btn04.active span:nth-of-type(3) { opacity: 0; }
/* 05 */
#btn05.active span:nth-of-type(1) { transform: translateY(20px) rotate(-45deg); }
#btn05.active span:nth-of-type(2) { left: 50%; opacity: 0; animation: bar-hide .8s forwards; }
#btn05.active span:nth-of-type(3) { transform: translateY(-20px) rotate(45deg); }
/* 06 */
#btn06.active span:nth-of-type(1) { transform: translateY(20px) rotate(-45deg); }
#btn06.active span:nth-of-type(2) { left: 200%; opacity: 0; transform: translateY(10px); animation: bar-hide .8s forwards; }
#btn06.active span:nth-of-type(3) { transform: translateY(-20px) rotate(45deg); }
/* 07(下がってから回る) */
#btn07 span:nth-of-type(1) { animation: btn07-bar01 .75s forwards; }
#btn07 span:nth-of-type(2) { transition: all .25s .25s; opacity: 1; }
#btn07 span:nth-of-type(3) { animation: btn07-bar03 .75s forwards; }
#btn07.active span:nth-of-type(1) { animation: active-btn07-bar01 .75s forwards; }
#btn07.active span:nth-of-type(2) { opacity: 0; }
#btn07.active span:nth-of-type(3) { animation: active-btn07-bar03 .75s forwards; }
@keyframes btn07-bar01 {
0% { transform: translateY(20px) rotate(45deg); }
50% { transform: translateY(20px) rotate(0); }
100% { transform: translateY(0) rotate(0); }
}
@keyframes btn07-bar03 {
0% { transform: translateY(-20px) rotate(-45deg); }
50% { transform: translateY(-20px) rotate(0); }
100% { transform: translateY(0) rotate(0); }
}
@keyframes active-btn07-bar01 {
0% { transform: translateY(0) rotate(0); }
50% { transform: translateY(20px) rotate(0); }
100% { transform: translateY(20px) rotate(45deg); }
}
@keyframes active-btn07-bar03 {
0% { transform: translateY(0) rotate(0); }
50% { transform: translateY(-20px) rotate(0); }
100% { transform: translateY(-20px) rotate(-45deg); }
}
/* 08 */
#btn08.active span:nth-of-type(1) { transform: translateY(20px) rotate(-315deg); }
#btn08.active span:nth-of-type(2) { opacity: 0; }
#btn08.active span:nth-of-type(3) { transform: translateY(-20px) rotate(315deg); }
/* 09 */
#btn09.active span:nth-of-type(1) { transform: translateY(20px) rotate(315deg); }
#btn09.active span:nth-of-type(2) { opacity: 0; }
#btn09.active span:nth-of-type(3) { transform: translateY(-20px) rotate(-315deg); }
/* 10・11・12(ボタンごと回る) */
#btn10.active { transform: rotate(-90deg); }
#btn11.active { transform: rotate(90deg); }
#btn12.active { transform: rotate(450deg); }
/* 13・14(左向きの矢印) */
#btn14.active { transform: rotate(360deg); }
#btn13.active span:nth-of-type(1), #btn13.active span:nth-of-type(3),
#btn14.active span:nth-of-type(1), #btn14.active span:nth-of-type(3) { width: 20px; }
#btn13.active span:nth-of-type(1), #btn14.active span:nth-of-type(1) { transform: translate(-1px, 13px) rotate(-45deg); }
#btn13.active span:nth-of-type(3), #btn14.active span:nth-of-type(3) { transform: translate(-1px, -13px) rotate(45deg); }
/* 15・16(右向きの矢印) */
#btn16.active { transform: rotate(-360deg); }
#btn15.active span:nth-of-type(1), #btn15.active span:nth-of-type(3),
#btn16.active span:nth-of-type(1), #btn16.active span:nth-of-type(3) { width: 20px; }
#btn15.active span:nth-of-type(1), #btn16.active span:nth-of-type(1) { transform: translate(31px, 13px) rotate(45deg); }
#btn15.active span:nth-of-type(3), #btn16.active span:nth-of-type(3) { transform: translate(31px, -13px) rotate(-45deg); }
/* 17(まるが出る) */
#btn17::after,
#btn19::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
display: block;
width: 84px;
height: 84px;
margin: -45px 0 0 -45px;
border-radius: 50%;
border: 4px solid transparent;
transition: all .75s;
}
#btn17.active span:nth-of-type(1) { transform: translateY(20px) rotate(45deg); }
#btn17.active span:nth-of-type(2) { left: 60%; opacity: 0; animation: bar-hide .8s forwards; }
#btn17.active span:nth-of-type(3) { transform: translateY(-20px) rotate(-45deg); }
#btn17.active::after { border-color: #2b2a27; }
/* 18(波紋のあとに ×) */
#btn18 span:nth-of-type(1) { animation: btn18-bar01 .5s forwards; }
#btn18 span:nth-of-type(2) { animation: btn18-bar02 .5s forwards; }
#btn18 span:nth-of-type(3) { animation: btn18-bar03 .5s forwards; }
#btn18::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
display: block;
width: 30px;
height: 30px;
margin: -16px 0 0 -16px;
border-radius: 50%;
border: 1px solid rgba(43, 42, 39, .4);
opacity: 0;
}
#btn18.active::after { animation: circle .5s; }
#btn18.active span:nth-of-type(1) { animation: active-btn18-bar01 .5s .5s forwards; }
#btn18.active span:nth-of-type(2) { animation: active-btn18-bar02 .5s .5s forwards; }
#btn18.active span:nth-of-type(3) { animation: active-btn18-bar03 .5s .5s forwards; }
@keyframes btn18-bar01 { 0% { transform: translateY(20px) rotate(-45deg); } 100% { transform: translateY(0) rotate(0); } }
@keyframes btn18-bar02 { 0% { opacity: 0; } 100% { opacity: 1; } }
@keyframes btn18-bar03 { 0% { transform: translateY(-20px) rotate(45deg); } 100% { transform: translateY(0) rotate(0); } }
@keyframes active-btn18-bar01 { 0% { transform: translateY(0) rotate(0); } 100% { transform: translateY(20px) rotate(-45deg); } }
@keyframes active-btn18-bar02 { 0% { opacity: 1; } 100% { opacity: 0; } }
@keyframes active-btn18-bar03 { 0% { transform: translateY(0) rotate(0); } 100% { transform: translateY(-20px) rotate(45deg); } }
@keyframes circle {
0% { transform: scale(.1); opacity: 0; }
50% { opacity: 1; }
100% { transform: scale(3.5); opacity: 0; }
}
/* 19(まるを描きながら回る) */
#btn19.active span:nth-of-type(1) { transform: translateY(20px) rotate(-45deg); }
#btn19.active span:nth-of-type(2) { left: 60%; opacity: 0; animation: bar-hide .8s forwards; }
#btn19.active span:nth-of-type(3) { transform: translateY(-20px) rotate(45deg); }
#btn19.active::after { animation: active-btn19 .7s .25s forwards; }
@keyframes active-btn19 {
0% { border-color: transparent; transform: rotate(0); }
25% { border-color: transparent #2b2a27 transparent transparent; }
50% { border-color: transparent #2b2a27 #2b2a27 transparent; }
75% { border-color: transparent #2b2a27 #2b2a27 #2b2a27; }
100% { border-color: #2b2a27; transform: rotate(-680deg); }
}
/* 動きを減らす設定のとき:すぐに切り替える */
@media (prefers-reduced-motion: reduce) {
.btn-trigger, .btn-trigger span, .btn-trigger::after {
transition-duration: .01ms !important;
animation-duration: .01ms !important;
animation-delay: 0s !important;
}
}
JavaScript
document.querySelectorAll('.btn-trigger').forEach(btn => {
btn.addEventListener('click', () => btn.classList.toggle('active'));
});
実装サンプル 左上にボタンがあるタイプ
ボタンを押すと、左からメニューが出てきます。うしろは少し暗くなって、暗いところを押しても閉じます。
閉じているあいだは、三本線の長さがゆらゆら動きます。
コードを見る(HTML・CSS・JavaScript)
HTML
<div id="navArea">
<nav>
<ul>
<li><a href="#"><span>01</span>デザインのメモ</a></li>
<li><a href="#"><span>02</span>works</a></li>
<li><a href="#"><span>03</span>service</a></li>
<li><a href="#"><span>04</span>contact</a></li>
</ul>
</nav>
<button class="toggle_btn" aria-label="メニュー" aria-expanded="false">
<span></span><span></span><span></span>
</button>
<div id="mask"></div>
</div>
CSS
/* ===== 左上にボタンがあるタイプ ===== */
/* メニュー(左から出る) */
#navArea nav {
position: fixed;
top: 0;
left: 0;
z-index: 3;
width: 300px;
height: 100%;
padding: 96px 32px 32px;
background: #2b2a27;
color: #fff;
transform: translateX(-100%);
transition: transform .5s;
}
#navArea.open nav { transform: translateX(0); }
#navArea nav li { border-bottom: 1px solid rgba(255, 255, 255, .16); }
#navArea nav a { display: flex; align-items: baseline; gap: 16px; padding: 16px 0; }
#navArea nav a span { font-size: 12px; color: #e8dc6a; }
/* うしろを暗くする */
#mask {
position: fixed;
inset: 0;
z-index: 2;
background: rgba(43, 42, 39, .5);
opacity: 0;
visibility: hidden;
transition: .5s;
}
#navArea.open #mask { opacity: 1; visibility: visible; }
/* ボタン */
.toggle_btn {
position: fixed;
top: 16px;
left: 16px;
z-index: 4;
width: 48px;
height: 48px;
border: 0;
border-radius: 50%;
background: #e8dc6a;
cursor: pointer;
}
.toggle_btn span {
position: absolute;
left: 14px;
width: 20px;
height: 2px;
border-radius: 2px;
background: #2b2a27;
transition: .5s;
animation: wave 1.6s infinite; /* 閉じているあいだ、長さがゆれる */
}
.toggle_btn span:nth-child(1) { top: 17px; }
.toggle_btn span:nth-child(2) { top: 23px; animation-delay: .2s; }
.toggle_btn span:nth-child(3) { top: 29px; animation-delay: .4s; }
@keyframes wave { 50% { width: 12px; } }
/* 開いたら × に */
#navArea.open .toggle_btn span { animation: none; }
#navArea.open .toggle_btn span:nth-child(1) { transform: translateY(6px) rotate(-45deg); }
#navArea.open .toggle_btn span:nth-child(2) { opacity: 0; }
#navArea.open .toggle_btn span:nth-child(3) { transform: translateY(-6px) rotate(45deg); }
@media (max-width: 600px) {
#navArea nav { width: 240px; padding: 88px 24px 24px; }
}
@media (prefers-reduced-motion: reduce) {
#navArea * { transition: none !important; animation: none !important; }
}
JavaScript
const nav = document.getElementById('navArea');
const btn = nav.querySelector('.toggle_btn');
const mask = document.getElementById('mask');
btn.addEventListener('click', () => {
const isOpen = nav.classList.toggle('open');
btn.setAttribute('aria-expanded', isOpen);
});
mask.addEventListener('click', () => {
nav.classList.remove('open');
btn.setAttribute('aria-expanded', false);
});
実装サンプル 右上にボタンがあるタイプ
ボタンは右上、メニューも右から出てきます。開くと、三本線がくるっと回って × になります。
コードを見る(HTML・CSS・JavaScript)
HTML
<div id="navArea">
<nav>
<ul>
<li><a href="#"><span>01</span>デザインのメモ</a></li>
<li><a href="#"><span>02</span>works</a></li>
<li><a href="#"><span>03</span>service</a></li>
<li><a href="#"><span>04</span>contact</a></li>
</ul>
</nav>
<button class="toggle_btn" aria-label="メニュー" aria-expanded="false">
<span></span><span></span><span></span>
</button>
<div id="mask"></div>
</div>
CSS
/* ===== 右上にボタンがあるタイプ ===== */
/* メニュー(右から出る) */
#navArea nav {
position: fixed;
top: 0;
right: 0;
z-index: 3;
width: 300px;
height: 100%;
padding: 96px 32px 32px;
background: #e8dc6a;
transform: translateX(100%);
transition: transform .5s;
}
#navArea.open nav { transform: translateX(0); }
#navArea nav li { border-bottom: 1px solid rgba(43, 42, 39, .2); }
#navArea nav a { display: flex; align-items: baseline; gap: 16px; padding: 16px 0; }
#navArea nav a span { font-size: 12px; }
/* うしろを暗くする */
#mask {
position: fixed;
inset: 0;
z-index: 2;
background: rgba(43, 42, 39, .5);
opacity: 0;
visibility: hidden;
transition: .5s;
}
#navArea.open #mask { opacity: 1; visibility: visible; }
/* ボタン */
.toggle_btn {
position: fixed;
top: 16px;
right: 16px;
z-index: 4;
width: 48px;
height: 48px;
border: 0;
border-radius: 50%;
background: #2b2a27;
cursor: pointer;
}
.toggle_btn span {
position: absolute;
left: 14px;
width: 20px;
height: 2px;
border-radius: 2px;
background: #fff;
transition: .5s;
}
.toggle_btn span:nth-child(1) { top: 17px; }
.toggle_btn span:nth-child(2) { top: 23px; }
.toggle_btn span:nth-child(3) { top: 29px; }
/* 開いたら、くるっと回って × に */
#navArea.open .toggle_btn span:nth-child(1) { transform: translateY(6px) rotate(-315deg); }
#navArea.open .toggle_btn span:nth-child(2) { opacity: 0; }
#navArea.open .toggle_btn span:nth-child(3) { transform: translateY(-6px) rotate(315deg); }
@media (max-width: 600px) {
#navArea nav { width: 240px; padding: 88px 24px 24px; }
}
@media (prefers-reduced-motion: reduce) {
#navArea * { transition: none !important; }
}
JavaScript
const nav = document.getElementById('navArea');
const btn = nav.querySelector('.toggle_btn');
const mask = document.getElementById('mask');
btn.addEventListener('click', () => {
const isOpen = nav.classList.toggle('open');
btn.setAttribute('aria-expanded', isOpen);
});
mask.addEventListener('click', () => {
nav.classList.remove('open');
btn.setAttribute('aria-expanded', false);
});
実装サンプル 左上にボタンがあって全体に移動するタイプ
メニューと一緒に、ページ全体が右へずれます。開くと、ボタンは ← の形になります。
ページの中身を .page で囲んで、#navArea のすぐあとに置いてください。
コードを見る(HTML・CSS・JavaScript)
HTML
<div id="navArea">
<nav>
<ul>
<li><a href="#"><span>01</span>デザインのメモ</a></li>
<li><a href="#"><span>02</span>works</a></li>
<li><a href="#"><span>03</span>service</a></li>
<li><a href="#"><span>04</span>contact</a></li>
</ul>
</nav>
<button class="toggle_btn" aria-label="メニュー" aria-expanded="false">
<span></span><span></span><span></span>
</button>
<div id="mask"></div>
</div>
<div class="page">
<!-- ページの中身 -->
</div>
CSS
/* ===== ページごと横にずれるタイプ ===== */
body { overflow-x: hidden; }
/* メニュー(ページのうしろに置いておく) */
#navArea nav {
position: fixed;
top: 0;
left: 0;
z-index: 1;
width: 300px;
height: 100%;
padding: 96px 32px 32px;
background: #f3efe6;
}
#navArea nav li { border-bottom: 1px solid #e8e3d8; }
#navArea nav a { display: flex; align-items: baseline; gap: 16px; padding: 16px 0; }
#navArea nav a span { font-size: 12px; color: #6b675f; }
/* ページ・ボタン・マスクが一緒に右へ動く */
.page { position: relative; z-index: 2; transition: transform .5s; }
#mask {
position: fixed;
inset: 0;
z-index: 3;
background: rgba(43, 42, 39, .15);
opacity: 0;
visibility: hidden;
transition: .5s;
}
#navArea.open ~ .page,
#navArea.open #mask,
#navArea.open .toggle_btn { transform: translateX(300px); }
#navArea.open #mask { opacity: 1; visibility: visible; }
/* ボタン */
.toggle_btn {
position: fixed;
top: 16px;
left: 16px;
z-index: 4;
width: 48px;
height: 48px;
border: 0;
border-radius: 50%;
background: #e8dc6a;
cursor: pointer;
transition: transform .5s;
}
.toggle_btn span {
position: absolute;
left: 14px;
width: 20px;
height: 2px;
border-radius: 2px;
background: #2b2a27;
transform-origin: left center;
transition: .5s;
}
.toggle_btn span:nth-child(1) { top: 17px; }
.toggle_btn span:nth-child(2) { top: 23px; }
.toggle_btn span:nth-child(3) { top: 29px; }
/* 開いたら ← に(上下の線が短くなって、矢じりになる) */
#navArea.open .toggle_btn span:nth-child(1) { width: 10px; transform: translateY(6px) rotate(-45deg); }
#navArea.open .toggle_btn span:nth-child(3) { width: 10px; transform: translateY(-6px) rotate(45deg); }
@media (max-width: 600px) {
#navArea nav { width: 240px; padding: 88px 24px 24px; }
#navArea.open ~ .page,
#navArea.open #mask,
#navArea.open .toggle_btn { transform: translateX(240px); }
}
@media (prefers-reduced-motion: reduce) {
#navArea *, .page { transition: none !important; }
}
JavaScript
const nav = document.getElementById('navArea');
const btn = nav.querySelector('.toggle_btn');
const mask = document.getElementById('mask');
btn.addEventListener('click', () => {
const isOpen = nav.classList.toggle('open');
btn.setAttribute('aria-expanded', isOpen);
});
mask.addEventListener('click', () => {
nav.classList.remove('open');
btn.setAttribute('aria-expanded', false);
});
さいごに





