html中无效的属性值,在CSS自定义属性中有效使用无效变量

CSS自定义属性已是CSS中非常成熟的特性了,也是近两年非常受欢迎的特性。它的到来让CSS像其他编程语言一样,可以在编写CSS的时候变量,而且还可以在CSS具备动态计算、逻辑运算和状态切换等特性。特别是CSS Houdini的CSS自定义属性更进一步的扩展了CSS的能力。

就我个人而言,在几年前CSS自定义属性就进入我的世界,而且相关的规范也阅读过好几次。但自从阅读了@Lea Verou的《The -​-var: ; hack to toggle multiple values with one custom property》一文之后,我才发现自己遗漏了CSS自定义属性中一个非常关键,而且非常强大的特性。那就是CSS自定义属性中的无效变量,即var()函数中使用了一个无效的变量。如果我们在使用CSS自定义属性的时候,要是有效的使用了无效变量,它可以帮助我们实现一些非常有意思的功能。比如说状态切换,主题切换等。在接下来,我们就一起来探讨这方面的话题。

前景

@Lea Verou在《The -​-var: ; hack to toggle multiple values with one custom property》一文中介绍了CSS自定义一种特性,即:使用一个单一的属性值来开启或关闭多个不同的属性,甚至是多个CSS规则。比如下面这个示例,当你将鼠标移动到按钮上,按钮从一个扁平的效果过渡到一个凸起(带有渐变,高亮,边框)的按钮:

代码很简单:

button {

--is-raised: ; /* off by default */

border: 1px solid var(--is-raised, rgb(0 0 0 / 0.1));

background: var(

--is-raised,

linear-gradient(hsl(0 0% 100% / 0.3), transparent)

)

hsl(200 100% 50%);

box-shadow: var(

--is-raised,

0 1px hsl(0 0% 100% / 0.8) inset,

0 0.1em 0.1em -0.1em rgb(0 0 0 / 0.2)

);

text-shadow: var(--is-raised, 0 -1px 1px rgb(0 0 0 / 0.3));

}

button:hover {

--is-raised: initial; /* turn on */

}

button在:hover状态时,自定义属性--is-raised从一个空字符串(--is-raised: ;)变成了initial(--is-raised: initial;),就轻易地实现了两种状态的UI切换。最初我一直没搞明白这其中的原理是什么?后来重新阅读CSS自定义属性规范时,才发现我自己遗漏了其中最为关键的一个特性,即 无效变量(Invalid Variables)。

需要了解的几个关键信息

在详细介绍CSS自定义属性中“无效变量”之间,我们有几个关键信息需要先了解一下,因为掌握这些关键信息有利于我们更好的理解CSS自定义属性中的“无效变量”所起的作用。也就是,为什么可以使用CSS自定义属性就可以轻易实现“一个单一的属性值来开启或关闭多个不同的属性,甚至是多个CSS规则”。

71f84ed1d64d50bf6780ebe5c82ee0ca.png

回退值(Fallback Value)

接触过CSS自定义属性的同学应该都了解,在CSS中使用var()函数调用CSS自定义属性时,该自定义属性在var()函数中就变成了CSS的变量:

9c77740a369893e68f8c3c40b9cfed39.png

而var()函数接受两个参数,其中第一个参数是要替换的自定义属性名;第二个参数,如果提供的话是一个回退值,即当被引用的自定义属性无效时,它被用作自定义属性的回退值。比如下面这个示例:

.element {

color: var(--color, red)

}

就该示例而言,--color并没有被定义,那么这个时候,var()将会取其第二个参数red作为其回退值,并赋值给color属性。

另外一种情况是,在代码中显式声明了自定义属性,但该自定义属性运用于某些CSS属性上时,它是个无效值,比如:

.element {

--color: 20;

border: 3px double var(--color, red);

color: var(--color, blue);

}

48e9cddc8dfb89899291b532a8dbd00e.png

这个示例中我们显式声明了--color自定义属性,而且其值是20,对于--color自定义属性是个有效值,但var()引用--color时,--color是有效的,此时var()的回退值就不会起作用。此时相当于:

