尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

精读 CSS 属性选择器:语法速查、实战技巧与工程化取舍

精读 CSS 属性选择器:语法速查、实战技巧与工程化取舍 文档技术博客教程【免费下载链接】weekly前端精读周刊。帮你理解最前沿、实用的技术。项目地址https://gitcode.com/GitHub_Trending/we/weekly点击查看免费下载导读本文以前端精读周刊对 Smashing Magazine 一篇关于属性选择器文章的解读为核心系统梳理 CSS 属性选择器的全部匹配语法存在、精确、单词、前缀、后缀、连字符、子串、大小写不敏感等、attr()取值技巧以及输入框样式、下载图标、折叠面板、调试着色、隐藏元素等可直接上手的实战案例同时结合本仓库中关于 css-in-js 与 css-modules 的多篇精读深入讨论「属性选择器虽强为何在工程中难以大规模实践」的根源与适用边界帮助读者在「选择器的设计之美」与「工程隔离的现实」之间做出理性取舍。引言为什么还要重新学习 CSS 选择器在 Css Module 与 Css-in-js 大行其道的当下多数前端团队已经习惯于「用 className 做唯一定位」。但正如本期刊解读的文章所指出的这种习惯会导致对 class 的过度依赖与滥用反而违背了 CSS 选择器的设计初衷——选择器本应基于文档结构、元素类型与属性状态来描述样式而不是为每一个视觉状态都造一个独一无二的 class 名。这篇文章的价值在于把「选择器」本身作为主角重新审视它在现代前端工程中的实用价值。完整的原文收录于 readme.md 所维护的周刊目录中读者可在 前沿技术 目录下找到本期的完整精读稿。属性选择器七种匹配方式一次讲透属性选择器允许我们基于元素是否存在某个属性、以及该属性的值来选中元素。它本质上是一套比 class 更贴近「数据语义」的匹配语法。1. 属性存在性[attr]只要元素包含title属性就选中不看属性值是什么div[title]这里有一个容易混淆的细节选择器之间加不加空格语义完全不同。加上空格表示后代选择器匹配的是「包含title属性的子元素」div [title]即「先选中所有div再在其后代中寻找带title属性的元素」而不加空格的div[title]是「同时满足 div 标签与 title 属性」的同一元素。这是属性选择器最基础也最常踩的坑。2. 精确匹配[attrvalue]匹配title值完全等于dna的元素div[titledna]3. 单词匹配[attr~value]匹配title属性值中包含独立单词dna的元素。所谓「独立单词」指用空格分割出的完整词例如my beautiful dna或mutating dna is fun!都能命中而dnax或my-dna不会被命中div[title~dna]~常用于匹配以空格分隔的 token 列表例如多值 class 属性、rel属性等场景。4. 后缀匹配[attr$value]与正则的结尾锚点类似匹配title属性值以dna结尾的元素div[title$dna]5. 前缀匹配[attr^value]匹配title属性值以dna开头的元素div[title^dna]6. 连字符前缀匹配[attr|value]这是前缀匹配的「语言标签版」匹配属性值以dna开头且紧跟其后的是连字符-的元素。因此dna与dna-zh都能命中而dnaer不会被命中div[title|dna]该操作符的设计初衷就是匹配语言标记lang attribute例如en、en-us都可以用[lang|en]统一选中是做国际化布局时非常实用的选择器。7. 子串匹配[attr*value]只要属性值中包含dna这三个字符即命中不要求是完整单词div[title*dna]大小写不敏感修饰符i属性选择器真的很像正则你可以附加i修饰符让匹配过程对大小写不敏感div[title*dna i]这样DNA、Dna、dna都会被命中。注意修饰符i与属性值之间需要空格分隔。组合使用多个属性条件叠加属性选择器可以与其他选择器自由组合例如「找到同时拥有title属性且 class 名以genes结尾的a标签」a[title][class$genes]多个属性条件在同一组方括号内或连续书写均可它们之间是「且」的关系这种组合能力让选择器可以精确描述「带有特定语义属性、且处于特定视觉状态」的元素而无需额外引入 class。用attr()读取选中元素的属性值属性选择器负责「选中」attr()函数则负责「取值」——把选中元素的某个属性值直接注入到样式内容中。两者配合可以做出非常巧妙的纯 CSS 交互。例如当鼠标悬停在.joke元素上时在文字末尾显示其title属性的内容.joke:hover:after { content: Answer: attr(title); display: block; }这里的content属性接收了attr(title)返回的字符串让提示信息完全由 HTML 中的数据驱动无需在 JS 中维护一份对应的状态。同理也可以用attr(src)把script或img的资源地址显示在页面上作为调试手段。实战技巧属性选择器能解决的真实场景根据输入框类型设置样式表单控件天然携带type属性是属性选择器最典型的应用场景。比如为不同类型的输入框赋予不同的颜色帮助用户从视觉上区分输入内容的类别input[typeemail] { color: papayawhip; } input[typetel] { color: thistle; }这比给每个输入框额外编写一个 class 更直接、也更符合语义。改变下载标签的图标配合download属性与href后缀匹配可以为不同类型的下载链接自动附加对应的图标。例如「带download属性、且链接以.pdf结尾」的下载链接a[download][href$pdf]:after { content: url(pdf-icon.svg); }属性选择器让「链接是什么类型的文件」这个事实直接驱动视觉呈现而不需要为每个文件类型维护独立的 class。重写历史遗留代码的样式面对无法改动的老代码属性选择器可以作为「定向覆盖」的利器。例如下面这段陈旧的 HTMLdiv bgcolor#000000 color#FFFFFFOld, holey genes/div可以精确命中带有这些历史属性的元素并重写样式div[bgcolor#000000] { /*override*/ background-color: #222222 !important; }但需要特别谨慎这种「属性即样式」的写法写得越多样式与 HTML 的耦合越深最终会变成难以维护的样式债。它更适合作为一次性修复手段而不是常规的样式方案。为原生折叠组件定义展开态样式details是 HTML 原生的手风琴折叠组件open属性表示其当前展开状态details summaryList of Genes/summary Roddenberry Hackman /details属性选择器可以优雅地表达「展开时的样式」details[open] { background-color: hotpink; }这里[open]是典型的「状态即属性」用法状态由 HTML 属性承载样式随属性变化无需 JS 参与。给缺失async的脚本「上色」作为页面性能的友好提示可以选中「带src属性、但没有async标记」的script标签将其渲染为显眼的色块并显示出其src路径script[src]:not([async]) { display: block; width: 100%; height: 1em; background-color: red; } script:after { content: attr(src); }其中:not([async])是对属性选择器的否定取反[src]与:not([async])组合后可以精确锁定「需要异步加载却未标记」的脚本相当于用纯 CSS 做了一轮性能体检。用属性选择器为内联事件「着色」由于 HTML 属性包括内联事件属性在 DOM 中都以属性形式存在属性选择器同样可以命中它们。例如为带OnMouseOver属性的元素染色并在其后追加属性内容[OnMouseOver] { color: burlywood; } [OnMouseOver]:after { content: JS: attr(OnMouseOver); }需要说明的是这种「JS 事件选择器」本质是匹配任意存在的属性名HTML 属性名不区分大小写而非浏览器新增的 CSS 事件机制在现代工程中内联事件属性本身会引入安全隐患与 CSP 限制因此该技巧更适合作为理解「属性选择器可以匹配任意属性」的演示而非生产实践建议。选中隐藏元素并强制显示以下两条规则可以选中「带hidden属性」或「typehidden」的元素并把它们强制显示出来在排查被隐藏元素问题时非常有用[hidden], [typehidden] { display: block; }精读思考强大的选择器为何在工程中难以大规模实践属性选择器的能力远不止上述示例。正如原文所指出的更完整的参考可查阅 w3school 选择器参考手册但把「结合一篇文章来读」与「动手实践」结合起来才能理解得更深刻。然而回到 css modules 或 css-in-js 的工程代码中我们往往难以大量实践属性选择器原因集中在以下三个方面。一直在担心的 DOM 结构变动业务开发中需求大量涌入也许过了一周DOM 结构就已经面目全非普通的圣杯布局可能从 Table 布局被重构为div flex今天写的table选择器可能在某一天全部失效今天的div选择器明天可能因语义化改造换成了article标签。这种脆弱的根源在于一种视觉界面对应的实现方式太多。不仅标签可以各异布局属性还有table、block、flex、grid可选而grid布局还会导致视觉结构与 DOM 结构不完全对应。如果你今天用选择器做了一套完全贴合当前 DOM 结构的样式文件这个文件很可能成为后续 DOM 改动的噩梦——选择器与 DOM 的强耦合意味着每一次结构调整都要同步审视所有依赖它的规则。你敢做全局样式覆盖吗排除标签、仅对属性做全局覆盖确实可以部分绕开 DOM 结构的限制但「全局样式覆盖」本身在不同团队中有着截然不同的命运小明的团队非常懂 CSS 运用每天花一小时讨论项目的 CSS 架构对通用需求样式做抽象且每个人都认可方案。在他们的团队里一个酷炫的按钮与动画效果通过button animate /就能完成页面交互流畅、体验统一、代码简洁优雅。小白的团队水平参差不齐有人永远只用table布局有人总想把试验阶段的 CSS 属性用在生产环境。小白抽象了一个全局样式文件但团队没时间沟通甚至有人私下注入全局样式总有人抱怨样式被覆盖最后小白不得不在页面入口写*: unset来清空各种奇怪的全局干扰——但他清楚清空那个「该死的」全局样式文件会带来更大的灾难。结论很明确并不是每个团队都适合做全局样式覆盖。全局覆盖对团队的样式治理能力、沟通成本与共识度都有极高要求这也是属性选择器难以普及的组织层面原因。JS 模块化思维的影响为什么一个项目安装了几百个 npm 三方包却依然能正常运行因为好的三方包遵守模块化、不产生副作用被使用时的效果可被预期。试想几百个 npm 包同时定义不同规范的全局 CSS 覆盖项目会变成什么样子。当然JS 与 CSS 并不适合放在一起比较CSS 大多是业务级别的能写 CSS 的只有做业务的你第三方包一般不会提供 CSS 定义来干扰你的项目。然而大部分 UI 组件库是自带样式的——为什么当初使用 Bootstrap 不反感而现在却反感组件库的全局样式使用 Bootstrap 的时代Bootstrap 一般是项目第一个依赖我们明确知道它会注入全局样式会泡在官方文档里一条条理解它的全局规则。而现在是 css-in-js、至少是 css-in-npm 的时代什么都用 npm 装什么都是模块化的。很多时候我们用一个 UI 组件只是为了在某一处使用并不想接受它带来的全局样式污染、视觉设计哲学更不想看它的 CSS 文档。因此好的组件库往往 CSS 使用得很收敛尽量不影响用户项目环境。如果你项目的样式已经被不得不安装的第三方包全局覆盖得面目全非每一次修改全局样式都如履薄冰你可能就会反感 CSS 选择器转而推崇更安全的 css modules 或 css-in-js——让每个组件的 className 唯一做到标签粒度的隔离。本仓库中的 精读《我们为何弃用 css-in-js》 与 精读《css-in-js 杀鸡用牛刀》 两篇分别从「弃用方」与「质疑方」两个角度完整呈现了这场讨论可对照阅读。总结选择器的设计之美与理性的使用边界笔者认为在一个确定的环境中——比如一个组件、一个独立负责的模块——是比较适合使用 CSS 选择器的这样可以让样式代码更易读DOM 结构更清爽。但请一定注意作用域如果不是大家一起达成的共识最好不要放到全局样式中。即使项目的风格非常明确比如a标签一定要用红色在把这条规则放入全局样式之前请思考一下这样做会不会破坏某个用a标签模拟按钮的组件库的样式CSS 属性选择器的强大功能需要有良好的项目管理做支撑或者通过技术手段如 shadow dom做支撑。不过 shadow dom 的支持程度在当年仍然很低因此使用编译工具css-modules、css-in-js 等做隔离在某种程度上「模拟」了 CSS 选择器 shadow dom 的功能——一切样式都用唯一 className 控制或许是 shadow dom 全面普及前的一种妥协方案。回到本仓库的周刊脉络这篇文章更多是在描述CSS 选择器的设计之美而工程化的取舍css-in-js vs css-modules vs 原生选择器仍在持续演进。后续如 精读《使用 css 变量生成颜色主题》、精读《我们为何弃用 css-in-js》 等篇目都在同一主题下提供了更完整的视角。建议读者把本文的语法速查当作工具箱把「作用域与共识」当作使用前提让属性选择器在合适的位置发挥它真正的价值。赞分享文档技术博客教程【免费下载链接】weekly前端精读周刊。帮你理解最前沿、实用的技术。项目地址https://gitcode.com/GitHub_Trending/we/weekly点击查看免费下载相关推荐The Concise TypeScript Book 精读TypeScript 可选属性Optional Properties从语法到工程实战The Concise TypeScript Book 精读TypeScript 可选属性Optional Properties从语法到工程实战 本篇指南文档教程NocoBase CLI nb proxy caddy 实战Caddy 反向代理入口的 driver 选择、配置生成与运行控制NocoBase CLI nb proxy caddy 实战Caddy 反向代理入口的 driver 选择、配置生成与运行控制 本文基于 NocoBase C文档教程知识库requests-html CSS选择器实战精准定位网页元素技巧requests html CSS选择器实战精准定位网页元素技巧 你还在为网页数据提取时找不到正确的元素而烦恼吗是否遇到过明明CSS选择器在浏览器里能工作网页爬虫上一篇PSGAN视频妆容迁移教程让你的视频人像妆容秒变高级感下一篇Next.js热重载深度解析提升开发效率的终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表