全局选择器*会污染所有元素的背景和盒模型,导致段落文字“嵌入”导航栏;宽泛标签选择器如ul li a匹配过广易误伤;scoped环境下属性选择器易因大小写或注入失败失灵;BEM本质是样式责任边界协议,确保模块隔离与精准定位。

全局选择器 * 会悄悄污染所有元素的背景和盒模型
最典型的后果是:段落文字看起来“嵌在导航栏里”,其实只是因为 * 给所有元素(包括 p、div、span)都套上了和导航栏一样的 background: #30302F。浏览器没出错,是你看错了——它只是忠实地执行了那条“所有元素统一背景”的指令。
-
*匹配的是 DOM 中每一个节点,哪怕是一个空的或内联图标,也会被重置margin、padding、background -
box-sizing: border-box这类“安全”属性加在*上看似无害,但一旦和其他库(如第三方组件、富文本编辑器)混用,就可能让它们的内部尺寸计算逻辑失效 - 真正危险的是“顺手加上的”全局样式,比如
button { appearance: none; }—— 它会干掉所有原生按钮的平台默认样式,包括系统对话框里的确认按钮
宽泛标签选择器(如 ul li a)不是写得少,而是匹配得太广
你以为只改了导航栏链接?其实只要页面里存在任意一个 ul > li > a 结构(比如评论列表、侧边栏菜单、甚至 Markdown 渲染出的目录),全都会被拉进样式作用域。这不是“复用”,是“误伤”。
- 浏览器从右往左匹配:先找所有
a,再逐个往上查父级是否为li→ul,DOM 越大,性能越差 - 结构一变就失效:把
ul换成nav,样式立刻丢失;而你根本没在 HTML 里改过 class - 特异性(specificity)高得离谱:
.header ul li a权重是 1-0-3-1,后期想覆盖它,要么加!important,要么写更长的选择器,陷入恶性循环
伪类和属性选择器在局部作用域中容易“失灵”
在 Vue 的 或 React 的 CSS Modules 里,[data-status="active"] 这种写法看着没问题,但构建工具通常只给 class 加哈希后缀,不会转义属性值。结果就是:HTML 里写的是 data-status="ACTIVE"(大小写不一致),CSS 里写的却是 [data-status="active"],完全不匹配。
-
:hover、:focus-within在 scoped 环境下能正常工作,但若嵌套在深层结构中(如.card .content p:hover),构建工具可能无法正确注入 scope 属性,导致悬停效果出现在不该出现的地方 - 推荐用类名代替状态:把
[data-status="active"]改成.item--active,既语义清晰,又确保构建时能被完整哈希化 - 避免在动画关键帧里用
:checked控制display或height—— 这类布局属性触发回流,且每次点击都重新计算整个选择器链
BEM 不是命名规范,而是样式责任边界协议
写 product-card__title 不是为了“好看”,是为了让这个样式只属于 product-card 模块。哪怕页面里有十个 h2 标题,只要没加 product-card__ 前缀,就绝对碰不到它。
立即学习“前端免费学习笔记(深入)”;
- 模块名(Block)是隔离单位:
header-nav和footer-nav是两个独立世界,互不干扰 - 元素名(Element)必须依附于 Block:
header-nav__logo合法,__logo单独出现就是错误 - 修饰符(Modifier)只表达状态变化:
button--primary和button--disabled是同一类按钮的不同形态,不是新组件
最容易被忽略的一点:BEM 的价值不在“写的时候多敲几个字符”,而在“改的时候不用翻三页 CSS 找冲突源”。当一个样式 bug 出现在生产环境,你能直接根据 class 名定位到唯一文件、唯一区块——这才是它真正省下的时间。










