如何使用 JavaScript 创建有下拉菜单的响应式导航栏

您所在的位置:网站首页 网页怎么下拉菜单设置密码保护 如何使用 JavaScript 创建有下拉菜单的响应式导航栏

如何使用 JavaScript 创建有下拉菜单的响应式导航栏

2024-07-09 09:08| 来源: 网络整理| 查看: 265

原文: How to Build a Responsive Navigation Bar with a Dropdown Menu using JavaScript

导航栏是网站和 web 应用中经常使用的基本组件。作为一名 web 开发人员,你需要能够为客户的项目或者基本的作品集网站定制它。

在本指南中,你将学习如何只用 HTML、CSS 和 JavaScript 从头开始创建一个导航栏。你还将学习如何从无障碍方面优化它。

下面是这个导航栏的截图:

navigation-bar-final-result

这个设计的灵感来自 Dribbble 上 Tran Mau Tri Tam 的极简导航栏。

第 1 步 - 添加 HTML 标记

为了简洁起见,我们将使用一个叫做 boxicons 的图标库来为这个导航栏导入某些图标。我强烈建议使用内联 SVG。

要使用这个库,请在你的 HTML 文件的 head 插入下面的片段:

该标记被分为三个主要部分:

一个 class 为 nav-start 的 div 元素另一个 div 元素,class 为 nav-end一个 id 为 hamburger 的 button 元素

所有这些元素都将被包裹在一个 header 标签中。为了更好地解释这一点,请复制下面的标记。

Inc Logo user image Create

对于 nav-start,我们有以下元素:

一个 元素作为 logo,包裹在一个 标签中一个 元素,class 为 menu,包含所有导航链接,我们将使用 、 和 定义这些链接

nav-end 有以下元素:

一个 元素,它的 role 是 search,包含一个搜索输入和搜索图标一个 class 为 btn 的按钮元素,我们将使用这个 class 来设计按钮

对于汉堡包按钮:

一个按钮,其 id 和 aria-label 为 hamburger,aria-haspopup 设置为 “true”,aria-expanded 设置为 “false”。这些标签将使我们能够使这个按钮更容易被屏幕阅读器访问。

下面是输出:

markup-elements-broken-down-into-three-main-parts-1导航菜单

导航菜单 是导航链接所在的位置。用下面这个标记替换你先前添加的 nav 元素:

Browse Discover Jobs Livestream About

这里你有一个 nav 标签,它包含一个无序的列表,其中有五个 li 元素,代表每个导航菜单项目:browse、discover、 jobs、livestream 和 about。

前两个元素,browse 和 discover,是 button 元素,将被用来切换它们各自的下拉菜单。而元素 Jobs、livestream 和 about 只是普通的链接。

使用到目前为止的代码,你的结果应该是这样的:

Navigation-markup-with-links-and-popup-buttons下拉元素

接下来,让我们为每个导航按钮定义下拉元素。下面是第一个下拉菜单的标记。把你的标记中的第一个 li 元素替换成这样:

Browse Best of the day

Shorts featured today by curators

Featured Streams

Leading creatives livestreams

Subscriptions

Gain exclusive access

Creative Feed

See trending creations

Browse by apps Adobe XD After Effect Sketch Indesign Figma

你可以在这里获得 SVG 图标。

看看这个标记,我们添加了以下内容:

一个 id 为 dropdown1、class 为 dropdown 的 div 元素。两个 ul 元素,每个元素的 role 是 "menu"。一个 span 元素,其 class 为 dropdown-link-title,作为每个 menu 集合的 header。使用 li 和 a 标签定义的链接集合,li 标签有一个 role 为 "menuitem",每个链接有一个 class 为 dropdown-link。在每个锚标签内,通过 img 标签添加一个图标。

注意:由于通过img标签添加的图标是严格意义上的声明性的,我强烈建议你直接将它们作为SVG元素添加。我这样做只是为了使代码更容易阅读

下面是第二个下拉元素dropdown2的标记:

Discover Browse Categories Branding Illustration Download App MacOS & Windows Linux

最终结果应该是这样:

popup1-and-popup2-markup-1

