:not(:first-child)最直白,但仅适用于同类型子元素连续排列的场景;若父容器首子节点非目标类型(如后跟),则会误选所有目标元素,此时应改用:nth-of-type(n+2)或兄弟选择器。

用 :not(:first-child) 最直白,但要注意元素类型混杂时失效
这个写法看着最符合直觉:div:not(:first-child) 会选中所有 div 中「不是父元素第一个子元素」的那些。但它真正匹配的是「是 div 且不是其父元素的第一个子节点」——关键在「第一个子节点」不一定是 div。
比如父容器里是 ,那么 标题
div:first-child 根本不匹配任何元素(因为第一个子节点是 h2),div:not(:first-child) 就会把两个 div 全选中——这常被误认为“生效了”,其实是巧合。
- ✅ 适用场景:父容器内子元素类型完全一致(全是
div或全是li) - ❌ 坑点:只要第一个子元素是其他标签(如
span、p、注释、文本节点),:first-child就不指向你预期的那个div - ? 替代思路:如果目标只是排除视觉上“第一个块”,优先考虑
:nth-of-type(),它按元素类型计数,不care中间夹了啥
:nth-of-type(n+2) 是更稳的选择,尤其适合混合 DOM 结构
当父容器里有标题、说明文字、图标等杂项节点时,:nth-of-type(n+2) 才真正按「同类型元素的顺序」来算。比如你想给所有 article 之外的第二个及以后的 section 加边距,写成 section:nth-of-type(n+2) 就不会被前面的 header 或 aside 干扰。
- ✅ 它只统计同名标签(
section只数section,无视其他) - ⚠️ 注意
n从 0 开始:n+2表示第 2、3、4… 个该类型元素;2n+1是奇数位,2n是偶数位 - ❌ 不要和
:nth-child()混用:后者严格按 DOM 位置,哪怕中间插了个comment节点,序号也会偏移
用兄弟选择器 ~ 或 + 避免伪类兼容性问题
某些老项目还在支持 IE9–IE11,而 :not() 和 :nth-of-type() 在 IE9+ 才完整支持。~(通用兄弟)和 +(相邻兄弟)则从 IE7 就能用,且语义清晰:「后面出现的同级元素」。
例如:.item + .item 表示「紧接在另一个 .item 后面的 .item」,天然跳过第一个;.item ~ .item 则选中第一个之后所有同级 .item。
- ✅ 兼容性好,逻辑简单,无计算开销
- ⚠️
+只能选紧邻下一个,~才能覆盖全部后续兄弟 - ? 实际常用写法:
.list-item ~ .list-item { margin-top: 1rem; }—— 给列表第二项起统一加顶距,第一项自动零间距
动态内容下 :first-child 可能“失焦”,得靠 JS fallback 或结构约束
前端常遇到「初始渲染只有 1 个 item,后来异步插入更多」的情况。此时若用 :first-child 控制样式,新插入的元素可能因 DOM 插入位置不同(比如用 appendChild 还是 insertBefore)导致首个元素判定漂移。
更麻烦的是服务端渲染 + 客户端水合(hydration)时,如果 SSR 输出的 HTML 和客户端 JS 构建的 DOM 树不一致,:first-child 匹配结果可能前后端不一致,造成样式闪动。
- ✅ 稳健做法:把「第一个」的特殊样式抽成独立 class(如
is-first),由 JS 显式控制 - ⚠️ 如果必须用纯 CSS,确保父容器子节点结构可控——比如强制用
,避免混入非- ...
li的节点 - ? 小技巧:用
:only-child做兜底判断,单独处理「只剩一个子元素」的边界情况
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











