.png&w=3840&q=75)
Tailwind & Nextjsでレスポンシブ対応(スマホ用)ハンバーガーメニューを作成する
公開日:
更新日:
完成イメージ (スマホ画面ではヘッダーメニューがアイコンになります)

当サイトで使用しているハンバーガーメニューの実装コードを紹介します。
基本的な機能は下記になります。
・画面サイズがsm以下になるとヘッダーのメニューが隠れて、ハンバーガーボタンが表示されます。
・ハンバーガーメニューは画面右側からスライドされ表示、閉じるときもスライドで消えます。
・メニューを閉じたい時はバツボタンを押すか、メニュー外の影になっている部分を押しても閉じることができます。
コード実例
まずコードの全体像です。
Header.tsx
1"use client";
2
3/* eslint-disable */
4import Link from "next/link";
5import React, { useState } from "react";
6import HomeIcon from "@mui/icons-material/Home";
7import HeaderIcon from "./components/HeaderIcon";
8import AppBar from "@mui/material/AppBar";
9import { IconButton, Toolbar } from "@mui/material";
10import ArticleIcon from "@mui/icons-material/Article";
11import IntegrationInstructionsIcon from "@mui/icons-material/IntegrationInstructions";
12import EmailIcon from "@mui/icons-material/Email";
13import MenuIcon from "@mui/icons-material/Menu";
14import ClearIcon from "@mui/icons-material/Clear";
15const Header = () => {
16 const [openMenu, setOpenMenu] = useState(false);
17
18 const handleMenuOpen = () => {
19 setOpenMenu(!openMenu);
20 };
21
22 return (
23 <header className="border-b ">
24 <div className="flex flex-col">
25 <div
26 className={"flex items-center justify-between fixed top-0 z-10 w-full py-3 bg-[#798777]"}
27 >
28 <div
29 className={"mx-auto w-11/12 h-full flex items-center justify-center"}
30 >
31 <div className="w-1/3 flex items-center justify-center"></div>
32 <div className="w-1/3 flex items-center justify-center">
33 <Link href={"/"} className="hover:opacity-50">
34 <div className="w-[300px]">
35 <HeaderIcon className="w-full h-full" />
36 </div>
37 </Link>
38 </div>
39 <div className="w-1/3 flex items-center justify-end"></div>
40 </div>
41 </div>
42 <div>
43 {/* ここからハンバーガーメニューの実装 */}
44 <nav
45 className={
46 openMenu
47 ? " fixed bg-black bg-opacity-40 left-0 top-0 z-50 w-6/12 h-screen flex flex-col justify-start pt-8 px-3 delay-500 fade-in-100 duration-500 "
48 : "fixed right-[-100%] delay-500 fade-out-100 duration-400"
49 }
50 onClick={handleMenuOpen}
51 ></nav>
52 <nav
53 className={
54 openMenu
55 ? "text-left fixed bg-slate-100 right-0 top-0 z-50 w-6/12 h-screen flex flex-col justify-start pt-8 px-3 delay-75 ease-linear duration-500"
56 : "fixed right-[-100%] top-0 delay-75 ease-linear duration-400 z-50"
57 }
58 >
59 <div>
60 <div className="-ml-1">
61 <IconButton onClick={handleMenuOpen}>
62 <ClearIcon fontSize="large" sx={{ color: "black" }} />
63 </IconButton>
64 </div>
65 <ul className="mt-0">
66 <li className="p-3">
67 <Link
68 onClick={handleMenuOpen}
69 href={"/"}
70 className="hover:opacity-50 "
71 >
72 <div className="flex flex-row min-w-20 items-center">
73 <HomeIcon fontSize="small" sx={{ color: "black" }} />
74 <p className=" ml-1 text-base font-semibold min-w-14 sm:text-lg sm:font-bold text-black hover:underline underline-offset-8 decoration-2">
75 ホーム
76 </p>
77 </div>
78 </Link>
79 </li>
80 <li className="p-3">
81 <Link
82 onClick={handleMenuOpen}
83 href={"/mix"}
84 className="hover:opacity-50 min-w-5"
85 >
86 <div className="flex flex-row min-w-20 items-center">
87 <ArticleIcon fontSize="small" sx={{ color: "black" }} />
88 <p className="ml-1 text-base font-semibold sm:text-lg sm:font-bold text-black hover:underline underline-offset-8 decoration-2">
89 雑多記事
90 </p>
91 </div>
92 </Link>
93 </li>
94 <li className="p-3">
95 <Link
96 onClick={handleMenuOpen}
97 href={"/code"}
98 className="hover:opacity-50 min-w-5"
99 >
100 <div className="flex flex-row items-center">
101 <IntegrationInstructionsIcon
102 fontSize="small"
103 sx={{ color: "black" }}
104 />
105 <p className="ml-1 text-base font-semibold sm:text-lg sm:font-bold text-black hover:underline underline-offset-8 decoration-2">
106 開発
107 </p>
108 </div>
109 </Link>
110 </li>
111 </ul>
112 </div>
113 </nav>
114
115 <AppBar position="static" sx={{ bgcolor: "#798777" }}>
116 <Toolbar>
117 <div className="flex sm:hidden justify-end w-full">
118 <IconButton onClick={handleMenuOpen}>
119 <MenuIcon fontSize="large" sx={{ color: "black" }} />
120 </IconButton>
121 </div>
122 <div className=" flex-row mx-auto gap-5 sm:gap-10 hidden sm:flex">
123 <div className="">
124 <Link href={"/"} className="hover:opacity-50 ">
125 <div className="flex flex-row min-w-20 items-center">
126 <HomeIcon fontSize="small" sx={{ color: "black" }} />
127 <p className=" ml-1 text-base font-semibold min-w-14 sm:text-lg sm:font-bold text-black hover:underline underline-offset-8 decoration-2">
128 ホーム
129 </p>
130 </div>
131 </Link>
132 </div>
133 <div className="">
134 <Link href={"/mix"} className="hover:opacity-50 min-w-5">
135 <div className="flex flex-row min-w-20 items-center">
136 <ArticleIcon fontSize="small" sx={{ color: "black" }} />
137 <p className="ml-1 text-base font-semibold sm:text-lg sm:font-bold text-black hover:underline underline-offset-8 decoration-2">
138 雑多記事
139 </p>
140 </div>
141 </Link>
142 </div>
143 <div className="">
144 <Link href={"/code"} className="hover:opacity-50 min-w-5">
145 <div className="flex flex-row items-center">
146 <IntegrationInstructionsIcon
147 fontSize="small"
148 sx={{ color: "black" }}
149 />
150 <p className="ml-1 text-base font-semibold sm:text-lg sm:font-bold text-black hover:underline underline-offset-8 decoration-2">
151 開発
152 </p>
153 </div>
154 </Link>
155 </div>
156 <div className="">
157 <Link href={"/contact"} className="hover:opacity-50 min-w-5">
158 <div className="flex flex-row minw-20 items-center">
159 <EmailIcon fontSize="small" sx={{ color: "black" }} />
160 <p className="ml-1 text-base font-semibold sm:text-lg sm:font-bold text-black hover:underline underline-offset-8 decoration-2">
161 お問い合わせ
162 </p>
163 </div>
164 </Link>
165 </div>
166 </div>
167 </Toolbar>
168 </AppBar>
169 </div>
170 </div>
171 </header>
172 );
173};
174
175export default Header;
176