本教程最后将提供完整的标记。

第 2 步 - 为导航栏设计样式

像往常一样,我们将从重置页面上每个元素的默认 margin 和 padding 开始,添加全局变量,并对一些元素进行一些基本的样式设计。

/* style.css */ @import url("https://fonts.googleapis.com/css2?family=Inter:wght@200;300;400;500;600;700&display=swap"); * { margin: 0; padding: 0; box-sizing: border-box; font-family: "Inter", sans-serif; } :root { --dark-grey: #333333; --medium-grey: #636363; --light-grey: #eeeeee; --ash: #f4f4f4; --primary-color: #2b72fb; --white: white; --border: 1px solid var(--light-grey); --shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px, rgba(0, 0, 0, 0.08) 0px 0px 0px 1px; } body { font-family: inherit; background-color: var(--white); color: var(--dark-grey); letter-spacing: -0.4px; } ul { list-style: none; } a { text-decoration: none; color: inherit; } button { border: none; background-color: transparent; cursor: pointer; color: inherit; }

接下来,添加一些可重复使用的样式。

.btn { display: block; background-color: var(--primary-color); color: var(--white); text-align: center; padding: 0.6rem 1.4rem; font-size: 1rem; font-weight: 500; border-radius: 5px; } .icon { padding: 0.5rem; background-color: var(--light-grey); border-radius: 10px; } .logo { margin-right: 1.5rem; } #nav-menu { border-bottom: var(--border); } .container { display: flex; align-items: center; justify-content: space-between; max-width: 1600px; margin: 0 auto; column-gap: 2rem; height: 90px; padding: 1.2rem 3rem; }

现在你已经得到了这些基本的样式,你可以专注于核心导航栏本身的样式。

导航菜单的样式

下面是为导航栏容器设计的标记:

.menu { position: relative; background: var(--white); } .menu-bar li:first-child .dropdown { flex-direction: initial; min-width: 480px; } .menu-bar li:first-child ul:nth-child(1) { border-right: var(--border); } .menu-bar li:nth-child(n + 2) ul:nth-child(1) { border-bottom: var(--border); } .menu-bar .dropdown-link-title { font-weight: 600; } .menu-bar .nav-link { font-size: 1rem; font-weight: 500; letter-spacing: -0.6px; padding: 0.3rem; min-width: 60px; margin: 0 0.6rem; } .menu-bar .nav-link:hover, .dropdown-link:hover { color: var(--primary-color); } .nav-start, .nav-end, .menu-bar, .right-container, .right-container .search { display: flex; align-items: center; }下拉菜单的样式

除了对下拉菜单进行样式设计外,还将使用 visibility 和 opacity 属性的组合来隐藏它。我们的想法是,只有在一个按钮被点击时才显示菜单。

.dropdown { display: flex; flex-direction: column; min-width: 230px; background-color: var(--white); border-radius: 10px; position: absolute; top: 36px; z-index: 1; visibility: hidden; opacity: 0; transform: scale(0.97) translateX(-5px); transition: 0.1s ease-in-out; box-shadow: var(--shadow); } .dropdown.active { visibility: visible; opacity: 1; transform: scale(1) translateX(5px); } .dropdown ul { display: flex; flex-direction: column; gap: 0.5rem; padding: 1.2rem; font-size: 0.95rem; } .dropdown-btn { display: flex; align-items: center; justify-content: space-between; gap: 0.15rem; } .dropdown-link { display: flex; gap: 0.5rem; padding: 0.5rem 0; border-radius: 7px; transition: 0.1s ease-in-out; } .dropdown-link p { font-size: 0.8rem; color: var(--medium-grey); }

接着,可以通过使用 active class 将 visibility 和 opacity 属性恢复到默认状态来切换该菜单。但我们将通过 JavaScript 来做这件事。

如果你喜欢完全隐藏菜单,可以用 display: none; 代替 opacity 和 visibility 属性。虽然这个属性在 CSS 中不能用过渡来做动画。

右边的菜单样式

接下来,为搜索输入、按钮和个人资料图片添加样式,然后在桌面屏幕上隐藏汉堡包按钮。

.right-container { display: flex; align-items: center; column-gap: 1rem; } .right-container .search { position: relative; } .right-container img { border-radius: 50%; } .search input { background-color: var(--ash); border: none; border-radius: 6px; padding: 0.7rem; padding-left: 2.4rem; font-size: 16px; width: 100%; border: var(--border); } .search .search-icon { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); opacity: 0.6; } #hamburger { display: none; padding: 0.1rem; margin-left: 1rem; font-size: 1.9rem; }

