是时候在 flexbox 中进行实际练习了!在本教程中,我们将使用 flexbox 创建一个移动优先、响应式、可切换的导航栏,具有适用于移动设备、平板电脑和桌面屏幕的不同布局。
本教程已更新为包含响应式子菜单和纯 javascript 而不是 jquery。
Flexbox 非常适合响应式导航
Flexbox 是一个多功能的布局模块,我们可以使用它创建需要灵活性的一维布局,例如响应式菜单。使用 flexbox 的 ordering、alignment 和 sizing 属性,我们可以构建导航栏,使其布局适应视口大小,同时保持 html 大纲的逻辑性和可访问性。
在本教程中,我们将研究如何使用 flexbox 创建响应式导航栏。我们的 flexbox 导航将具有三种不同的布局,具体取决于视口大小:
一种 移动布局 ,默认情况下只有徽标和切换按钮可见,用户可以使用切换打开和关闭菜单,
平板电脑布局,我们将在 徽标之间显示两个号召性用语按钮,并在默认状态下切换,菜单的其余部分将保持可切换状态,
一种 桌面布局 ,其中除了切换按钮之外的所有菜单项都将在屏幕上可见。
我们将使用媒体查询来检测用户浏览器的视口大小。我们的响应式导航栏将是移动优先的,因此我们将首先创建移动布局。min-width 然后,我们将使用媒体查询添加特定于平板电脑和桌面的 css 。
导航栏还将有一个基于 JavaScript 的下拉子菜单,当用户单击父菜单项时会打开和关闭。
以下是菜单在移动设备上的外观:
这是平板电脑版本:
而且,这就是它在桌面上的外观:
您还可以在 CodePen 上测试、分叉和使用交互式演示:
See the Pen Responsive Navigation Bar & Dropdown with Flexbox (updated, no jQuery) by Envato Tuts+ (@tutsplus) on CodePen.
刚接触 Flexbox?
如果您不习惯 flexbox,或者需要复习,这些初学者指南将为您提供完成本教程所需的所有技能:
Flexbox 对齐综合指南安娜莫努斯2021 年 5 月 23 日
Flexbox 排序和重新排序的综合指南安娜莫努斯2021 年 6 月 5 日
Flexbox 大小调整综合指南安娜莫努斯2021 年 6 月 6 日
1. 创建 HTML
HTML 是一个简单的 <ul> 列表,如下所示。类将 .menu 是 flex 容器,列表项将是 flex 项。它们的顺序将适应用户设备的视口大小。例如, 登录 和 注册 按钮将首先出现在移动设备上,但将显示在桌面菜单的末尾。我们将通过使用 flexbox 的排序属性来实现这个效果。
<nav>
<ul class="menu">
<li class="logo"><a href="#">Creative Mind Agency</a></li>
<li class="item"><a href="#">Home</a></li>
<li class="item"><a href="#">About</a></li>
<li class="item has-submenu">
<a tabindex="0">services</a>
<ul class="submenu">
<li class="subitem"><a href="#">Design</a></li>
<li class="subitem"><a href="#">Development</a></li>
<li class="subitem"><a href="#">SEO</a></li>
<li class="subitem"><a href="#">Copywriting</a></li>
</ul>
</li>
<li class="item has-submenu">
<a tabindex="0">Plans</a>
<ul class="submenu">
<li class="subitem"><a href="#">Freelancer</a></li>
<li class="subitem"><a href="#">Startup</a></li>
<li class="subitem"><a href="#">Enterprise</a></li>
</ul>
</li>
<li class="item"><a href="#">Blog</a></li>
<li class="item"><a href="#">Contact</a>
</li>
<li class="item button"><a href="#">Log In</a></li>
<li class="item button secondary"><a href="#">Sign Up</a></li>
<li class="toggle"><a href="#"><i class="fas fa-bars"></i></a></li>
</ul>
</nav>
您可能已经注意到带有子菜单(“服务”和“计划”)的菜单项有一个 没有属性的<a>标签 。href我们这样做是因为这些“空”的父菜单项不会指向任何其他页面——它们只是打开和关闭子菜单。允许使用不带 href 的锚标记,并防止当用户单击空菜单项以打开或关闭子菜单时页面在小屏幕上跳转。
我们还将属性添加到没有tabindex="0"属性的<a>元素href中。这是因为空<a>标签从默认的 tab 顺序中被省略了,所以我们需要将它们放回 tab 顺序并带有tabindex属性以保持菜单键盘可访问。
注意:列表末尾的切换按钮使用 font Awesome 图标。要使演示工作,您需要使用以下代码将 Font Awesome 库添加到 <head> CDN 中的 HTML 文档部分。(如果你想让菜单离线工作,你需要在 本地托管 Font Awesome。)
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/css/all.min.css">
2. 添加一些基本样式
对于基本样式,我设置了一些默认值和颜色,但是您也可以使用任何自己的样式规则:
/* Basic styling */
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
body {
font-family: sans-serif;
font-size: 16px;
}
nav {
background: #222;
padding: 0 15px;
}
a {
color: white;
text-decoration: none;
}
.menu,
.submenu {
list-style-type: none;
}
.logo {
font-size: 20px;
padding: 7.5px 10px 7.5px 0;
}
.item {
padding: 10px;
}
.item.button {
padding: 9px 5px;
}
.item:not(.button) a:hover,
.item a:hover::after {
color: #ccc;
}
3. 从移动导航开始
由于我们的导航将是移动优先的,我们从移动布局开始。flex-direction: column; 大多数响应式 flexbox 菜单在移动设备上使用基于列的布局,因为通过将规则添加到 flex 容器中,菜单项可以快速地在彼此下方打包 。尽管这是一个很好的解决方案,但我们不会在我们的示例中使用它。
相反,我们将为移动设备创建一个环绕的、基于行的布局,以便我们可以在菜单顶部彼此相邻地显示徽标和切换按钮。
这里的 CSS 技巧是我们使用规则使 Home 和 About等常规菜单项 跨越整个容器 width: 100%; 。因此,flexbox 会将它们显示在彼此下方,而 logo 和切换将保持其自然大小并位于同一行的导航栏顶部。
在下面的 CSS 中,我们还使用 justify-content 和 align-items 属性来 水平和垂直对齐弹性项目。除此之外,我们 使用 规则隐藏.item 元素 。display: none;仅当用户单击切换按钮时才会显示菜单项。该类 .active 不在 HTML 代码中,我们将使用 javaScript 动态添加它。
/* Mobile menu */
.menu {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
}
.menu li a {
display: block;
padding: 15px 5px;
}
.menu li.subitem a {
padding: 15px;
}
.toggle {
order: 1;
font-size: 20px;
}
.item.button {
order: 2;
}
.item {
order: 3;
width: 100%;
text-align: center;
display: none;
}
.active .item {
display: block;
}
.button.secondary { /* divider between buttons and menu links */
border-bottom: 1px #444 solid;
}
正如您在上面看到的,我们还借助 order 属性更改了菜单项的顺序。我们的 HTML 大纲遵循逻辑顺序。这就是我们希望屏幕阅读器用户和搜索引擎机器人浏览菜单的方式。
但是,在移动布局中,我们希望在菜单顶部显示徽标和切换按钮。我们还希望在常规菜单项之前显示两个号召性用语按钮(“登录”和“注册”)。因此,我们设置了以下顺序:
.logo 获取 order: 0; 值,因为它将是第一项(但是,由于这是 的默认值 order,我们不需要将其添加到 CSS 中),
.toggle 得到 1,因为它紧随其后 .logo,
.item.button 属于 登录 和 注册 按钮获取 2,
并且 .item 属于其余的菜单项 3。
4. 设置子菜单的样式
由于这是移动优先导航,我们将主要考虑移动屏幕的子菜单样式。这是一项很棒的技术,因为为小屏幕创建用户友好的子菜单通常比为大屏幕创建用户友好的子菜单更难。然后,我们也可以对平板电脑屏幕使用相同的子菜单布局。对于桌面,我们只需要更改子菜单的位置。
默认情况下,子菜单设置为display: none;并且仅在用户单击父菜单项时才会显示。在进入平板电脑菜单之前,我们将在接下来的两个步骤中添加所需的 JavaScript 功能。
/* Submenu up from mobile screens */
.submenu {
display: none;
}
.submenu-active .submenu {
display: block;
}
.has-submenu i {
font-size: 12px;
}
.has-submenu > a::after {
font-family: "Font Awesome 5 Free";
font-size: 12px;
line-height: 16px;
font-weight: 900;
content: "\f078";
color: white;
padding-left: 5px;
}
.subitem a {
padding: 10px 15px;
}
.submenu-active {
background-color: #111;
border-radius: 3px;
}
正如您在上面看到的,现在我们使用 CSS 而不是 HTML 添加 Font Awesome 图标。::after我们使用伪元素添加的这些图标将是显示在每个具有子菜单的菜单项旁边 的小向下箭头。
如果您还记得我们在第 1 步中为带有 HTML 的切换按钮添加了 Font Awesome 图标。这是因为切换按钮将以 JavaScript 为目标,因此它必须存在于 dom 中。但是,这里的向下箭头只是指示子菜单存在的样式元素。由于没有任何功能依赖于它们,因此最好使用 CSS 添加它们。
5. 使用 JavaScript 添加切换功能
我们将通过向在移动设备上打开和关闭菜单的切换按钮添加一个单击事件***器来设置切换功能。在 JavaScript 代码中,我们将使用 ES6 语法,它使我们能够访问const 和let符号和for...of循环,并且已经具有良好的浏览器支持。
对于自定义 JavaScript,创建一个空 script.js文件并将其添加到 HTML 的结束</body>标记之前:
<script src="script.js"></script>
这是负责切换功能的 JavaSript 代码:
const toggle = document.queryselector(".toggle");
const menu = document.querySelector(".menu");
/* Toggle mobile menu */
function toggleMenu() {
if (menu.classList.contains("active")) {
menu.classList.remove("active");
// adds the menu (hamburger) icon
toggle.querySelector("a").innerHTML = "<i class=’fas fa-bars’></i>";
} else {
menu.classList.add("active");
// adds the close (x) icon
toggle.querySelector("a").innerHTML = "<i class=’fas fa-times’></i>";
}
}
/* event Listener */
toggle.addEventListener("click", toggleMenu, false);
首先,我们使用该 方法选择菜单和切换按钮 querySelector(), 以便我们可以使用 JavaScript 访问它们。
然后,我们添加toggleMenu()将在单击切换时调用的自定义函数。
最后,我们添加事件***器,该***器将使用该addEventListener()方法***单击事件。
6. 使用 JavaScript 添加下拉功能
现在,当用户单击切换按钮时,菜单被激活和停用,但是,子菜单仍然隐藏。我们将使用以下 JavaScript 添加此功能:
const items = document.querySelectorAll(".item");
/* Activate Submenu */
function toggleItem() {
if (this.classList.contains("submenu-active")) {
this.classList.remove("submenu-active");
} else if (menu.querySelector(".submenu-active")) {
menu.querySelector(".submenu-active").classList.remove("submenu-active");
this.classList.add("submenu-active");
} else {
this.classList.add("submenu-active");
}
}
/* Event Listeners */
for (let item of items) {
if (item.querySelector(".submenu")) {
item.addEventListener("click", toggleItem, false);
item.addEventListener("keypress", toggleItem, false);
}
}
.submenu-active 在这里,当用户单击它时 ,我们将类添加到带有子菜单的每个菜单项。
querySelectorAll()首先,我们使用返回节点列表的方法(而不是像 那样的单个元素)选择所有菜单项querySelector()。
在自定义函数中,我们向/从单击的元素toggleItem()添加和删除。.submenu-active请注意,在该else if块中,我们从之前打开的所有其他菜单项中删除了该类。这样就不会发生两个子菜单同时打开的情况,因为它们可以在桌面上相互覆盖。
最后,我们items使用循环遍历 classList for...of。在该if块中,我们为具有子菜单的菜单项添加了两个事件***器:一个用于click通过单击或点击访问菜单的普通用户的事件,一个keypress用于键盘用户的事件。
7. 创建平板电脑菜单
我们将使用 min-width 媒体查询创建平板电脑布局。在平板电脑上,默认情况下会显示四个菜单项:徽标、两个号召性用语按钮(“登录”和“注册”)和切换按钮。为了让一切变得漂亮,我们的 CSS 将:
更改 order 菜单项以使布局适应平板电脑视口,
重新对齐项目(参见下面的说明),
使 登录 和 注册 按钮看起来像真正的按钮(在移动布局中,它们看起来像链接,因为它们是可切换下拉列表的一部分)。
在代码中:
/* Tablet menu */
@media all and (min-width: 700px) {
.menu {
justify-content: center;
}
.logo {
flex: 1;
}
.item.button {
width: auto;
order: 1;
display: block;
}
.toggle {
flex: 1;
text-align: right;
order: 2;
}
/* Button up from tablet screen */
.menu li.button a {
padding: 10px 15px;
margin: 5px 0;
}
.button a {
background: #0080ff;
border: 1px royalblue solid;
}
.button.secondary {
border: 0;
}
.button.secondary a {
background: transparent;
border: 1px #0080ff solid;
}
.button a:hover {
text-decoration: none;
}
.button:not(.secondary) a:hover {
background: royalblue;
border-color: darkblue;
}
}
在平板电脑布局中,菜单项以不同的方式对齐。如果您看一下四个可见的菜单项,您会看到两个按钮显示在中间,而徽标和切换按钮则被推到容器的左右端:
flex: 1; 我们可以使用CSS 规则来实现这个效果 。该 flex 属性是 flex-grow、 flex-shrink和 的简写flex-basis。它可以与许多不同的值组合存在。当它只用一个值声明时,它属于 flex-grow, flex-shrink 并 flex-basis 保持其默认值。
在上面的 CSS 中,我们 在 and 元素中添加了flex: 1; 规则 。通过这种方式,我们可以告诉浏览器,如果屏幕上有任何正空间,我们希望在这两个元素之间共享它。由于“ 登录” 和 “注册” 按钮保留了它们的默认 值 ,因此它们不会从额外的空间中得到任何东西。因此,它们将停留在容器的中心,因为它们遵守 弹性容器上设置的规则。.logo.toggle0flex-growjustify-content: center;
8. 创建桌面菜单
桌面菜单隐藏了切换,设置回每个项目的原始顺序和自然宽度,并重新定位子菜单。
请务必记住,特定于平板电脑的规则也适用于桌面菜单。这是因为这里的视口宽度大于700px 和 960px,所以两个媒体查询都生效。因此, .logo 保留其 flex: 1; 属性并将其余项目推送到容器的末尾。
/* Desktop menu */
@media all and (min-width: 960px) {
.menu {
align-items: flex-start;
flex-wrap: nowrap;
background: none;
}
.logo {
order: 0;
}
.item {
order: 1;
position: relative;
display: block;
width: auto;
}
.button {
order: 2;
}
.submenu-active .submenu {
display: block;
position: absolute;
left: 0;
top: 68px;
background: #111;
}
.toggle {
display: none;
}
.submenu-active {
border-radius: 0;
}
}
9. 让用户通过单击页面上的任意位置来关闭子菜单
现在只退了一步。由于单击事件激活了下拉菜单,因此当用户将鼠标悬停在顶部菜单项之外时,它不会自动关闭。这在下拉菜单可以覆盖内容的桌面上尤其令人讨厌。
因此,让用户通过单击屏幕上的任意位置来关闭子菜单会很好。我们可以使用 JavaScript 添加该功能:
/* Close Submenu From Anywhere */
function closeSubmenu(e) {
if (menu.querySelector(".submenu-active")) {
let isClickInside = menu
.querySelector(".submenu-active")
.contains(e.target);
if (!isClickInside && menu.querySelector(".submenu-active")) {
menu.querySelector(".submenu-active").classList.remove("submenu-active");
}
}
}
/* Event listener */
document.addEventListener("click", closeSubmenu, false);
自定义closeSubmenu() 函数检查屏幕上是否有打开的子菜单,如果是,它还会检查用户是否在属性的帮助下点击了其中的内容。如果用户单击屏幕上的其他任何位置,该类将被删除,子菜单将自行关闭。我们将事件监听器添加到对象中,因为我们想监听整个页面的点击。target .submenu-active document
您已经使用 Flexbox 和 JavaScript 构建了响应式导航栏!
我们的移动优先、响应式导航栏以三种不同的布局启动并运行。
这里提醒一下最终结果:
See the Pen Responsive Navigation Bar & Dropdown with Flexbox (updated, no jQuery) by Envato Tuts+ (@tutsplus) on CodePen.
Flexbox 是无需任何调整即可实现复杂布局的绝佳工具。如果您将 flexbox 的对齐、排序和尺寸属性与媒体查询结合使用,您可以为不同的视口创建不同的布局,而无需操作 HTML 源代码。