CSS 选择器

238 阅读9分钟

本文摘录于《css 选择器世界》。
选择器的相关内容并不多,在逻辑关联性和历史发展上也不像 js 能有很多扩展。在这有限的条件下还能写出一本书,的确得佩服作者的水平。
除前端开发都基本能掌握的知识点进行了必要的陈述,此书对伪类做较多扩展,并对各选择器的使用技巧和浏览器兼容性做详细描述,在 css 应用与 js 中的差异,用兼容性反推测用户浏览器 ( - _ - |||

最佳设计实践

最佳设计实践本书最干的部分,也是工作中最应该重视的部分。( 再往后的的内容都是查缺漏的基础内容 )

  1. 避免使用 ID 选择器
    ID 选择器的优先级太高,与 js 耦合,不利于维护。

  2. 避免过多嵌套
    嵌套过多导致渲染性能下降,每一层嵌套都导致浏览器多一层计算。
    优先级混乱,尽可能的通过命名与设计保持选择器的低优先级。
    样式布局脆弱,与 html 的结构高度的耦合。

    .nav a {
    }
    .nav a img {
    } /** 不建议 **/
    .nav-a {
    }
    .nav-a-img {
    } /** 建议 **/
    
  3. 注意选择器的命名
    选择器命名全小写,组合命名可以用 -_ ,不建议使用驼峰命名
    要注意避免选择器命名过长。
    避免使用拼音命名。
    添加合适的前缀。

    .header {
    } /** 不建议 **/
    .cs-header {
    } /** 建议 **/
    .cs-module-section {
    } /** 根据标签 **/
    .hide {
      display: none;
    } /** 根据语义 **/
    .ml20 {
      margin-left: 20px;
    } /** 根据属性 **/
    .cs-radio {
    } /** 根据标签属性 **/
    
  4. 善用伪类和 html 中的布尔值
    如: .activedisabledchecked等。

  5. 项目中选择器分布依据情况使用

规模项目规模项目(含外部引用)微小项目
网站级变量?
css rest/通用结构?
模块/业务样式?
样式库×

选择器命名合法性

  1. 大小写区分:
选择器类型是否敏感
标签选择器不敏感
属性选择器对属性不敏感,属性值敏感
类选择器敏感
ID 选择器敏感

简而言之,对标签名与属性这些在 html 中对大小写不敏感的数据所对应的选择器也不敏感,对于属性值、类名、ID 值这些区分大小写的值属性数据所对应的选择器也敏感。
此外属性选择器支持属性值大小写也不敏感:

[CLASS~='COTNET' i] {
} /** 添加小写 i 即可令属性值的大小写不敏感 **/
  1. 支持以数字为开头,但在 css 中必须以使用转义符:
.1-foo {
} /** 不支持 **/
.\31-foo {
} /** 支持 **/
  1. 支持不合法的ASCII字符,同样需要转义。
  2. 支持中文字符。
  3. 支持 emoji 表情。

选择器的作用域

  1. 全局作用域
  2. :scpoe (昙花一现的标准,现已弃用)
  3. Shadow DOM
var el = doucment.getElementById('el');
var shadow = el.attachShadow({ mode: 'open' });
shadow.innerHTML = '<p>Shadow DOM</p>';
shadow.innerHTML += '<style>p{color:#fff}</style>';

选择器的命名空间

@namespace url(http:www.w3.org/1999/xhtml);
@namespace svg url(http:www.w3.org/2000/svg);

/* xhtml 的命名空间 */
a {
}
/* svg 的命名空间 */
svg|a {
}

选择器命名空间的兼容性非常好,但却很少用,主要原因在于直接用 css 的嵌套也可以解决命名冲突的问题。而命名空间则提高了该选择器的优先级。

选择器的优先级

级别权重值css/选择器
00通配符 * 、组合连接符( +>~ 等) 、逻辑组合伪类( :is():not():where() 等)
11标签选择器
210类选择器、 属性选择器 、伪类选择器
3100ID 选择器
4-内联样式
5-!important 关键字

组合选择器的权重值即为所有单一选择器权重之和,权重值越高则优先级越高。
但权重值的数字和计算方法仅是业内广为流传的说法而并不是绝对的。也即为 11 个标签选择器无法越级 1 个类选择器的权重。

组合连接符

  1. 后代选择器 ( 空格 )
  2. 子代选择器 ( > )
  3. 相邻兄弟选择器 ( + )
  4. 兄弟选择器 ( ~ )
  5. 双管道选择器 ( || )

前 4 种选择器太基础不赘述,值得一提的是:由于 DOM 的渲染计算顺序,所有选择器的效果都是 父代影响后代 、排前的选择器影响排后的兄弟节点,此顺序不可逆。
双管道选择器 是 table 布局中的 <colgroup><col> 的相关实现。

元素选择器

  1. 唯一不能重复自身的选择器。(其余选择器可以重复自身,但实际开发并没有意义)
  2. 级联使用时必须写在最前。(可以理解为元素选择器是唯一没有对应关键符号的选择器)
  3. 高版本浏览器支持自定义标签选择器。
  4. 通配符选择器支持各种标签,但不包括伪元素。

属性选择器

  1. ID 与类选择器都属于属性选择器,使用写法和优先级不同。
  2. 属性值匹配选择器,支持直接匹配与正则匹配。
    表达式描述
    [attr]直接匹配
    [attr=val]完全匹配
    [attr|=val]片段开头匹配 val 或 val- 开头的值
    [attr^=val]匹配 val 开头
    [attr$=val]匹配 val 结尾
    [attr*=val]匹配包含 val

用户行为伪类

  1. 手型经过伪类 :hover
    移动端也能触发,但体验效果不佳故不适用。
    桌面端常用语鼠标上浮 和 Tip 浮层。

  2. 激活状态伪类 :active
    当鼠标主键按下或触控屏幕时元素触发,可用于任何元素。
    主要作用是反馈点击交互,各浏览器兼容效果不同,不适合做复杂交互。

  3. 聚焦伪类 :focus
    匹配:非 disabled 状态的表单标签、 包含 hrefa 标签、area 标签、summary 标签。
    聚焦转态可通过 tab 键触发,在其他职能设备上也可通过相关配套设备进行交互,可重置但不应直接取消 :focus的默认样式。

  4. 整体聚焦伪类 :focus-within
    当前元素或当前元素的任意子元素处于聚焦状态则触发。

  5. 键盘焦点伪类 :focus-visible
    Chrome 支持
    在部分特殊情况下,不同的交互 ( 比如鼠标点击和键盘切换键 ) 预期的效果不同,此时浏览器会主动判断是否应该出现聚焦转态的轮廓。

URL 定位伪类

  1. 链接伪类 :link
    匹配没有访问过 hrefa 标签。与 访问过href 的伪类 :visited 对应。
    由于伪类的优先级相同,样式书写时应注意顺序::link -> :visited -> :hover -> :active

  2. 链接历史伪类 :visited
    支持的 css 属性有限:colorbackground-colorcolumn-rule-coloroutline-color
    不支持伪元素,但子元素支持伪元素。
    支持半透明的写法,但效果上不支持半透明。
    css 属性只能重置不能添加设置。
    设置的颜色不能通过 js 获取。

  3. 超链接伪类 :any-link
    匹配所有设置了href 的链接标签:alinkarea
    匹配所有 :link:visited

  4. 锚点伪类 :target
    URL 中的哈希值匹配,页面元素的 id 值 或者 a 标签的 name 值。

  5. 目标伪类 :target-within
    :focus-within 类似, 当子元素处于 :target 时匹配。

输入伪类

该类伪类常作用于表单组件,与直接用属性选择器的效果不同。属性选择器可以作用于任何标签元素,且不具备表单元素中 fieldset 等联动与继承效果,而此类伪类可以提供更好的设计方案。

  1. 可用状态伪类 :enabled 与 禁用状态伪类 :disabled
    在正常情况下,两个伪类完全对立,即两个状态必有一个匹配。

  2. 读写特性伪类 :ready-only:ready-write
    匹配 htmlreadyonly 属性。
    :ready-only:disabled 的区别是前者依旧可以被表单提交且样式为默认样式,后者默认样式文字置灰。

  3. 占位符伪类 :placeholder-shown
    匹配表单空值时 placeholder 占位符显示。

  4. 默认选项伪类 :default
    匹配 optionselected 选中状态。

  5. 选中项伪类 :checked
    匹配单选框和复选框,书中介绍了很多 :checked 的使用场景,基本是利用 labelchecked 联动使用。

  6. 不确定值伪类 indeterminate
    匹配半选中的复选框。

  7. 有效性验证伪类 :valid:invalid
    htmlrequiredpattern 关联匹配。

  8. 范围伪类 :in-range:out-of-range
    指的注意 typerang 的 滑动元素并不存在 :out-of-range

  9. 可选伪类 :requiredoptional
    相互对立, 匹配是否设置了 required 属性的表单元素。

  10. 用户交互伪类 :user-invalid 与 空值伪类 :blank
    尚未成熟的伪类。
    :user-invalid 为用户输入不匹配内容且用户与之进行明显交互后匹配 ( 尝试提交表单和再次与表单元素交互前 )。
    :blank 规范多变,一开始匹配空标签元素,后改为没有输入值表单元素。

树状结构伪类

  1. 根伪类 :root
    匹配 html 节点

  2. :empty 匹配空标签元素和可闭合的替换元素:buttontextarea
    注释节点、空格、换行的情况不匹配。
    伪元素 ::before::after 不影响匹配。

  3. 子元素索引伪类:
    :first-child 第一个子元素。
    :last-child 最后一个子元素。
    :only-child 唯一的子元素。
    :nth-child() 第 n 个子元素。
    :nth-last-child() 反向第 n 个子元素。

  4. 类型索引伪类:
    :first-of-type 同类型第一个元素。
    :last-of-type 同类型最后一个元素。
    :only-of-type 同类型唯一元素。
    :nth-of-type() 第 n 个同类型元素。
    :nth-last-of-type() 反向第 n 个同类型元素。

逻辑组合伪类

  1. 否定伪类 :not()
    对只能重置而不能设置的属性可以巧用此伪类使代码更简洁更好理解。

  2. 任意匹配伪类 :is()

    前身为 :matches:any(),匹配表达式内任意内容。
    :where() 用法和作用相同,但 :where() 的优先级为 0 。

  3. has() - 设想中的功能强大,但目前暂不支持。

其他伪类选择符

  1. 作用域伪类:
    :scope 局部作用域伪类。
    :host() Shadow DOM 根节点伪类 。
    :host-context() Shadow DOM 根节点上下文伪类 。

  2. 全屏伪类 :fullscreen

  3. 语言相关伪类:
    :dir() 语言方向伪类, :dir(rtl) 为从左向右、:dir(rtl) 为从右向左 。
    :lang() 语言类型伪类。

  4. 资源状态伪类:
    :playing:paused 播放状态伪类。