.element {

border: 3px double 20;

color: 20;

}

此对color和border是个无效的值,会被忽略。但对于color属性来说,虽然是无效,但这个时候浏览器在计算时,会继承其父元素的color值,该示例对应的是浏览器默认文本颜色,即#000。

乍一看似乎很混乱,但有充分的理由。第一个是技术原因:浏览器引擎在“解析时间”(先发生)处理无效或未知的语法,但变量要到“计算值时间”(后发生)才会被解析。

在解析时,无效语法的声明会被完全忽略(回退到之前的声明),而之前的声明会被丢弃

在计算值时,变量被编译为无效,但为时已晚(之前的声明已经被丢弃了)

根据规范,无效的变量值和未设置的变量值会像unset一样解析。

这对于开发者而言是好事,因为它允许我们为提供更复杂的回退值。更妙的是,这允许我们使用null、undefined状态来设置所需参数。

另外规范中对“ 要在一个属性的值中替换一个var() ”做出了明确的指导:

如果var()函数的第一个参数命名的自定义属性被动画污染(animation-tainted),并且var()函数被用于动画属性(animation)或它的一个简写属性,那么本算法的其余部分将自定义属性视为具有初始值(initial)

如果var()函数的第一个参数命名的自定义属性的值不是初始值(initial),则用相应的自定义属性的值替换var()函数;否则,则用var()函数的第二个参数值(当然,var()要显式设置了回退值)。如果var()的回退值中引用了任何var()函数,使用原则是相同的;如果没有var()没有回退值,那么var()函数的属性在计算值时是无效的

也就是说:

var()函数是在计算值时间(Computed-Value)被替换的。如果一个声明,一旦所有的var()函数都被替换进来,那么这个声明在计算值时间是无效的。

保证无效值(Guaranteed-Invalid Value)

如果自定义属性的值是initial,那它就是一个保证无效的值(Guaranteed-Invalid Value)。正如前面提到的,使用var()将一个自定义属性替换为这个值(initial),将会使引用它的属性在计算值时无效。

这个值序列化为空字符串,但实际上在自定义属性中写一个空值,比如--foo: ;是一个有效的(空)值,而不是保证无效的值。不管出于什么原因,想要手动将一个变量重置为保证无效的值,只需要使用关键词initial就可以做到。

说到自定义属性的空值就很有意思了,比如:

:root {

--color: ;

--borderColor:;

}

示例中--color和--borderColor自定义属性都没有设置其他的值,唯一不同的是--color后面紧跟的冒号(:)和分号(;)之间有一个空格硬编码(记住,在编码的时候手动敲了一个空格),--borderColor后面紧跟的冒号和分号之间却没有这个空格。他们同时被var()函数引用的时候,却有天壤之别,--color是有一个有效的自定义属性,而--borderColor是一个无效的,如果var()函数提供回退值时,那么引用--borderColor变量的var()函数将会使用回退值替换--borderColor设置的值。

:root {

--color: ;

--borderColor:;

}

.element {

border: 3px double var(--borderColor, red);

color: var(--color, blue);

}

f10c80deee498f14c1499ccb1365f438.png

示例结果和我们前面描述是一致的。--borderColor:;是一个保证无效的值(等同于--borderColor: initial),因此会采用回退值red作为border-color的值,所以看到的边框颜色是red;而--color: ;是一个有效值,这个时候即使var()函数提供了回退值blue,也不会被使用。color取了一个空值,不过color会继承其父元素的color值(此例是#000),因此你看到的文本颜色是黑色。

虽然在自定义属性中使用--foo:;方式可以和使用--foo: initial;让该自定义属性是一个保证无效的值,但使用--foo:;在可读性上不怎么好,甚至对于不了解该特性的同学来说会以为是一个错语;而使用--foo: initial;方式对于不了解该技术的同学来说同样会让人感到奇怪。因此,为了提高代码可读性,最好是在后面添加相应的代码注释。

计算值(Computed Value)

了解CSS工作机制的同学都应该知道,CSS属性的最终值会经过四步计算:

通过指定来确定值,常称之为

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值