现在它是这样的:

final-styling-output-of-navigation-bar-and-popup-menu

为了完成样式设计,添加媒体查询样式:

@media (max-width: 1100px) { #hamburger { display: block; } .container { padding: 1.2rem; } .menu { display: none; position: absolute; top: 87px; left: 0; min-height: 100vh; width: 100vw; } .menu-bar li:first-child ul:nth-child(1) { border-right: none; border-bottom: var(--border); } .dropdown { display: none; min-width: 100%; border: none !important; border-radius: 5px; position: static; top: 0; left: 0; visibility: visible; opacity: 1; transform: none; box-shadow: none; } .menu.show, .dropdown.active { display: block; } .dropdown ul { padding-left: 0.3rem; } .menu-bar { display: flex; flex-direction: column; align-items: stretch; row-gap: 1rem; padding: 1rem; } .menu-bar .nav-link { display: flex; justify-content: space-between; width: 100%; font-weight: 600; font-size: 1.2rem; margin: 0; } .menu-bar > li:not(:last-child) { padding-bottom: 0.5rem; border-bottom: var(--border); } } @media (max-width: 600px) { .right-container { display: none; } }

首先,这排列了元素,最重要的是,它定位 hamburger class 并将其隐藏。现在在平板电脑和手机屏幕上,导航栏是响应式的,汉堡包按钮是可见的。

responsive-navigation-bar-2

这就完成了导航栏的样式设计。让我们在下一节中进行功能设计。

第 3 步 - 添加 JavaScript 功能

对于 JavaScript 功能,我们将专注于以下几个类别:

切换下拉菜单的可见性关闭下拉菜单切换汉堡包菜单的可见性切换 aria-expanded 属性

首先,使用 DOM 的 querySelector 方法选择你的类,并将它们存储在变量中,以便它们可以重复使用。

// script.js const dropdownBtn = document.querySelectorAll(".dropdown-btn"); const dropdown = document.querySelectorAll(".dropdown"); const hamburgerBtn = document.getElementById("hamburger"); const navMenu = document.querySelector(".menu"); const links = document.querySelectorAll(".dropdown a");

接下来在你的代码中添加下面的函数。我稍后将解释它们的用途。

function setAriaExpandedFalse() { dropdownBtn.forEach((btn) => btn.setAttribute("aria-expanded", "false")); } function closeDropdownMenu() { dropdown.forEach((drop) => { drop.classList.remove("active"); drop.addEventListener("click", (e) => e.stopPropagation()); }); } function toggleHamburger() { navMenu.classList.toggle("show"); }获取下拉菜单 ID

下一步是获取下拉菜单的 ID。由于有两个下拉菜单,其值将基于点击的下拉按钮。

为了获得 ID,你将利用 dataset 属性,然后将该值存储到它自己的变量中。

dropdownBtn.forEach((btn) => { btn.addEventListener("click", function (e) { const dropdownIndex = e.currentTarget.dataset.dropdown; const dropdownElement = document.getElementById(dropdownIndex); console.log(dropdownElement); }); });

理解这个片段:

forEach 方法遍历按钮的集合addEventListener() 方法为每个按钮附加了一个点击事件currentTarget.dataset 属性获取被点击按钮的当前下拉菜单每一个 id 都被用来定位相应的下拉元素

这意味着,当 dataset 为 dropdown1 的按钮被点击时,id 为 dropdown1 的 div 元素被记录到控制台,反之则为 dropdown2 按钮。

get-popup-element-id-dynamically-1使用按钮 dataset 属性动态地获得每个下拉元素切换下拉菜单

切换菜单是相当容易的,因为你已经把下拉元素的 ID 存储到一个叫作 dropdownElement 的变量中。通过定位这个变量,你可以切换每个下拉元素的 active class。

dropdownBtn.forEach((btn) => { btn.addEventListener("click", function (e) { const dropdownIndex = e.currentTarget.dataset.dropdown; const dropdownElement = document.getElementById(dropdownIndex); dropdownElement.classList.toggle("active"); dropdown.forEach((drop) => { if (drop.id !== btn.dataset["dropdown"]) { drop.classList.remove("active"); } }); e.stopPropagation(); }); });

除了切换下拉菜单外,我们还添加了一个条件,检查当前下拉元素的 id 是否与活动按钮相匹配。这可以确保每次只有一个下拉元素被展开。

toggling-dropdown-element切换下拉菜单切换 aria-expanded 属性

aria-expanded 属性允许辅助技术告知一个交互式菜单是展开还是折叠的。要切换这个属性,请在 btn 代码块中的 e.stopPropagation() 下插入这段代码:

btn.setAttribute( "aria-expanded", btn.getAttribute("aria-expanded") === "false" ? "true" : "false" );

现在,只要下拉菜单是可见的,aria-expanded 属性就被设置为 true;而当菜单折叠时,它被设置为 false。

toggling-the-aria-expanded-property切换 aria-expanded 属性折叠下拉菜单

到目前为止,下拉菜单只有在点击按钮的时候才会折叠。它应该被折叠的其他情况包括:

当点击下拉菜单内的链接时当你按下 ESC 键时当你点击文档主体时——在下拉容器之外

通过调用前面创建的函数 closeDropdownMenu 和 setAriaExpandedFalse,可以折叠下拉菜单并将 aria-expanded 属性设置为 false。

// 当点击下拉链接时关闭下拉菜单 links.forEach((link) => link.addEventListener("click", () => { closeDropdownMenu(); setAriaExpandedFalse(); }) ); // 当点击文档主体时关闭下拉菜单 document.documentElement.addEventListener("click", () => { closeDropdownMenu(); setAriaExpandedFalse(); }); // 当按 ESC 键时关闭下拉菜单 document.addEventListener("keydown", (e) => { if (e.key === "Escape") { closeDropdownMenu(); setAriaExpandedFalse(); } });

下面是输出:

closing-dropdown-menu-when-dropdown-links-and-escape-key-is-clicked切换汉堡包菜单

要在平板电脑和手机屏幕上看到导航栏,请将 toggleHamburger 函数作为汉堡包按钮的回调,然后在 links 代码块内调用该函数。

links.forEach((link) => link.addEventListener("click", () => { closeDropdownMenu(); setAriaExpandedFalse(); toggleHamburger(); }) );hamburgerBtn.addEventListener("click", toggleHamburger);

这会切换一个名为 show 的不同 class,控制显示或隐藏导航栏。

下面是最终的输出:

show-hamburger-menu-on-tablet-and-mobile-screens添加更多下拉菜单

你可以添加更多下拉菜单,只需将任何一个列表项替换为按钮和下拉菜单的链接。为了使其发挥作用,请确保你更新以下内容:

根据你需要的菜单数量,更新下拉菜单的 ID。例如,第三个菜单的 ID 是 dropdown3按钮的 data-dropdown 值将设置为 dropdown3

下面是一个将 Jobs 链接转换为下拉菜单的例子。

之前:Jobs之后: Jobs Software Frontend Backend AI/ML Mobile Development Others UI/UX Technical Writing

这是最终的结果:

additional-dropdown-menu

按照这个过程,你可以添加你想要的下拉菜单。

就这样,你用 HTML、CSS 和 JavaScript 成功地创建了一个带有下拉菜单的响应式导航栏。你还学会了如何使用包括 aria-expanded 属性在内的几个 aria 属性来使菜单可访问。

下面是测试这个导航栏运行情况的 CodePen 文件:

这是 GitHub 的代码链接。

总结

我真诚地希望你觉得这篇文章有趣或有用。如果你这么想,请与你的朋友分享它或订阅我的博客,这样你就不会错过任何未来的文章。感谢阅读。

GitHub | Twitter | Blog | LinkedIn



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3