ul > li不生效的最常见原因是dom结构“被插队”,如li实际是div的子元素而非ul的直接子元素,或框架/模板插入了中间层、文本节点;>只匹配父元素的直接子元素,无视文本节点和嵌套层级。

> 只认「第一层」,不是直接子节点,再怎么写样式也白搭。
为什么 ul > li 有时完全不生效
最常见原因是 DOM 结构“被插队”了。比如你写的 HTML 是 <ul><div><li>item</li></div></ul>,那 li 实际上是 div 的子元素,ul 的孙子元素——ul > li 就匹配不到。
- React/Vue 等框架常自动包裹一层
<div> 或 <code><span></span>,导致原本的父子关系断裂 - 服务端模板(如 Django、Thymeleaf)也可能插入空格、注释或文本节点,而
>完全无视文本节点,只认元素节点 - 用浏览器 Elements 面板看缩进:如果
li比ul多两级缩进,就不是直接子元素 - 空格选择器是深度优先,穿透任意层级
-
>是宽度优先,只扫父元素的 immediate children 列表(即parent.children) - 性能上没差别,但语义强得多:
>明确告诉你“这里不该有中间层” - 写
.card > h2能确保只改卡片顶层标题,不会误中.card > .content > article > h2 -
form > input可以排除所有嵌套在fieldset或div里的input,适合统一重置直系控件样式 - 搭配
:scope使用更灵活::scope > [data-role="item"]在 JS 动态插入后仍可靠 - 在控制台运行
document.querySelector('ul > li'),返回null就说明结构不对,不是选择器写错 - 用
document.querySelector('ul').children看实际子节点列表,确认里面有没有li - 注意:
children只返回元素节点,childNodes还包含文本和注释——这也解释了为什么有时明明看着“挨着”,>却不生效
> 和空格(后代选择器)到底差在哪
区别不在“有没有嵌套”,而在“嵌套了几层”。nav a(空格)会命中 <nav><section><a></a></section></nav> 里的 a;但 nav > a 只会匹配 <nav><a></a></nav> 这种扁平结构。
哪些场景非用 > 不可
当你要隔离样式作用域,避免意外污染深层结构时,> 是唯一干净解法。比如菜单项、表单控件组、卡片标题区。
调试时别只盯 CSS,先查 DOM 树真实结构
很多人反复改 css 却忽略一个事实:浏览器渲染的是最终 DOM,不是你写的源码。框架、polyfill、甚至某些 CMS 都可能重写结构。
真正难的不是记住 > 的语法,而是每次写之前都得问一句:这个元素,在当前页面的 DOM 树里,是不是真的站在父元素正下方那一行?











