:first-child和:last-child不能直接连写以匹配唯一子元素,仅当该元素是父容器的唯一子元素时才生效;选某类型首个/末个实例须用:first-of-type/:last-of-type。

伪类组合时:first-child和:last-child不能直接连写
很多人尝试写 :first-child:last-child 想匹配“既是第一个又是最后一个”的唯一子元素,语法上合法,但实际效果受限于 DOM 结构——只有当该元素**恰好是父容器的唯一子元素**时才生效。更常见的情况是想选中某个特定类型元素的第一个/最后一个实例,比如“第一个 ”或“最后一个 ”,这时必须用类型选择器前置,不能只靠伪类堆叠。
选中某类型元素的第一个或最后一个实例要加标签名或类名
浏览器不支持 p:first-child 这种写法去匹配“第一个 p 元素”,因为 :first-child 只判断它是不是父元素的**第一个子节点**,不管类型。正确方式是用 :first-of-type 和 :last-of-type:
p:first-of-type {
color: red;
}
li:last-of-type {
font-weight: bold;
}如果必须用 :first-child,得确保目标元素确实是父元素的第一个子节点,例如:
.container > p:first-child {
margin-top: 0;
}这只有在 p 紧跟在 .container 开始标签后(前面无其他子元素)时才生效。
立即学习“前端免费学习笔记(深入)”;
嵌套结构中避免误用组合顺序导致选择失败
伪类的位置很关键。下面这些写法含义完全不同:
-
ul li:first-child:选中每个ul下的**第一个li子元素**(常见且安全) -
ul:first-child li:选中那些自身是其父元素**第一个子元素的ul** 里面的全部li -
ul > li:first-child:和第一条等价,但限定为直接子元素,排除嵌套li -
li:first-child:hover:仅当该li是第一个子元素时才响应 hover
容易踩的坑是把伪类放在复合选择器中间,比如 nav ul:first-child li,这其实是在找“nav 下第一个 ul 的所有 li”,而不是“nav 下每个 ul 的第一个 li”。
兼容性与性能差异:优先用 :first-of-type 而非模拟方案
有人用 :not(:first-child) 或兄弟选择器 + :nth-child 模拟“第一个某类型”,比如:
li:not(li ~ li) { /* 试图选第一个 li */ }这种写法既难读又低效,且 IE 不支持 :not() 嵌套伪类。现代项目应直接用:
li:first-of-type {
border-top: 2px solid #333;
}
li:last-of-type {
border-bottom: 2px solid #333;
}:first-of-type 和 :last-of-type 在所有主流浏览器中支持良好(IE9+),语义清晰,渲染性能也优于复杂否定组合。真正需要 :first-child 的场景,通常是做重置样式(如移除首项上边距),此时它本就依赖结构位置,而非类型。
记住:伪类不是函数调用,没有“参数”概念;它们是条件断言,作用对象始终是当前选择器匹配到的那个元素本身——所以组合逻辑全看选择器主干怎么写,而不是伪类怎么排。










