:focus-within 能用于表格行是因为其子元素获焦时父元素自动匹配,前提是单元格内含可聚焦元素(如input、button)或tabindex="0"容器,且未被display:none等隐藏;需注意兼容性与样式冲突。

focus-within 为什么能用在表格行上
因为 :focus-within 是 CSS 原生伪类,只要元素内部任意子元素获得焦点(比如 <input>、<button></button>、<a href></a>),它自身就会匹配。表格行(<tr>)本身不能聚焦,但它的单元格里放可聚焦元素后,<code>tr:focus-within 就能生效——这是关键前提,不是“给 tr 加 tabindex”那种取巧方式。
常见错误是直接写 tr:focus-within { background: #eef }; 却没效果,原因通常是:单元格里没有可聚焦的子元素,或者用了 display: none / visibility: hidden 隐藏了它们,导致浏览器认为“无聚焦可能”,跳过匹配。
怎么写才真正生效
必须确保 <td> 或 <code><th> 内有默认可聚焦的元素(如 <code><input>、<button></button>),或显式加 tabindex="0" 的容器。样式要作用于 <tr>,且不能被更具体的规则覆盖。
<ul>
<li>推荐写法:<pre class="brush:php;toolbar:false;">tr:focus-within { background-color: #f8f9fa; }</pre>
</li>
<li>避免写成 <code>tbody tr:focus-within —— 层级过深容易被其他 CSS 覆盖,直接 tr:focus-within 更稳
border-collapse: collapse,记得给 tr 设 background-color 而非 td,否则背景会断开:focus-within 支持较晚(iOS 15.4+),旧版本会完全不触发,需 fallback(见下一条)兼容性兜底方案怎么做
当目标环境包含 iOS :focus-within 不工作。不能只靠 JS 模拟 focus/blur,因为键盘导航(Tab)和屏幕阅读器行为难复现。更可行的是用 JS 监听子元素聚焦事件,动态加 class:
document.querySelectorAll('tr').forEach(row => {
row.addEventListener('focusin', () => row.classList.add('focused'));
row.addEventListener('focusout', () => row.classList.remove('focused'));
});
注意点:
-
focusin冒泡,所以监听tr就能捕获内部所有聚焦;focusout同理 - 别用
focus/blur——它们不冒泡,得给每个子元素单独绑 - 如果表格内容动态渲染,要用事件委托,监听
table的focusin - CSS 中同时写
tr:focus-within, tr.focused,保证两种路径样式一致
容易被忽略的细节
视觉反馈不是加个背景色就完事。用户实际操作中,常遇到这些隐形问题:
- 焦点样式和 hover 样式冲突:如果
tr:hover和tr:focus-within都设背景,鼠标悬停再点击输入框,hover 会覆盖 focus-within,建议用tr:hover:not(:focus-within)分离逻辑 - 高对比度模式下背景色可能失效,应配合边框或 outline(如
outline: 2px solid #0066cc)增强可见性 - 如果某行有多个可聚焦元素(比如两个
<input>),切换焦点时focusout → focusin间隙会导致背景闪一下,可用transition: background-color 0.1s缓解 - 辅助技术(如 VoiceOver)依赖真实焦点流,JS 添加的 class 不影响焦点顺序,这点比纯 CSS 更安全
真正麻烦的不是写出来,而是验证它在键盘 Tab、屏幕阅读器、触屏双击、外接键盘各种路径下都一致响应。别跳过这步。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











