最直接方案是用 :first-child 和 :last-child 精准去除首项上边框、末项下边框;若存在注释/文本节点或类型混杂,应改用 :first-of-type/:last-of-type;flex/grid 视觉顺序错位时需手动加 class 或 js 处理。

用 :first-child 和 :last-child 去掉首尾分割线
父容器里每个子项之间加了 border-bottom,但首项不该有上边框、末项不该有下边框——最直接的办法就是让父级“告诉”首尾子项:你不用画那条线。
关键不是改子项样式,而是用伪类精准定位。注意::first-child 和 :last-child 匹配的是 DOM 顺序上的第一个/最后一个子元素,不是 CSS 渲染顺序,也不是“第几个 div”这种语义。
- 如果父容器第一个子节点是注释或文本节点,
:first-child就不会命中你的目标元素 - 如果末尾有空格、换行符生成的
Text节点,:last-child可能失效 - 确保目标子元素确实是父容器的直接子节点(不是嵌套在其他标签里)
.list > li {
border-bottom: 1px solid #ccc;
}
.list > li:first-child {
border-top: none;
}
.list > li:last-child {
border-bottom: none;
}
当子项类型不统一时,改用 :first-of-type / :last-of-type
如果父容器里混着 <li>、<p></p>、<div>,而你只想控制其中某类元素的首尾边框,<code>:first-child 就不可靠了——它只看位置,不管标签名。
:first-of-type 和 :last-of-type 是按元素类型分别计数的,更适合这类混合结构。
- 它们对 HTML 注释、空格文本完全免疫,比
*-child更稳定 - 但要注意:如果目标元素前面还有同类型元素(比如两个
<div> 连着),第一个 <code><div> 才是 <code>:first-of-type - IE8 不支持
:first-of-type,如需兼容得用 JS 或额外 class
.card-group > div {
border-bottom: 1px solid #eee;
}
.card-group > div:first-of-type {
border-top: none;
}
.card-group > div:last-of-type {
border-bottom: none;
}
Flex/Grid 布局下,:last-child 可能失效
Flex 或 Grid 容器中,子项的视觉顺序可能和 DOM 顺序不一致(比如用了 order 或 grid-template-areas),这时 :last-child 仍按原始 DOM 判断,不是按屏幕上看到的“最后一个”。
这种情况下,不能依赖伪类自动识别“视觉末尾”,得手动加 class 或用 JS 动态标记。
- Flex 中
order改变排列后,:last-child还是指 HTML 最后一个子节点 - Grid 中
grid-column跨列、重叠布局也会导致视觉与 DOM 错位 - 没有纯 CSS 方案能动态响应视觉顺序变化,这是 CSS 伪类的固有限制
用相邻兄弟选择器(+)替代部分场景
如果只是想避免“重复边框”,比如每项之间需要间隔线,但不想写两遍规则,可以用 + 选择器从第二项开始画线。
这种方式绕开了首尾判断,逻辑更简单,也天然规避了伪类匹配失败的问题。
- 适用于所有子项结构一致、无插入干扰节点的列表
- 比
:first-child兼容性更好(支持 IE7+) - 但如果第一项需要特殊顶部样式(比如阴影),还得单独处理,不能只靠这个
.item {
/* 不设边框 */
}
.item + .item {
border-top: 1px solid #ddd;
}
CSS 里没有“视觉上的第一个/最后一个”这个概念,所有伪类都基于 DOM 树。真要响应动态排序或条件渲染,得靠 JS 补位,或者设计时就预留 class 控制点。











