直接结论:用 li:not(:first-child):not(:last-child) 一行就能同时排除首尾,语义清晰、行为确定、ie9+ 全支持;但需确保 dom 结构干净,否则文本节点或混排元素会导致匹配失效。

直接结论:用 li:not(:first-child):not(:last-child) 一行就能同时排除首尾,比链式写法或多次否定更可靠;但必须注意 DOM 结构是否“干净”,混排或存在文本节点时会失效。
为什么不用 :nth-child(n+2):nth-last-child(n+2)?
这个组合看似能避开首尾,实际是陷阱:它匹配的是“从第 2 个开始,且倒数位置 ≥ 2”的元素,也就是中间段。但一旦列表只有 2 项,n+2 就无匹配项;只有 1 项时更全不命中。它本质是“取中间”,不是“排除首尾”。
-
:not(:first-child):not(:last-child)是 AND 逻辑,只要不是第一个且不是最后一个,就命中——语义清晰、行为确定 - IE9+ 全支持,无需降级;而
:nth-last-child在 IE8 完全不可用 - 若父容器末尾有注释或空格文本节点,
:last-child会选中那个节点,导致:not(:last-child)错误放行最后一个li——此时应改用:not(:last-of-type)
:not(:first-child):not(:last-child) 的真实使用场景
常见于卡片栅格、标签页、导航项等需要“首尾对齐、中间留白”的布局。例如:
nav a:not(:first-child):not(:last-child) {
margin-inline: 1rem;
}
这里 margin-inline 同时控制左右间距,首尾 a 不受干扰,自然贴边。但要注意:
- 如果
nav里穿插了span或注释,:first-child可能指向那个非a元素,导致第一个a被错误排除——此时应确保结构纯净,或改用a:nth-of-type(n+2):nth-of-type(-n+2)(不推荐,复杂且易错) - Flex 或 Grid 容器中,伪类仍按 DOM 顺序匹配,不受
order或grid-row影响 - 不要试图用它处理“视觉上第一个但 DOM 中靠后”的情况——CSS 伪类不读取渲染结果,只读 DOM 树
混排结构下怎么安全排除首尾?
当父容器内不止一种标签(如 article 里有 p、h2、blockquote),又只想给 p 排除首尾边距,就得换判断依据:
- 用
p:not(:first-of-type):not(:last-of-type)——它只看同为p的兄弟,无视中间的h2或div -
:first-of-type和:last-of-type在 IE9+ 支持,但 IE8 不支持;若需兼容,只能加 class 或 JS 动态标记 - 注意:
:first-of-type不等于“第一个出现的p”——如果第一个子元素是h2,第二个是p,那这个p就是:first-of-type
真正容易被忽略的是:伪类选择器的匹配发生在样式计算阶段,完全不感知 layout、paint 或用户交互。你写的 :not(:first-child) 永远不会因为某个元素被 display: none 就重新计算“谁是第一个”——它只数原始 DOM 子节点。所以动态增删元素后,必须靠浏览器重排触发更新,不能指望 CSS 自动“重数”。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