詳細の説明 44〜51行目
Header.tsx
1<nav
2 className={
3 openMenu
4 ? "fixed bg-black bg-opacity-40 left-0 top-0 z-50 w-6/12 h-screflex flex-col justify-start pt-8 px-3 delay-500 fade-in-1 duration-500 "
5 : "fixed right-[-100%] delay-500 fade-out-100 duration-400"
6 }
7 onClick={handleMenuOpen}
8></nav>
一つ目のnavはメニューが出た時の黒い影になっている部分です。
onClick={handleMenuOpen}
を書くことで影の部分を押してもサイドメニュー(ハンバーガーメニュー)を閉じることができます。
詳細の説明 52〜113行目
Header.tsx
1
2<nav
3 className={
4 openMenu
5 ? "text-left fixed bg-slate-100 right-0 top-0 z-50 w-6/12 h-screeflex flex-col justify-start pt-8 px-3 delay-75 ease-linear duration-500"
6 : "fixed right-[-100%] top-0 delay-75 ease-linear duration-400 z-50"
7 }
8>
9 <div>
10 <div className="-ml-1">
11 <IconButton onClick={handleMenuOpen}>
12 <ClearIcon fontSize="large" sx={{ color: "black" }} />
13 </IconButton>
14 </div>
15 <ul className="mt-0">
16 <li className="p-3">
17 <Link
18 onClick={handleMenuOpen}
19 href={"/"}
20 className="hover:opacity-50 "
21 >
22 <div className="flex flex-row min-w-20 items-center">
23 <HomeIcon fontSize="small" sx={{ color: "black" }} />
24 <p className=" ml-1 text-base font-semibold min-w-14 sm:text-lg sm:font-bold text-black hover:underline underline-offset-8 decoration-2">
25 ホーム
26 </p>
27 </div>
28 </Link>
29 </li>
30 <li className="p-3">
31 <Link
32 onClick={handleMenuOpen}
33 href={"/mix"}
34 className="hover:opacity-50 min-w-5"
35 >
36 <div className="flex flex-row min-w-20 items-center">
37 <ArticleIcon fontSize="small" sx={{ color: "black" }} />
38 <p className="ml-1 text-base font-semibold sm:text-lg sm:font-bold text-black hover:underline underline-offset-8 decoration-2">
39 雑多記事
40 </p>
41 </div>
42 </Link>
43 </li>
44 <li className="p-3">
45 <Link
46 onClick={handleMenuOpen}
47 href={"/code"}
48 className="hover:opacity-50 min-w-5"
49 >
50 <div className="flex flex-row items-center">
51 <IntegrationInstructionsIcon
52 fontSize="small"
53 sx={{ color: "black" }}
54 />
55 <p className="ml-1 text-base font-semibold sm:text-lg sm:font-bold text-black hover:underline underline-offset-8 decoration-2">
56 開発
57 </p>
58 </div>
59 </Link>
60 </li>
61 </ul>
62 </div>
63</nav>
二つ目のnavがサイドメニュー(ハンバーガーメニュー)です。
ease-linear
は一定量の速度で変化させる、という意味です。
duration-400
はどのくらいの時間をかけて変化させるか、という意味です。(数値が少ないと早く、多いと遅くなります)
delay-75
はボタンを押してから少しだけ遅れてアニメーションが開始されるように設定している部分です。
まとめ
本サイトのサイドメニュー(ハンバーガーメニュー)は下記のオカログさんの記事を参考に作成させて頂きました。
※参考記事: React×Tailwindで作るハンバーガーメニュー!
説明などもとても分かりやすく参考になりました。皆さんもぜひ参照してみて下さい。
tailwindのアニメーションの説明などは下記の記事を参考にさせて頂きました。
※参考記事: Transitions|1から始めるTailwindCSS
本記事は以上になります。
ご一読頂きありがとうございました。