快捷搜索:
来自 新京葡娱乐场网址 2019-11-01 11:16 的文章
当前位置: 67677新澳门手机版 > 新京葡娱乐场网址 > 正文

CSS3中的原生变量var详解,为什么我为css变量如此

为什么我为css变量如此兴奋

2016/01/01 · CSS · 变量

原文出处: Philip Walton   译文出处:腾讯ISUX   

几个星期前,CSS Variables ——CSS 变量草案发布在了W3C官方 ,更准确的应该叫CSS 自定义属性,目前在Chrome Canary 版里面已经支持,开启该功能见附[1]

当Chrome浏览器工程师Addy Osmani第一时间把这消息发布在twitter后,遭到了数万人的否定、敌视和怀疑。于我而言,更多的感到是一个惊喜,因为这个功能实在让人太兴奋了。

快速的扫了一遍之后,发现99%人抱怨的无外乎这两点:

  • 语法太丑和不够简洁
  • Sass 、Less早就有这些玩意了,不太care

虽然我承认我也对这语法很反感,更重要的是理解语法不只是反复无常的在选择。CSS工作组讨论很久语法的长度,他们提取了一些点,考虑到CSS的语法兼容不会与未来增加的其他语言冲突。

CSS 预处理器是一个非常出色的工具,但是它们的变量是静态的,有语法作用域。Native CSS 变量,从另一面来看,它们是一个完全不同类型的变量:因为它们是动态的,他们的作用域是DOM,事实上,这也是困惑该不该称他们为变量,它们实际上是CSS 属性,这也给了他们一个机会,来解决这个功能完全不同的问题。

在这篇文章中,我将讨论一些CSS 自定义属性这个功能,而且不用CSS 预处理器来做。当然我还演示一些新的设计模式,自定义功能的启用。文章最后讨论一下,我认为在未来最有可能的是预处理变量和自定义变量一起使用,两个东西取长补短,珠联璧合。

注意:这篇文章不是介绍CSS 自定义属性,如果你还从来没听说过他们,不熟悉他们是如何工作的,可以看看这里

使用语法

首先我们先来看一个例子:
html代码:

<div class="element">这是一段文字</div>

css代码:

.element {
  width:200px;
  height:200px;
  --main-bg-color: #000;
  color:#fff;
  background-color: var(--main-bg-color);
}

实现效果:

图片 1

结果是该DOM元素背景变成了黑色。

CSS中原生的变量定义语法是:--*,变量使用语法是:var(--*),其中*表示我们的变量名称。关于命名这个东西,各种语言都有些显示,例如CSS选择器不能是数字开头,JS中的变量是不能直接数值的,但是,在CSS变量中,这些限制通通没有,例如:

:root{
    --main-bg-color: #000;
}
.element {
    background-color: var(--main-bg-color);
}

