选择器越长维护越难,因其强耦合DOM结构、高特异性导致覆盖困难;BEM通过扁平化类名解耦样式与结构,禁用后代选择器、限定属性选择器范围、用状态类替代复杂伪类,确保组件样式封闭可定位。
不是所有能生效的选择器都该被写进代码。.header .nav .menu .item a:hover 看似精准,但只要 .nav 改成 .navigation,整条链就失效;更麻烦的是,它把特异性拉到 0,0,4,1(四个类名+一个类型),后续想用 .nav-link--active 覆盖,就得加 !important 或硬凑更长链——这不是维护,是缝合。
BEM 不是语法糖,是解耦策略。它让样式不再依赖 DOM 结构,只认类名本身。
.card .card__header .card__title → 三个类名绑定三层结构.card__title → 单一类名,直接作用于元素,DOM 换了也不影响.card--featured、.input--error,不靠父容器类控制h2.card__title 比 .card__title 多一层隐式耦合,删掉> 和后代选择器空格,用错就漏样式.list li 匹配所有后代 li,包括嵌套组件里的;.list > li 只匹配直接子元素。看起来只差一个符号,实际影响范围天壤之别。
>,除非你明确需要穿透多层(比如统一设置全站 a 链接颜色).card > .card__body > p,而不是 .card p,否则第三方组件的 p 会被意外染色[type="submit"] 本身没问题,但一旦混进 div#main section.article ul li a[href^="/blog"]:hover 这种链,特异性直接爆表,调试时根本找不到谁在覆盖你。
立即学习“前端免费学习笔记(深入)”;
button[type="submit"] 比 input[type="submit"] 更准,也比 [type="submit"] 权重低、更安全.is-active、.has-error 写在 HTML 上,别用 :not(:disabled) 这类复杂逻辑拼选择器:nth-child() 依赖 DOM 顺序,结构一动就废;改用 :nth-of-type() 或直接加类名控制card 和 title 的选择器。