yezi 2019-11-04
CSS语言是一种声明式语言,不像其他语言有变量、条件和逻辑等特性,因为这个原因,社区中有了各种CSS处理器语言,比如Sass、LESS和Stylus等。这些处理器语言引入了一些类似其他程序语言的特性,比如变量、运算符和逻辑运算等。
虽然CSS处理器给编写和维护CSS带来了一些便利,但是需要额外的编译,所以社区开始将CSS处理器中的变量引入到原生CSS中,最后形成了今天的CSS自定义属性。
由CSS作者(CSSer)自己定义的属性,统称为自定义属性。它允许作者自由的选择名称,自由的为名称属性分配任意值。这些属性能够提供给var()函数使用,被var()函数引用的自定义属性又常被称为变量。
这样一来,CSSer声明的这些自由属性就有了两个名称:自定义属性 和 变量:
自定义属性:使用两个连词线 -- 声明的特殊格式作为名称,该名称被称为自定义属性,同时可以给自定义属性赋予任何值。比如 --color: #fff 。
变量:CSS的 var() 函数引用的自定义属性被称为变量。var() 会返回自定义属性所对应的值,同时可以被运用于相应的CSS属性。对应的即是CSS规则中的属性值。
用一张图来描述他们之间的关系:
当我们的项目中有很多CSS文件时,无形中增加了维护成本。即便使用了CSS框架,虽然这些框架都有可能引入了Sass这样的CSS处理器帮助我们减少了出错的机会,提高了可维护性的能力,但这种通过添加额外步骤的方式(需要做编译处理),可能会增加系统的复杂性。
CSS自定义属性的出现,为我们带来了一些CSS处理器的便利,并且不需要额外的编译。在CSS中使用CSS自定义属性的好处和在编写语言中使用变量的好处没有特别的不同之处。W3C规范上有过这样的一段描述:
使用CSS自定义属性使得大文件更易于阅读,因为看起来很随意的值有了一个提示信息的名字,并且编辑这些文件更加简单,更不易于出错。因为你只需要在自定义属性处修改一次,这个修改就会应用到使用该自定义属性的任何地方。
另外,CSS自定义属性除了提供了更灵活的设置、引用和修改的便利性之外,还具有较强的语义化(比如primary这样的名称总是要比red这样的名称来得有意义)。这些语义化信息让你的CSS文件变得易读和理解。
为此,可读性和可维护性是CSS自定义属性最大的优势。并且,它让我们可以在CSS中使用原生的变量,而不再需要借助于类似Sass这样的CSS处理器。
CSS的自定义属性是CSS的一个重要的新功能,到目前为止所有的现代浏览器中都对CSS自定义属性做了良好的支持,这将使得原生 CSS 从此变得更加强大。
CSS自定义属性和常规CSS属性的用法是一样的。把它们当作动态属性会比变量更好。这意味着它们只能在声明块中使用。也就是说,自定义属性和选择器是强绑定的。可以是任何有效的选择器。
如果已声明的CSS自定义属性未被任何属性调用的话,将不会产生任何的效果。只会是一段字符串停留在你的样式文件中。
声明自定义属性的时候,自定义属性名前面要加两根连词线(--)。
body { --foo: #7F583F; --bar: #F7EFD2; }
CSS自定义属性的命名规则比较松散,可以是任何有效的字符,比如中文、大写字母、驼峰命名、中距线、emoji和HTML实体等等:
自定义属性名大小写敏感,--color 和 --COLOR 是两个不同的自定义属性。
var() 函数用于读取自定义属性,将自定义属性当作 var() 函数的第一个参数传进去。
a { color: var(--foo); text-decoration-color: var(--bar); }
var() 函数还可以使用第二个参数,表示自定义属性的默认值。如果该自定义属性不存在,就会使用这个默认值。
color: var(--foo, #7F583F); font-family: var(--font-stack, "Roboto", "Helvetica"); padding: var(--pad, 10px 15px 20px);
来做一道题:
body { --color: 20px; background-color: var(--color, skyblue); }
此时 <body> 的背景颜色是什么呢?
经过分析,上面的CSS等同于:
body { --color: 20px; background-color: transparent; }
这里需要注意的是,仅限于我们使用的自定义属性没有定义时,才使用后面的值作为元素的属性值。
如果自定义属性的值是不合法的,就会用缺省值代替。
所以 <body> 的背景色就是缺省值transparent。
var()函数还可以用在自定义属性的声明。
:root { --primary-color: red; --logo-text: var(--primary-color); }
var() 函数可以代替元素中任何属性中的值的任何部分。不过var() 函数不能作为属性名、选择器或者其他除了属性值之外的值。
例如下面的写法是无效的:
.foo { --side: margin-top; /* 无效 */ var(--side): 20px; }
CSS 自定义属性不能像 Sass 这样的处理器一样直接做一些数学计算。如果你需要做一些数据计算,那么就要使用 CSS 的 calc() 函数。
/* 这是一种错误的使用方式 */ .margin { --space: 20px * 2; font-size: var(--space); }
使用CSS自定义属性要做一些数学计算时,应该像下面这样通过calc()函数来完成:
.margin { --space: calc(20px * 2); font-size: var(--space); }
如果使用下面的CSS,<body>中的font-size大小是多少呢?
body { --size: 20; font-size: var(--size)px; }
哈哈哈,机智的我一眼就看出了答案,font-size 的值是 20px!
在构建单个指令时要小心!
当你设置如下所示的属性值时,20px被解释为单个指令(Tokens)。
font-size: 20px
在这里,20px的值被视为一个单独的实体。
如果使用下面的这种写法:
body { --size: 20; font-size: var(--size)px; }
浏览器会将其解释为 20 px。注意 20 和 px 之间有一个空格。
如果你必须创建单个指令,则用一个 CSS 自定义属性来表示整个指令,比如 --size: 20px 或者使用calc() 函数,比如 calc(var(--size) * 1px)(当 --size 设置为20时)。
因此,最稳妥的做法是:
body { --size: 20px; font-size: var(--size); }
或者使用CSS3 calc()计算:
body { --size: 20; font-size: calc(var(--size) * 1px); }
此时,<body> 的 font-size 大小才是 20px。
在 JavaScript 中,变量有作用域一说。它们可能是全局作用域,也有可能是局部作用域。那么在CSS中,CSS自定义属性也有这样的说法。
:root { --color: black; /* 全局作用域*/ } .block { color: #8cacea; --color: blue; /* 局部作用域;`--color`作用域是`.block`选择器 */ }
:root 选择器可以选择到 DOM 元素中或 document 树中最高顶级的元素。因此,在 :root 选择器中声明的CSS 自定义属性,其作用域的范围是全局范围,也就是全局作用域。局部作用域就是它所在的选择器的有效范围。
再来做一道题吧~
<!-- HTML --> <p>我是什么颜色?</p> <div>我又是什么颜色?</div> <div id='alert'> 猜猜我的颜色吧~ <p>我!还有我!可别忘了我的颜色呢! </p> </div> // CSS :root { --color: purple; } div { --color: green; } #alert { --color: red; } * { color: var(--color); }
同一个 CSS 变量,可以在多个选择器内声明。读取的时候,优先级最高的声明生效。
CSS自定义属性和CSS属性一样,可以在元素的style属性中使用CSS自定义属性。
<!-- HTML --> <button style="--color: blue">Click Me</button> // CSS button { border: 1px solid var(--color); } button:hover { background-color: var(--color); }
background-color: blue;background-color: yellow;<input type="button" value="变蓝" @click="changeColorT