查看原文
其他

【第1596期】CSS 自定义属性:基础篇

kmokidd 前端早读课 2019-10-10

前言

今天要补班,大家记得噢~今日早读文章由@kmokidd分享。

正文从这开始~~

这是 CSS 自定义属性系列文章的第一篇,在这篇文章中我将快速介绍什么是自定义属性以及它们的语法,并在后续文章中详尽地分析 CSS 自定义属性,各位可以持续关注。

你大概已经听说过 CSS 自定义属性 (也被称为 CSS 变量),可能你是从 Google 发表的这篇文章中得知这个属性的。你可能尚且不了解这个特性的浏览器支持程度,从没见过相关的最佳实践,也无从将它同 Less 或者 Sass 做比较,总之就是一头雾水。那现在就怀揣着一肚子疑问,接着往下看吧,我将为你一一解答。

兼容性

第一个问题是:CSS 自定义属性能用在哪?目前从 Can I use 上获取的信息显示除了 Edge 外主流浏览器的最新版都已经支持这个特性了,而 Edge 也将支持这个属性。

这说明现在 CSS 自定义属性已经能用在实际项目中了,相信不久以后开发者们将大大依赖这个特性。但还请在使用之前请先检查一下本文附录中 Postcss 对于 CSS 自定义属性的支持情况,以便做好兼容。

设一个值,任何值都可以

那么……什么是自定义属性呢?简单来说就是一种开发者可以自主命名和使用的 CSS 属性。浏览器在处理像 color 、position 这样的属性时,需要接收特定的属性值,而自定义属性,在开发者赋予它属性值之前,它是没有意义的。所以要怎么给 CSS 自定义属性赋值呢?这倒和习惯无异:

  1. .foo {

  2. color: red;

  3. --theme-color: gray;

  4. }

自定义元素的定义由 -- 开头,这样浏览器能够区分自定义属性和原生属性,从而将它俩分开处理。假如只是定义了一个自定义元素和它的属性值,浏览器是不会做出反应的。如上面的代码, .foo 的字体颜色由 color 决定,但 --theme-color 对 .foo 没有作用。

你可以用 CSS 自定义元素存储任意有效的 CSS 属性值:

  1. .foo {

  2. --theme-color: blue;

  3. --spacer-width: 8px;

  4. --favorite-number: 3;

  5. --greeting: "Hey, what's up?";

  6. --reusable-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.85);

  7. }

使用

假如自定义属性只能用于设值,那也太没用了点。至少,浏览器得能获取到它们的属性值。

使用 var() 方法就能实现:

  1. .button {

  2. background-color: var(--theme-color);

  3. }

下面这段代码中,我们将 .button 的 background-color 属性值赋值为 --theme-color 的值。这例子看起来自定义属性也没什么了不起的嘛,但这是一个硬编码的情况。你有没有意识到,--theme-color 的属性值是可以用在任意选择器和属性上的呢?这可就厉害了。

  1. .button {

  2. background-color: var(--theme-color);

  3. }


  4. .title {

  5. color: var(--theme-color);

  6. }


  7. .image-grid > .image {

  8. border-color: var(--theme-color);

  9. }

缺省值

如果开发者并没有定义过 --theme-color 这个变量呢?var() 可以接收第二个参数作为缺省值:

  1. .button {

  2. background-color: var(--theme-color, gray);

  3. }

注意:如果你想把另一个自定义属性作为缺省值,语法应该是 background-color: var(--theme-color, var(--fallback-color))

传参数时总是传入一个缺省值是一个好习惯,特别是在构建 web components 的时候。为了让你的页面在不支持自定义属性的浏览器上正常显示,别忘了加上兼容代码:

  1. .button {

  2. background-color: gray;

  3. background-color: var(--theme-color, gray);

  4. }

作用域和级联

要在什么时候定义这些属性?在使用之前吗?自定义属性遵从标准的作用域和级联规则,开发者按照平时使用的习惯来就可以了!

你可能希望将 --theme-color 设置为全局变量,处处可用。最简单的方法是使用 :root 伪元素:

  1. :root {

  2. --theme-color: gray;

  3. }

