各位观众,各位朋友,大家好!我是今天的主讲人,江湖人称“代码老中医”,专治各种疑难杂症,尤其是前端方面的。今天咱们聊聊CSS里两个挺有意思的家伙:focus-visible
和focus-within
,以及它们如何拯救我们可怜的keyboard-only
导航体验。
开场白:键盘侠的呐喊
先问大家一个问题:你们有多少人是键盘党?注意,我说的是纯键盘操作,鼠标能不用就不用的那种。如果你是,那么恭喜你,你一定经历过这样的痛:
- 焦点乱飞:Tab键按得飞起,但根本不知道现在焦点在哪儿!
- 样式丑陋:默认的focus样式丑的一批,还跟页面风格格格不入!
- 误判敌友:鼠标点一下也触发focus样式,影响美观,用户体验极差!
这些问题,直接导致了键盘侠们寸步难行,严重影响了用户体验。别急,今天咱们就来拯救他们,啊不,是拯救我们的网站!
第一节课:focus
的那些事儿
在深入focus-visible
和focus-within
之前,我们得先搞清楚focus
是个什么东西。简单来说,focus
就是“焦点”。当一个元素获得焦点时,就意味着用户可以通过键盘与它进行交互(比如输入文字、点击按钮等等)。
HTML元素默认情况下,有些是可以获得焦点的,比如<a>
、<button>
、<input>
、<select>
等等。有些元素默认不能获得焦点,比如<div>
、<span>
、<p>
等等。但是,我们可以通过tabindex
属性让任何元素获得焦点。
tabindex="0"
:表示元素可以获得焦点,并且按照HTML结构顺序获得焦点。tabindex="-1"
:表示元素可以获得焦点,但是不能通过Tab键获得焦点,只能通过JavaScript来设置焦点。tabindex="任意正整数"
:表示元素可以获得焦点,并且按照数字大小顺序获得焦点(数字越小,优先级越高)。不建议使用,容易造成混乱。
代码示例:给一个div
加上焦点
<div tabindex="0">
我是一个可以获得焦点的 div
</div>
默认focus
样式的弊端
默认情况下,浏览器会给获得焦点的元素添加一个默认的outline
样式。这个样式通常是一个蓝色的边框,在不同的浏览器中可能略有差异。
这个默认的样式,有两个问题:
- 丑! 真的,大部分情况下它跟你的网站风格格格不入。
- 鼠标党也触发! 用户用鼠标点击元素时,也会触发
focus
样式,这可能会让他们感到困惑,因为他们并没有使用键盘进行导航。
第二节课:focus-visible
:键盘侠的专属福利
focus-visible
的出现,就是为了解决上述问题的。它是一个CSS伪类选择器,只有在键盘导航时,元素获得焦点才会应用样式。
重点: 只有键盘导航才会触发!鼠标点击不会触发!
使用方法:
/* 默认样式 */
button {
border: 1px solid transparent; /* 隐藏默认边框 */
}
/* 键盘导航时,按钮获得焦点时的样式 */
button:focus-visible {
border: 1px solid blue; /* 显示蓝色边框 */
outline: none; /* 移除默认 outline */
}
代码解释:
button { border: 1px solid transparent; }
: 这行代码是为了隐藏按钮默认的边框。有些按钮默认会有边框,为了更好地控制焦点样式,我们先把它隐藏掉。button:focus-visible { ... }
: 这行代码是focus-visible
的核心。只有当用户使用键盘导航,并且按钮获得焦点时,才会应用这里的样式。outline: none;
: 移除浏览器默认的outline
样式,避免与自定义的焦点样式冲突。
兼容性问题:
focus-visible
的兼容性并不是很好,老版本的浏览器可能不支持。为了解决这个问题,我们可以使用polyfill。
polyfill: focus-visible.js
这是一个JavaScript库,可以为不支持focus-visible
的浏览器提供支持。
使用方法:
- 下载
focus-visible.js
: 可以从npm安装npm install focus-visible
或者直接从github下载。 -
在你的HTML文件中引入
focus-visible.js
:<script src="focus-visible.js"></script>
- 然后就可以像上面一样使用
focus-visible
了。
更优雅的写法: :focus-visible
+ :not(:focus-visible)
有时候,我们需要对鼠标点击和键盘导航分别设置不同的样式。这时候,可以结合:not(:focus-visible)
来实现。
/* 默认样式(鼠标点击或其他方式获得焦点) */
button:focus {
/* */
outline:none;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
}
/* 键盘导航时,按钮获得焦点时的样式 */
button:focus-visible {
outline: 2px solid blue;
box-shadow: none;
}
/* 鼠标操作时候移除 focus-visible 的样式 */
button:focus:not(:focus-visible) {
outline:none;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
}
代码解释:
button:focus { ... }
: 这行代码定义了按钮获得焦点时的默认样式,包括鼠标点击或其他方式。button:focus-visible { ... }
: 这行代码定义了键盘导航时,按钮获得焦点时的样式。button:focus:not(:focus-visible){...}
这行代码定义了当元素获得焦点,但不是通过键盘导航的时候,移除focus-visible
的样式,恢复默认的样式,这样可以避免鼠标点击的时候,应用了键盘导航的样式,造成视觉上的混乱。
第三节课:focus-within
:父元素的守护者
focus-within
是另一个CSS伪类选择器。当元素自身或者它的任何后代元素获得焦点时,该元素就会应用focus-within
样式。
重点: 只要后代元素获得焦点,父元素也会应用样式!
使用场景:
- 表单验证:当表单中的任何一个输入框获得焦点时,可以高亮显示整个表单。
- 导航菜单:当导航菜单中的任何一个链接获得焦点时,可以高亮显示整个菜单。
- 卡片组件:当卡片中的任何一个元素获得焦点时,可以高亮显示整个卡片。
代码示例:高亮显示表单
<form class="form">
<label for="name">姓名:</label>
<input type="text" id="name" name="name"><br><br>
<label for="email">邮箱:</label>
<input type="email" id="email" name="email"><br><br>
<button type="submit">提交</button>
</form>
.form {
border: 1px solid #ccc;
padding: 20px;
}
.form:focus-within {
border: 2px solid blue;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
}
代码解释:
.form { ... }
: 定义了表单的默认样式。.form:focus-within { ... }
: 当表单或者表单内的任何一个元素获得焦点时,表单的边框会变成蓝色,并且添加阴影。
结合focus-visible
和focus-within
我们可以将focus-visible
和focus-within
结合起来使用,实现更精细的控制。
代码示例:只在键盘导航时高亮显示表单
.form {
border: 1px solid #ccc;
padding: 20px;
}
.form:focus-within:focus-visible {
border: 2px solid blue;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
}
代码解释:
- 只有当表单或者表单内的任何一个元素通过键盘导航获得焦点时,表单才会高亮显示。
第四节课:提升keyboard-only
导航体验的最佳实践
除了使用focus-visible
和focus-within
之外,还有一些其他的最佳实践可以帮助我们提升keyboard-only
导航体验。
-
合理的
tabindex
顺序确保
tabindex
的顺序与HTML结构顺序一致,避免焦点在页面上乱跳。尽量避免使用tabindex="任意正整数"
,容易造成混乱。 -
清晰的焦点指示器
使用清晰、醒目的焦点指示器,让用户能够清楚地知道当前焦点在哪里。可以使用
outline
、border
、box-shadow
等属性来创建焦点指示器。 -
避免焦点陷阱
确保用户可以通过键盘将焦点移动到页面上的每一个可交互元素,并且能够顺利地离开这些元素。避免出现焦点被困在某个区域无法移动的情况。可以使用JavaScript来监听键盘事件,并在必要时手动移动焦点。
-
语义化的HTML
使用语义化的HTML标签,比如
<button>
、<input>
、<a>
等等。这些标签默认就具有可访问性,可以减少我们的工作量。 -
使用ARIA属性
ARIA(Accessible Rich Internet Applications)是一组用于增强Web内容可访问性的属性。可以使用ARIA属性来描述元素的角色、状态和属性,帮助屏幕阅读器更好地理解页面内容。
表格总结:focus-visible
vs focus-within
特性 | focus-visible |
focus-within |
---|---|---|
触发条件 | 元素通过键盘导航获得焦点 | 元素自身或其后代元素获得焦点 |
应用对象 | 获得焦点的元素 | 元素自身 |
主要用途 | 区分键盘导航和鼠标操作,提供不同的焦点样式 | 高亮显示包含焦点的容器,用于表单、菜单等组件 |
兼容性 | 较差,需要polyfill | 良好 |
结束语:人人为我,我为人人
提升keyboard-only
导航体验,不仅仅是为了那些使用键盘导航的用户,也是为了我们自己的网站。一个可访问性良好的网站,能够吸引更多的用户,提升用户满意度,最终带来商业价值。
记住,Web开发不仅仅是让网站看起来漂亮,更重要的是让每个人都能够轻松地使用它。让我们一起努力,打造一个更加美好的互联网世界!
好了,今天的讲座就到这里。希望大家有所收获,下次再见!