CSS修仙传:第一篇·选择器法则篇

73 阅读3分钟

《CSS修仙传:第一篇·选择器法则篇》

楔子:!important之祸

"砰!"

青云门藏经阁内,我的茶杯突然炸裂。滚烫的茶水溅在刚写好的样式表上,墨迹晕染开来。

"又用!important?!"林惊羽师姐的剑尖抵着我的喉咙,剑身上反射着控制台的红光:"第五次了!你知道这会导致什么后果吗?"

我颤抖着看向自己写的代码:

css

复制

.button {
  color: red !important;
  /* 后面300行样式 */
}
.modal .button {
  color: blue; /* 无效! */
}

第一章:选择器权重论道

1.1 权重计算的秘密

林师姐的剑尖在空中划出一道CSS规则:

css

复制

#main .list > li:hover {}

"看好了,这就是标准的'四段权重'计算法:"

选择器部分权重值计算原理
#main0100ID选择器
.list0010类/属性/伪类选择器
>0000组合器不计权重
li0001元素/伪元素选择器
:hover0010伪类
总计0111非十进制!256进制体系

"记住这个公式:"师姐的剑在空中写出金光公式:

复制

Specificity = a*256² + b*256 + c

"浏览器实际比较时会用256进制,这就是为什么11个class也打不过1个id"

1.2 伪类选择器的陷阱

正当我领悟时,藏经阁突然震动。魔教妖人用:has()伪类攻击护山大阵!

"快用:where()化解!"师姐急喝。我连忙结印:

css

复制

/* 传统写法 - 权重 0,2,0 */
div:not(.active), section:not(.active) {}

/* 高阶写法 - 权重 0,1,0 */
:where(div, section):not(.active) {}

"看好了:"师姐演示DevTools的性能分析:

复制

1000次匹配耗时:
:not()传统写法 → 12.4ms
:where()优化写法 → 8.7ms

1.3 属性选择器的正则艺术

魔教妖人祭出[data-^="btn"]攻击,师姐冷笑:"让你见识真正的属性选择器!"

css

复制

/* 精准匹配 */
[data-type="primary"] {}

/* 开头匹配 */
[data-type^="pr"] {}

/* 包含匹配 */
[data-type*="ima"] {}

/* 结尾匹配 */
[data-type$="ary"] {}

/* 空格分隔匹配 */
[data-type~="pri"] {}

/* 连字符匹配 */
[data-type|="en"] {}

"注意:"师姐突然严肃,"属性选择器在IE..."

"我知道!"我抢答,"在IE要用getAttribute()polyfill!"

第二章:Shadow DOM的破阵之法

2.1 ::part()穿透术

魔教祭出Web Component法宝,样式完全隔离。师姐咬破手指,在空中画出鲜血符咒:

css

复制

custom-element::part(inner) {
  color: red;
}

对应组件内部:

html

复制

<div part="inner">可被样式穿透</div>

运行 HTML

2.2 ::slotted()传功大法

"再看这个!"师姐剑光分化:

css

复制

::slotted(.item) {
  transform: scale(1.1);
}

"此术只能影响slot分发的内容,对组件内部无效"

第三章:@scope的结界之术

危急时刻,掌门道玄真人出手,施展CSS最新秘法:

css

复制

@scope (.card) to (.footer) {
  :scope {
    border: 1px solid;
  }
  p {
    color: #333;
  }
}

"此术可创建样式结界,避免污染全局!"

性能心诀

掌门传我四句真言:

复制

选择器右起左查
避免通配如避蛇
伪类慎用位置判
ID最快类次之

实战:重写护山大阵

最终我重写护山大阵样式:

css

复制

/* 旧式(权重 0,2,1) */
div.container ul.list > li {}

/* 新式(权重 0,1,0) */
:where([data-component="list"]:not([hidden])) > :is(li, dt) {}

/* 添加Shadow穿透 */
::part(list-item) {
  --highlight: oklch(75% 0.3 145);
}

/* 作用域隔离 */
@scope (.spell-area) {
  button { animation: glow 2s infinite; }
}

渡劫测验

  1. 计算选择器权重:#app .list > [data-index]:not(:first-child)
  2. :where()优化:header > nav, aside > nav
  3. 实现一个可穿透样式的Web Component按钮
  4. 解释为什么[class^="btn"].btn-primary性能更好

(答案见GitHub仓库:github.com/css-immorta…


下篇预告:《布局真解篇》- Flex与Grid的时空法则,contain-intrinsic-size如何破解异步加载布局抖动,subgrid如何实现完美圣杯布局...