这样定义以后,无论是按钮、标题还是图片网格乃至整个文档,都可以使用 --theme-color 了。

但当你希望不同的模块使用不同的 --theme-color 值怎么办呢?和初始化自定义属性的步骤相同,只需要在模块的作用域中给属性重新赋值,新的颜色就会分模块生效,而不需要开发者一个个重置使用到 --theme-color 的属性。

  1. section.about {

  2. --theme-color: darkblue;

  3. }

  4. section.contacts {

  5. --theme-color: darkred;

  6. }

  7. section.news {

  8. --theme-color: teal;

  9. }

当然,你也可以定义复杂的选择器规则,应用特定的属性值:

  1. section.news > .sidenote {

  2. --theme-color: gray;

  3. }

CSS 计算

calc() 函数常常被用于跨单位的计算:

  1. .child {

  2. width: calc(100% - 16px);

  3. }

事实上这个计算是在浏览器运行时进行的,浏览器会将 calc() 的计算结果以像素单位呈现在屏幕上。

calc() 与 CSS 自定义属性结合以后会很有趣!这一点也是在制定自定义属性规范时,经过了深思熟虑才加上的,毕竟这两者的结合可谓是强强联手:

  1. :root {

  2. --base-size: 4px;

  3. }

  4. .title {

  5. text-size: calc(5 * var(--base-size));

  6. }

  7. .body {

  8. text-size: calc(3 * var(--base-size));

  9. }

只要最终的结果有意义,开发者无论使用什么样的单位都可以:

  1. :root {

  2. --base-size: 4px;

  3. --title-multiplier: 5;

  4. --body-multiplier: 3;

  5. }

  6. .title {

  7. text-size: calc(var(--title-multiplier) * var(--base-size));

  8. }

  9. .body {

  10. text-size: calc(var(--body-multiplier) * var(--base-size));

  11. }

CSS 和 JavaScript 间的桥梁

自定义属性和 Sass、Less 或者 PostCSS 这些处理器语言一个非常重要的不同点在于:浏览器是可以解析自定义属性的。这就意味着开发者可以动态改变自定义属性的值。这是 CSS 迈出的一大步。

就和平时用 JS 操作元素任意的属性一般,自定义属性也可以通过 getPropertyValue 和 setProperty 方法操作 :

  1. const styles = getComputedStyle(document.querySelector('.foo'));


  2. // Read value. Be sure to trim to remove whitespace.

  3. const oldColor = styles.getPropertyValue('--color').trim();


  4. // Write value.

  5. foo.style.setProperty('--color', 'green');

属性值一旦被改变,所有与这个自定义属性相关的 CSS 属性也都会发生改变,仿佛是开发者直接操作了那些 CSS 属性值似的。这样就能轻松实现批量修改元素的属性值。

关于 JS 和 CSS 自定义属性之间的合作和最佳实践,大家可以详细阅读这篇文章。

附录:使用预处理器编写 CSS 自定义属性

相信你已经迫不及待地想用上这个新技术,但又要考虑兼容尚未实现此特性的浏览器,那目前最好的选择就是使用 PostCSS。

PostCSS 现在可以支持 CSS 自定义属性的基本功能,也可以防止开发者不断重复编写自己的 CSS,但是像和 JS 结合动态改变自定义属性值,这相对高级的用法暂时还没有实现方案。

让我们来看看 PostCSS 能支持的特性和具体表现情况吧:

上表中对比的两个 Postcss plugin 为

  • postcss custom properties

  • postcss css variables

PostCSS CSS Varibales 中会出现编译问题的链接从上到下分别是

  • CaveatsIssue 30Caveats

若需要用 calc() 则都要和 Postcss Calc 配合使用。

(译者注:实测 cssnext 更好用一些)

关于本文 译者:@kmokidd 原文:https://zhuanlan.zhihu.com/p/25714131 作者:@Sérgio 原文:https://sgom.es/posts/2017-01-27-css-custom-properties-the-basics/

为你推荐


【第1247期】使用圆锥渐变和CSS变量创建一个Range Input控制的环形图


【第1227期】关于 CSS 变量,你需要了解的一切


他曾分享过


【第1452期】见微知著,Google Photos Web UI 完善之旅

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存