导航栏开发全攻略:hanav 助力无障碍和细腻动画

342 阅读13分钟

导航栏很重要,企业或产品把最希望用户到达的地址放入了导航栏,一切从导航栏开始。

导航栏风格多变,下面我们会从复杂程度出发,将它们分为基础 air 版和进阶 pro 版,由浅入深介绍我是如何开发一款导航栏的,同时介绍 hanav 这个导航栏组件库,带领我们顺流直下,帮助完成进阶导航栏的开发。

TLDR:使用 hanav 开发高可访问键盘控制响应式动画丝滑的导航栏(在线演示Edit hanav-demo

基础导航栏 Air

有的网站导航栏简单直观。例如文档类网站,React 官网导航栏非常精简,由几个链接、一个搜索框和一个主题按钮组成;Vue 官网的导航栏则有一些需要 hover 才出现的文字列表菜单,而这个列表菜单已经是基础导航栏里最复杂的模样了。

VueReact
Vue 官网的导航栏,鼠标悬浮在导航栏中的“playground”按钮上,并展开了一个文字列表菜单React 官网的导航栏,导航栏只包含几个链接和一个搜索框以及一个主题按钮

实现这样的导航栏不太困难,如果想为面板绣朵花、加一些动画,在 CSS 中设置 opacityvisiblitytransformtransition 即可,但是要特别注意其中的 visibility 不能遗漏,否则会导致键盘无法正常地 Tab 访问:

hanav

上图中导航栏的菜单面板消失后没有设置 visibility,从焦点的外边框可以看到,按下键盘的 Tab 访问到了本不该访问的未展开的菜单面板内容。

其次,上图暴露了另一个容易忽略的常见错误,菜单的触发器是一个普通元素 <div>,而非可以被聚焦的控件 <button>,注意“产品功能”这个触发器无法被聚焦。

元素使用 CSS 过渡动画消失后,需要设置 visibility: hidden,来避免键盘和屏幕阅读器的错误访问。

也许 visiblity<button> 就是基础导航栏最难的技术细节了。

进阶导航栏 Pro

下面有四个网站的导航栏,它们是 hanav 的灵感来源。第一眼看见它们的时候,一定会被细腻的动画和图文并茂的内容深深吸引:

AppleVercelRadix UIGoogle
Apple 官网导航栏Vercel 官网导航栏Radix UI 导航栏组件Google 安卓开发者官网导航栏

一眼很难深刻体会复杂的导航栏,更重要的是感受内在品质,我们要亲手验证屏幕阅读器能否正常导航、键盘能否完全控制。下面我们会从高可访问性、键盘导航和动画,三个角度来更进阶地了解导航栏。

下面的内容讨论热度低,所有会有较多的概念解释,理解了这些概念将有助于开发导航栏和各类高品质组件或应用。

高可访问

当前的前端技术环境关于可访问性的讨论热度不高,不过随着时间推移,情况会越来越好。

从企业和产品的角度,客户群体的不断扩大,只有具备多元和包容的品质才能照顾到每个人;从开发者的角度,有一部分会受到企业发展的影响,另一部分,当上层功能不断完善,或者意识到功能永远无法满足时,也许会转而关注那些能让程序变得坚固耐用的基础技术。

高可访问性让“能用”变得“好用”。

什么是可访问性 A11y(Accessibility),最常见的是设置图片的 alt 属性,以供网络差或图片资源丢失,看不见图片的情况下仍然有机会了解能概括图片的文字信息,可见可访问性是一个普及所有人的概念,而非针对特定群体:

下面有几张图片,每张对应了一个可访问性优化项的实践,可以帮助更形象地理解可访问性的应用:

高对比度弱网访问快速导航减弱动画效果
三星的 S24 产品页面的底部提供了高对比度按钮,选择后出现黑色背景、黄色文字三星的 S24 产品页面的底部提供了一个高带宽和低带宽的选项在微软的官网按下 Tab 将出现“跳至主内容”,回车后会聚焦导航栏之后的主体内容苹果的官网可以识别用户是否打开了操作系统的“减弱动态效果”,打开之后,页面的动效减少了

音乐应用 Spotify 有优秀的可访问性,Spotify 团队把可访问性纳入了软件开发生命周期,想了解更多关于 A11y 的实践可以查看他们的技术文档“可访问性指南”。

有了上面的可访问性基础,接下来我们为导航栏对号入座一些优化项。可以打开 hanav 演示网页,方便和后面的例子同步测试,火狐浏览器的开发者工具包含一个可访问性面板,有助于调试诸如对比度、焦点顺序之类的可访问性相关特性。

语义标签和原生控件

导航栏使用 <nav> 存放网站最常用的链接,使用 <button> 触发菜单面板的展开。使用 <button> 作为点击事件的元素是常识<button> 会作为控件得到符合操作系统习惯的特性,才能被聚焦和被屏幕阅读器识别;而 <nav> 作为导航栏至少会提供 3 个好处:

  • 利于 SEO;
  • 意义明确便于代码维护;
  • 能被屏幕阅读器识别从而提供便利。

下面的动图演示了我用 macOS 的屏幕阅读器“旁白”,在网站提供了 <nav> 后如何快速访问导航栏:

在一个包含 nav 标签的网页中激活了苹果“旁白”,通过旁白的“转子”工具快速定位到了导航栏内容

打开旁白后,按下 Ctrl-Opt-U 激活旁白工具“转子”,继续按下左右方向键可以找到“地标”过滤项,如果网站使用了 <nav>,导航内容将会出现在这个面板中,回车即可跳跃至导航栏。

不同的辅助技术实现的功能不同,有的辅助技术可能不包含对 <nav> 的识别。

减弱动态效果

CSS 提供了减弱动态效果的媒体查询,通过 JavaScript 同样可以检测操作系统是否开启“减弱动态效果”的选项。下面的动图展示了应用检测到操作系统开启“减弱动态效果”后,切换到导航栏的无动画版本组件的效果:

在一个网页中打开苹果的“减弱动态效果”后,导航栏的动画关闭了

响应式设计

导航栏响应式移动设备时,有一种常见的固定模式,原先桌面导航栏上的内容会被收纳在一个面板中,这个面板由汉堡按钮触发:

AppleNext.jsVue少数派
移动端的苹果官网,点击汉堡按钮之后展开了导航栏面板移动端的 Next.js 官网,点击汉堡按钮之后展开了导航栏面板移动端的 Vue 官网,点击汉堡按钮之后展开了导航栏面板移动端的少数派官网,点击汉堡按钮之后展开了导航栏面板

这导致原来桌面端通过 hover 或点击触发的二级菜单面板变成了移动端的三级菜单,下面的动图演示了导航栏适配移动端后的效果:

一个网站提供了专为移动端设计的导航栏,切换到移动端视图后,导航栏响应式,这时出现了汉堡按钮,点击汉堡按钮出现导航栏触发器按钮面板,并且汉堡按钮变成关闭按钮,接着点击面板的其中一个按钮,出现菜单面板,点击返回按钮,回到了之前的触发器按钮面板,最后点击关闭按钮,菜单面板关闭

辅助技术的 ARIA 属性和状态

空的 ARIA 优于错误的 ARIA。

ARIA 属性和状态能增强辅助技术(如屏幕阅读器)的访问,除此之外没有其它作用,另外语义标签已经内置了 ARIA 角色,所以正确地使用语义标签已经做到了辅助技术的增强。

导航栏常见的 ARIA 属性有下面这些:

  • aria-expanded,表示菜单是否展开,可以在用于展开菜单面板的按钮上使用;
  • aria-controls,通常用于触发展开菜单面板的按钮上,它的值是按钮对应菜单面板的 id,表示元素控制着对应 id 的菜单面板;
  • aria-labelledby,通常用于菜单面板上,它的值是面板对应的按钮的 id,表示当前面板可以由 id 元素的内容概括;
  • aria-hidden,跳过屏幕阅读器访问某个元素及其所有子元素;
  • aria-label,类似别名,设置后屏幕阅读器会阅读。

下面的动图展示了设置了 ARIA 属性和状态后,屏幕阅读器访问导航栏的模样:

在一个网站中打开苹果“旁白”,通过 Tab 聚焦导航栏中的元素,当聚焦到触发器按钮 hanav 时,旁白读出“hanav,已收起,按钮”,通过 Escape,焦点从菜单面板回到触发器按钮 hanav,旁白读出“hanav,已收起,按钮,Main,导航”

可以看到,当阅读器访问触发菜单的按钮时,会根据 aria-expanded 的值为 false,读出“已收起”,会根据 aria-label,读出“Main”,这是因为 <nav> 设置了 aria-label="Main"。由于不同屏幕阅读器具备的功能不同,所以部分 ARIA 属性在旁白中暂时无效。

键盘导航

键盘导航是可访问性的一部分,但是这里分解成单独一节,以突出它在用户体验的占比。如果对键盘导航是否实用有疑问,可以把自行车比作鼠标、双脚行走比作键盘,或许自行车可以带我们更快地抵达目的地,但是不能因此就失去双脚行走的能力,有时候双脚更灵活。

一,在优化键盘导航之前,有一些可访问性的常见错误会导致键盘导航失效:

  • 例如在跳转链接的时候使用点击事件和 location.href,而不使用 <a>
  • 在需要点击事件的地方使用 <div>,而不使用 <button>

二,杜绝这样的基础概念问题,确保可聚焦的元素不遗漏之后,再进行错误聚焦逻辑的修复:只聚焦屏幕内显示的元素,不聚焦隐藏元素,例如在“基础导航栏 Air”一节列举的不设置 visibility: hidden 导致透明元素仍然可聚焦的问题。

如果元素的结构合理,那么 Tab 的序列就会是基本正确的,至此,已经可以通过键盘或屏幕阅读器访问整个网页了。基础版的导航栏至少需要做到这一步。

三,进行键盘导航的聚焦优化,让键盘导航符合用户使用操作系统的习惯:

  • 例如焦点跳跃,通过按钮触发对话框时,焦点从按钮跳跃至对话框的第一个可聚焦元素;
  • 焦点循环,焦点会在一组包含头尾的元素中循环流动,通过 Escape 退出循环;
  • Home 跳跃至一组可聚焦元素的头,End 跳跃至尾;
  • 使用方向键进行上下左右元素的聚焦。

四,最后是快捷键的实现,这一步也是键盘战胜鼠标的关键,输入指令永远比 GUI 上的光标移动更快速。要注意,快捷键是一般键盘导航(即 TabShift-Tab)的增强,不是替代关系。下面是三个网站快捷键(按下 Shift-?)的例子:

GitHubTwitterSpotify
GitHub 的首页上有一个快捷键面板Twitter 首页有一个快捷键面板Spotify 页面中有一个快捷键面板

下面的动图展示了在适配键盘导航之后的导航栏,使用键盘访问的模样:

在一个网页中使用 Tab 和 Shift-Tab 导航,当聚焦导航栏触发器按钮时按下回车,焦点从按钮跳跃至菜单面板第一个元素,继续 Tab,按钮到达面板里最后一个可聚焦元素,接着 Tab,按钮又回到了第一个可聚焦元素,按下 Escape,焦点从面板回到了触发器按钮。在面板展开时,通过鼠标点击面板,接着按下 Tab 或 Shift-Tab,焦点会聚焦面板第一个可聚焦元素或最后一个可聚焦元素

可以看到,当焦点聚焦触发器按钮时,按下回车或空格,焦点跳跃至菜单面板的第一个可聚焦元素,当焦点位于菜单面板最后一个可聚焦元素时,按下 Tab,焦点循环跳跃至第一个可聚焦元素,最后按下 Escape,焦点回到触发器按钮并收起了菜单面板。

这样的导航栏可以完全通过 TabShift-TabEscape 访问,对键盘用户非常友好。不止一种焦点控制的实现,如果想了解更多可以查看 W3C 提供的导航栏模版范例以及键盘导航的实践建议

丝滑动画

动画是平淡文字的旋律,是黑白世界的颜料。

下面的动图展示了带有过渡动画的导航栏的样子:

一个网页提供了一个导航栏,当鼠标悬浮在触发器按钮上、切换菜单、移出按钮,出现了丝滑的动画:菜单面板从导航栏内部平滑滑出,切换到另一个菜单时,面板的高度顺滑地变高或变低,并且菜单的内容像履带一样左移或者右移。选择了导航栏的自定义 y 轴动画选项、面板跟随选项、动态宽度选项后,出现了和之前不一样的动画:菜单面板以渐隐的方式出现,切换菜单时,面板会进行顺滑地位移,面板始终以菜单对应的触发器按钮为中心运动,并且面板的宽度是以动画形式变化的

通常在我们平时浏览的网页里,可能“渐隐”配合“位移”的导航栏动画会占多数,并且切换菜单时,两个菜单在动画上不会产生关联。类似:

.default {
    opacity: 0;
    transform: translateY(-5px);
    visibility: hidden;
    transition: opacity .3s, transform .3s, visibility .3s;
}
.expanded {
    opacity: 1;
    transform: translateY(0px);
    visibility: visible;
}

相比,上面动图的动画是一种比较复杂的导航栏切换动画的实现,它有一个好处,它可以很好地表达“内容展现的由来、切换的过程和消失的去向”,很容易被接受和理解。

hanav 默认提供了这种较为复杂的动画,如果回到“进阶导航栏 Pro”这一节的开头,会从 AppleRadix UIVercelGoogle 的有关页面的导航栏找到这个动画的影子。

hanav

以上就是在开发一个导航栏时,我会考虑的几个方向。上面的内容把导航栏分为了基础和进阶,但是这样的分类不代表基础版的导航栏就不好用,如果基础版的导航栏同样具备语义标签、原生控件、基础的键盘交互以及不加多余的 ARIA 属性,那么这个导航栏依然是合格的、并且是好用的,同时基础版的导航栏可以快速地完成开发,后续的进阶优化是可扩展的。

另一方面,如果在您的场景里,需要更周全的设计,刚好符合之前提到的,需要响应式设计、正确的语义标签和 ARIA 属性、合理的动画、允许减弱动态效果,刚好对上面每节最后例子的截图里的导航栏有好感,那么刚好现在是时候引出一直陪伴在我们身边的导航栏组件库 hanav 了。

之前每一节最后的例子截图里的导航栏,都由 hanav 支持,如果想亲自尝试,可以访问 hanav 的演示网页

hanav 为我们做了很多工作,比如可访问性、键盘导航以及动画方面的优化。丝滑直观的动画是 hanav 的一个特点,可是如果希望自定义过渡动画,hanav 同样允许自定义切换菜单、展开和收起菜单的动画。无需担心自定义功能会增加 hanav 的产包、影响摇树,hanav 提供了独立的自定义动画组件,专用于防止无用代码的介入。

其它的,hanav 基于 React,使用形态直观、入参简洁,开发体验友好。尽管 hanav 是一个 React 库,但无论在开发导航栏还是其他组件或应用时,高可访问性键盘导航动画设计始终是通用的,它们让网页从“能用”变得“好用”。


相关链接:

🌷🪻🌹🌻🌷