:first-child 选不到第一个 li 是因父元素首个子节点非 li,可能是注释、空格或 Fragment;应检查 DOM 结构,或改用 :first-of-type(IE9+),但注意其不支持类名组合。

first-child 选不到第一个 li?检查父容器和元素类型是否匹配
很多人写 ul li:first-child { color: red; } 没效果,不是 CSS 写错了,而是 HTML 结构里 ul 下面可能有注释、文本节点或换行空格——这些都会被浏览器当成“第一个子节点”,导致真正的 li 不再是 :first-child。
真正起作用的前提是:目标元素必须是其父元素的**第一个子元素**,且类型要对得上选择器。
- ✅ 正确结构:
<ul> <li>首页</li> <li>关于</li> </ul>→li:first-child可命中 - ❌ 常见干扰:
<ul> <!-- 导航 --><li>首页</li> </ul>→ 注释是第一个子节点,li是第二个,:first-child失效 - ⚠️ 注意空白:模板引擎(如 Vue、Jinja)或 Prettier 格式化后,
<ul>\n <li> </ul>中的换行符会被解析为文本节点,也可能破坏匹配
用 :first-of-type 替代时要注意标签语义是否一致
如果父容器里混着多种标签(比如 div、p、li),而你只想选第一个 li,:first-child 就不可靠。这时候 :first-of-type 更稳,但它只认标签名,不认类名或属性。
- ✅
ul li:first-of-type会选中ul下第一个出现的li,不管前面有没有div或注释 - ❌
li.special:first-of-type不生效——伪类不能和类名组合来限定“某种类型的第一个”,它只对原生标签有效 - ⚠️ 兼容性:IE9+ 支持
:first-of-type,但 IE8 及以下完全不支持,如果还要兼容老系统,得用 class 手动标记
在 Flex/Grid 布局里 :first-child 依然按 DOM 顺序生效
Flex 和 Grid 改变的是渲染顺序,不是 DOM 顺序。:first-child 始终依据 HTML 源码里的位置,和 order 属性或 grid-template-areas 无关。
立即学习“前端免费学习笔记(深入)”;
- ✅ 即使你用
order: -1把第二个li推到最前,li:first-child还是匹配第一个写在 HTML 里的那个 - ⚠️ 如果真想按视觉首项加样式,得换思路:要么 JS 动态加 class,要么用
:nth-child(1)配合明确的结构假设(风险高) - ? 小技巧:用
flex-direction: row-reverse后,:first-child仍然选源码第一个,但视觉上它跑最后去了——别指望它“跟着布局走”
React/Vue 里动态列表首项样式失效?小心 key 和 Fragment 干扰
框架组件中,:first-child 容易因为虚拟 DOM 的包裹逻辑失效。比如用了 Fragment,或者外层加了 div 包装器,实际渲染出的父容器就不是你写的那个 ul 了。
- ✅ 在 React 中,确保样式作用的目标父元素就是你写的那个 JSX 标签,而不是被
Fragment或 HOC 包了一层 - ❌ Vue 的
<template v-for></template>默认不产生真实父节点,如果外层没包ul,那li的父级其实是DocumentFragment,:first-child无从谈起 - ⚠️ key 错误也可能导致重排后首项 class 残留——这不是 CSS 问题,但现象类似,得结合 React DevTools 看真实 DOM 结构
CSS 的 :first-child 看似简单,但真正卡住人的地方永远在“谁才是父元素的第一个孩子”这个判断上。DOM 树比想象中更敏感,空格、注释、Fragment、JSX 包裹,都可能悄悄改变它的行为。动手前先用浏览器开发者工具的 Elements 面板点开父节点,数一数子节点,比查文档更快。