注意:变量名称不能包含 style="color: #ff0000;">$,[,^,(,%等字符,普通字符局限在只要是“ style="color: #ff0000;">数字[0-9]”“ style="color: #ff0000;">字母[a-zA-Z]”“ style="color: #ff0000;">下划线_”和“ style="color: #ff0000;">短横线-”这些组合,但是可以是中文,日文或者韩文,例如:

.element {
  width:200px;
  height:200px;
  --黑色: #000;
  color:#fff;
  background-color: var(--黑色);
}

css变量完整语法:
CSS变量使用的完整语法为:var( [, ]? ),用中文表示就是:var( <自定义属性名> [, <默认值 ]? ),也即是如果我们没有定义变量名称,那么就会使用后面的值作为其默认属性值。
如下:

.element {
    background-color: var(--new-bg-color,#EE0000);
}

得到的结果当然是后面颜色的值的背景。

我们来看一下如果变量名称不合法会出现什么结果,看下面例子:

body {
  --color: 20px;
  background-color: #369;
  background-color: var(--color, #cd0000);
}

请问,此时<body>的背景色是?

  • A. transparent
  • B. 20px
  • C. #369
  • D. #cd0000

答案是:A. transparent
CSS变量中,果发现变量值是不合法的,例如上面背景色显然不能是20px,则使用背景色的缺省值,也就是默认值代替,于是,上面CSS等同于:

body {
    --color: 20px;
    background-color: #369;
    background-color: transparent;
}

预处理器变量的限制

在继续写之前,我想强调的是,我真的很喜欢CSS 预处理器,我的所有项目都在使用它。预处理器做了一件非常了不起的事情,即时你知道他最终出来的就是原始的CSS,任然可以感受这个神器的时代。

任何工具,都有他的局限性,有一个炫酷的外观会让人惊喜而忽略了其中的限制,特别是新用户。

css变量在js中的应用

看如下例子,html代码:

<div id="jsDom">这是一段文字</div>

css代码:

#jsDom {
    --my-varwidth: 200px;
    background-color: #000;
    color:#fff;
    width:var(--my-varwidth);
    height:200px;
}

js代码:

var element = document.getElementById('jsDom');
var curWidth = getComputedStyle(element).getPropertyValue("--my-varwidth");
console.log(curWidth); //200px

//设置过后该DOM元素的宽度变为了300px
element.style.setProperty("--my-varwidth", '300px');

如果样式是写到行间呢?那么进行如下操作:
html代码:

<div id="jsDom" style="--my-varwidth:400px;width:var(--my-varwidth);">这是一段文字</div>

js代码:

var element = document.getElementById('jsDom');
var curWidth = element.style.getPropertyValue("--my-varwidth");
console.log(curWidth); //400px

Preprocessor variables aren’t live

也许受预处理限制,在媒体查询中,最常见的新手也无力吐槽定义变量或使用@extend

<code> $gutter: 1em; @media (min-width: 30em) { $gutter: 2em; } .Container { padding: $gutter; } </code>

1
2
3
4
5
6
7
8
9
10
11
<code>
$gutter: 1em;
 
@media (min-width: 30em) {
  $gutter: 2em;
}
 
.Container {
  padding: $gutter;
}
</code>

如果你编译上面的代码,你得到是:

CSS

.Container { padding: 1em; }

1
2
3
.Container {
  padding: 1em;
}

如你所见,媒体查询被废弃,变量赋值被忽略。

从理论上讲,虽然sass 负责申明条件变量,但这样做也是一个挑战,枚举所有Permutations—exponentially 会增加CSS的最终大小。

浏览器兼容

浏览器的兼容如图所示:

图片 2

到目前位置IE11也不支持该css变量。

说到这儿感觉这个css变量也是很强大的,那么它跟预处理器比较,你觉得哪个更好?下面讲一下预处理器的劣势。

预处理器变量不能级联(层叠)

每当你使用变量,作用域的范围不可避免,这个变量应该全局吗?应该是file/module?还是块作用域?

CSS 最终是为HTML的样式,事实证明还有另外一种有用的方法是变量的范围:DOM 元素,但是preprocessors不能运行在浏览器且从未看见标记

参考一个网站,试图给` 的元素添加一个 classuser-setting-large-text他们更倾向于更大的文本大小 。 一旦这个class设置,更大$font-size`变量赋值就会运用:

CSS

$font-size: 1em; .user-setting-large-text { $font-size: 1.5em; } body { font-size: $font-size; }

1
2
3
4
5
6
7
8
9
  $font-size: 1em;
 
.user-setting-large-text {
  $font-size: 1.5em;
}
 
body {
  font-size: $font-size;
}

但是,就像上面媒体查询例子,Sass 直接忽略变量赋值, 意味着这种事是不可能的。他输出的:

CSS

body { font-size: 1em; }

1
2
3
  body {
  font-size: 1em;
}

预处理器劣势

预处理器变量不继承

虽然继承是级联的一部分,但是我还是要提一下,因为很多次我想使用这个功能都未能用成。

有一种情况,你有Dom元素在颜色风格基础上有什么的变化时候,你可以用在他们的父元素上。

CSS

.alert { background-color: lightyellow; } .alert.info { background-color: lightblue; } .alert.error { background-color: orangered; } .alert button { border-color: darken(background-color, 25%); }

1
2
3
4
5
6
7
.alert { background-color: lightyellow; }
.alert.info { background-color: lightblue; }
.alert.error { background-color: orangered; }
 
.alert button {
  border-color: darken(background-color, 25%);
}

上面的Sass代码是无效的,但你应该能理解这代码试图要完成什么。

它最后试图使用sass的darken函数用在background-color属性,但button元素继承它的父class元素.alert。如果class info或者error已经添加到alert(或者通过JavaScript设置背景颜色或用户样式),按钮元素希望能够得到这两个颜色。

现在这个虽然不会在sass 运行,因为预处理器不知道DOM结构,但还是希望搞清楚这类型的东西可能有哪些用处。

说一个特定的用例:这也是在继承DOM属性的可访问性运行color 函数的原因。举个栗子,为了确保文本总是可读,且充分与背景颜色形成鲜明对比。通过自定义属性和新的CSS Color函数,这将很快成为可能!

预处理器变量不是实时的

也许令新手惊讶的是,预处理器局限性最常见的情况是Sass无法在媒体查询中定义变量或使用@extend。

$gutter: 1em;
@media (min-width: 30em) {
     $gutter: 2em; 
} 
 .Container { 
     padding: $gutter; 
 }

上面代码将编译为:

.Container { 
     padding: 1em;
 }

上面结果可以看出来,媒体查询块被丢弃,变量赋值被忽略。

由于无法在匹配@media规则的基础上改变变量,所以唯一的选择是为每个媒体查询分配一个唯一的变量,并单独编写每个变体。

预处理器变量不能相互协作

这是一个明显呈下降趋势的预处理器,如果你用PostCSS 建立一个网站,你想使用第三方组件,不好意思,你只有通过Sass的themeable

与第三方分享预处理器变量在不同的工具集成或第三方托管的CND样式与都非常困难(至少不容易)

本地CSS自定义属性将与任何CSS预处理或者原CSS正好相反。

预处理器变量不能级联

每当使用变量,作用域的问题就不可避免的出现。这个变量应该设置为全局变量吗?是否应该限定其范围为文件或模块?是否应该限制在块中?

由于CSS最终目的是为HTML添加样式,事实证明还有另一种有效的方法给变量限定作用域:DOM元素。但由于预处理器不在浏览器中运行并且无法看到标记,它们不能这样做。

假设有一个网站,面对偏好较大文字的用户,就向<html>元素添加类user-setting-large-text。当设置了这个类时,应当应用较大的$font-size变量赋值:

$font-size: 1em;
.user-setting-large-text {
    $font-size: 1.5em;
} 
body { 
    font-size: $font-size; 
}

但同样,就像上面的媒体块示例,Sass完全忽略了该变量的赋值,这意味着这是不可能发生的。编译后的代码如下:

body { 
    font-size: 1em;
}

自定义属性有何不同

你可能已经猜到了,我上面列出的适用于CSS 自定义属性没有任何限制,但也许更重要的不是说他们不适用,而是为什么他们不用。

CSS自定义属性就像常规的CSS属性一样,他们的操作方式完全相同

像普通的CSS属性,自定义属性是动态的,他们可以在运行时修改,也可以在媒体查询时通过更改DOM添加一个新类,同时也可以指派内联元素和一个常规CSS里申明选择器。还可以通过正常的cascade规则或者使用JavaScript覆盖。最主要的是,他们的可以继承的,所以当他们应用到DOM元素的时候,他们的子元素也会继承属性。

为了更简洁,预处理器变量是语法作用域和编译后静态。自定义属性作用域是DOM,他们都很灵活。

预处理器变量不继承

虽然继承严格说来是级联的一部分,之所以把它单独分出来讲,是因为多次想调用这个特性却不得。

假设一种情况,要在DOM元素上基于其父元素应用的颜色而设置样式:

.alert {
    background-color: lightyellow;
}
.alert.info {
    background-color: lightblue;
}
.alert.error {
    background-color: orangered;
}

.alert button {
    border-color: darken(background-color, 25%);
}

上面的代码并不是有效的Sass(或CSS),但你应该明白它想达到什么目的。

最后一句声明试图在<button>元素从父元素.alert元素继承的background-color属性使用Sassdarken函数。如果类infoerror已经加在了.alert上(或如果background-color已通过JavaScript或用户样式设置),button元素能据此作出相应的响应。

显然这在Sass中行不通,因为预处理器不知道DOM结构,但希望你清楚的认识到为什么这类东西是有用的。

调用一个特定的用例:出于可访问性的原因,在继承了DOM属性上运行颜色函数是极其方便的。例如,确保文本始终可读,并充分与背景颜色形成鲜明对比。 有了自定义属性和新的CSS颜色函数,很快这将成为可能。

实际案例

如果你仍然不确定自定义属性可以做到这一点,而预处理器不行,我这里给一些例子。

不论真假,有大量非常好的例子我都很想展示,但为了不让这篇文章太丑,我选了两个。

我选择这些例子不仅仅因为它们的理论,它们也是我们过去实际面临的挑战,我依然记得试图用预处理器,但这是不可能的。现在好了,直接自定义属性走起。

预处理器变量不可互操作

这是预处理器相对明显的一个缺点,提到它是因为我觉得它重要。如果你正使用PostCSS来构建网站,想使用只能通过Sass实现主题化的第三方组件,那你真是不走运了。

跨不同的工具集或CDN上托管的第三方样式表共享预处理器变量是不可能(或至少不容易)的。

原生的CSS自定义属性可以与任何CSS预处理器或纯CSS文件一起使用。反之则不然。

下面给一个css变量在媒体查询中的使用:

:root {
    --gutter: 1.5em;
}

@media (min-width: 30em) {
    :root {
        --gutter: 2em;
    }
}
@media (min-width: 48em) {
    :root {
        --gutter: 3em;
    }
}

如果是预处理器这样写就无效了。

本文由67677新澳门手机版发布于新京葡娱乐场网址,转载请注明出处:CSS3中的原生变量var详解,为什么我为css变量如此

关键词: