:not(:first-of-type)是最稳妥的通用方案,它基于同类型兄弟元素的位置匹配,不依赖DOM绝对位置,兼容性上IE9–11不支持,需用JS或class降级。

用 :not(:first-of-type) 排除第一个元素
直接上解法::not(:first-of-type) 是最稳妥的通用方案。它不依赖父容器里有没有其他类型元素,只看当前元素在同类型兄弟中的位置。
常见错误是写成 :not(:first-child) —— 这个只认“是不是父元素的第一个子节点”,哪怕前面是个 <p> 或注释节点,后面第一个 <div> 就会被误判为 :first-child,导致样式没生效。
使用场景:比如给所有 <li> 加顶边框,但第一个不想加;或者给连续的 <section> 加分隔线,首节除外。
-
:first-of-type看的是标签名 + 在同类型兄弟中的顺序,更符合直觉 -
:first-child看的是 DOM 树里的绝对位置,容易被干扰 - 如果目标元素是动态插入的,
:first-of-type仍能稳定工作;:first-child可能因插入位置变化而失效
伪类组合时注意选择器权重和顺序
写 li:not(:first-of-type) { border-top: 1px solid #ccc; } 没问题,但如果你还写了 li:first-of-type { border-top: none; },就得小心覆盖逻辑。
立即学习“前端免费学习笔记(深入)”;
这两个规则权重相同,后写的会覆盖前写的。但更关键的是:如果后续加了更具体的选择器(比如 .nav-list li:not(:first-of-type)),它会比纯标签选择器优先级高,可能让原本想排除的样式又回来了。
- 优先用单个
:not(:first-of-type)规则,别拆成两个对立规则 - 避免混用
:first-of-type和:nth-of-type(1)—— 它们等价,但混用容易自己绕晕 - 如果父容器有内联样式或 JS 动态加 class,记得检查是否意外提高了某条规则的权重
IE 不支持 :first-of-type,得换方案
IE8 及以下完全不认 :first-of-type 和 :not(),连带整个 :not(:first-of-type) 失效。不是“部分失效”,是整条 CSS 规则被浏览器忽略。
如果必须兼容 IE8,只能退回到 JS 控制,或用 class 手动标记:
li { border-top: 1px solid #ccc; }
li.first { border-top: none; }
然后靠 HTML 写死 <li class="first">,或用脚本加 class。现代项目基本不用管,但老系统维护时容易在这儿卡住。
- Can I Use 数据显示,
:first-of-type在 IE9+ 支持,:not()在 IE9+ 仅支持单参数(:not(.cls)可以,:not(:first-of-type)在 IE9–11 不支持) - 所以严格兼容 IE9–11 的话,
:not(:first-of-type)依然不可靠,得用 JS 或服务端渲染 class - PostCSS 的
autoprefixer不会帮你转译这类伪类,它只处理属性前缀
flex / grid 容器中 :first-of-type 依然有效
有人担心用了 display: flex 或 grid 后,DOM 顺序和视觉顺序不一致,:first-of-type 会不会跟着“错乱”?不会。
这个伪类永远基于源码中的 DOM 结构,跟 CSS 布局无关。就算你用 order: -1 把第二个 <div> 挪到最前,:first-of-type 还是指源码里第一个同类型元素。
- 视觉顺序 ≠ 选择器匹配顺序,这点必须分清
- 如果真要按视觉顺序选“第一个显示的”,只能靠 JS 获取
getBoundingClientRect()或监听 layout 变化 - Grid 中用
grid-template-areas重排区域,也不影响:first-of-type匹配结果
:not() 嵌套伪类的支持程度——尤其在需要兼容稍老版本 Edge 或安卓 WebView 时,:not(:first-of-type) 看似简洁,却可能静默失效。










