网页焦点说丢就丢,键盘侠咋办?,:focus-visible拯救盲操体验

2,699字
11–17 分钟
in

好多网站一点击按钮,那个蓝色的焦点环就神秘消失,键盘党直接原地破防。这玩意儿叫“焦点指示器”,没了它,用Tab键切选项就像摸黑走夜路。其实浏览器自带一个智能开关——:focus-visible,能自动判断啥时候该亮起那圈“防走丢光环”。下面直接开干,从零配好这个伪类,让鼠标党和键盘侠都顺滑操作,不吵不闹。

目录

焦点环咋就没了

早年间网页开发者觉得浏览器默认那圈蓝框太丑,一激动就用outline:0outline:none给它干掉了。这一刀下去,鼠标点着爽了,可键盘切焦点的兄弟姐妹直接抓瞎——看不到当前怼到哪个按钮上。浏览器原本对<a><button><input>这些天生自带焦点样式的元素,被强行卸了妆。更要命的是,很多人删完不补任何替代样式,导致网页成了键盘导航的“百慕大三角”。

/* 这种写法直接让键盘党崩溃 */
:focus {
  outline: 0;
}

那如果真得改样式咋整?比如公司设计死活不要那个默认圈圈。这时候不能硬刚,得用品牌色做个高对比的焦点效果,同时保证颜色反差够大(WCAG 2.2非文字对比度至少3:1)。像下面这样既保住了颜值,又没丢掉功能:

:focus {
  outline: 2px solid #ff6600;
  outline-offset: 2px;
}

:focus-visible是个啥

:focus-visible是个伪类,它不跟:focus抢C位,而是当浏览器觉得“这波需要给焦点提示”时才触发。比方说用Tab键切到按钮,它就亮;用鼠标直接点击,它就不亮,免得满屏都是圈圈晃眼。写法贼简单:

:focus-visible {
  outline: 3px dashed #0a58ca;
  background-color: #e9ecef;
}

也可以只针对特定元素,比如表单输入框:

input:focus-visible {
  border-color: #0d6efd;
  box-shadow: 0 0 0 3px rgba(13,110,253,0.25);
}

智能判断的骚操作

浏览器内建一套“启发式规则”,能嗅探当前输入设备。敲键盘时,几乎所有可聚焦元素(按钮、链接、表单项)都自动戴上焦点环;摸鼠标或触屏时,只给文本框这类需要打字的地方加高亮,普通按钮则安静如鸡。这套逻辑像有个隐形小管家,看人下菜碟。

手把手配焦点样式

方案一:纯:focus-visible替换默认圈

目标:干掉原生outline但保留键盘时的醒目提示。

操作步骤

  1. 打开项目的CSS文件,找到全局样式区。
  2. 先写:focus把默认outline干掉(但记住这只是为了自定义,后面必须补:focus-visible)。
  3. :focus-visible定义想要的新样式——加粗边框、变背景色、放大字号都行。
  4. 保存文件,刷新页面后分别用鼠标和Tab键测试。鼠标点按钮不应该有特殊圈,按Tab键切到同一按钮时必须出现自定义圈。
/* 先取消默认的,但不完全删除焦点功能 */
:focus {
  outline: 0;
}

/* 键盘操作时闪亮登场 */
:focus-visible {
  outline: 2px solid #f0ad4e;
  outline-offset: 4px;
  background-color: #fff3cd;
}

注意:上面:focusoutline:0仅当马上配了:focus-visible才安全。如果整个项目里只有一个:focus而没有后手,那键盘党直接哭晕。实际操作中更推荐不删:focus,而是直接写:focus-visible覆盖,让不支持新特性的浏览器降级用原生圈。

方案二:带降级回退的稳妥写法

目标:兼容老浏览器,没:focus-visible时也不翻车。

操作步骤

  1. 先写基础按钮样式,给个默认:focus作为保底(比如浅色外发光)。
  2. 再用:focus-visible覆盖成更酷的视觉效果。
  3. 套上@supports查询,检测浏览器是否认识:focus-visible
  4. 在不支持的浏览器里,手动给.with-fallback类的元素重新启用焦点样式。
/* 保底样式:任何焦点都有反应 */
button:focus {
  outline: 2px solid #6c757d;
}

/* 新浏览器里键盘焦点更风骚 */
button:focus-visible {
  outline: 3px solid #dc3545;
  outline-offset: 3px;
  transform: scale(1.02);
}

/* 查询特性支持度 */
@supports not selector(:focus-visible) {
  button.with-fallback:focus {
    outline: 3px solid #198754;
    background-color: #d1e7dd;
  }
}

注意@supports not selector(:focus-visible)这段检测如果浏览器不认识这个伪类,就会执行花括号里的样式。但里面千万别再用:focus-visible,否则无限套娃。另外not selector写法在某些老旧Safari上可能报错,更稳健的写法是分开两个@supports,一个处理支持,一个处理不支持。

实测多设备翻车点

拿一台Windows笔记本+外接机械键盘,分别测Chrome、Firefox、Edge。用Tab走一遍页面所有可点元素,观察焦点环是否清晰可见。再用触控板点一下空白区域,然后继续按Tab,焦点应该从上次停留的地方继续跑,而不是跳回顶部。手机上没法按Tab,但连接蓝牙键盘后同样适用——:focus-visible在iOS Safari 15.4+和安卓Chrome里都支棱起来了。

浏览器桌面支持移动支持
Chrome86+146+
Firefox4*149
Edge86+146+
Safari15.4+15.4+

(*Firefox 4到84之间通过:-moz-focusring实现类似效果)

配色翻车案例与急救

选焦点色时千万别整活——浅灰配白底等于没配。假设品牌主色是#b3e0ff(淡蓝),直接拿来做轮廓线,在白背景上对比度可能只有1.5:1,眼神不好的小伙伴根本看不见。急救法:用深蓝#0056b3做外圈,或者给焦点元素加个深色阴影。下面这段代码救了一整个项目:

:focus-visible {
  outline: 2px solid #005cbf;
  outline-offset: 2px;
  /* 再加一层外发光增加存在感 */
  box-shadow: 0 0 0 4px rgba(0,92,191,0.3);
}

另外保持所有交互元素焦点样式统一,别让按钮一个样、链接另一个样、输入框又变样,否则键切时脑壳疼。就像楼道里的应急灯,每层都得是同款亮度和颜色。