[CSS] 自定义变量带你随心所欲,一键换肤

栏目: CSS · 发布时间: 5年前

内容简介:CSS自定义属性?听着怎么那么神奇呢,属性还可以自定义,那不是可以放肆地玩耍?我自己定义的属性浏览器都能认识?其实CSS自定义属性还有很多小名,比如说到变量,在SCSS\LESS等CSS预处理器中大家都已经经常运用,说来有几点好处:

CSS自定义属性?听着怎么那么神奇呢,属性还可以自定义,那不是可以放肆地玩耍?我自己定义的属性浏览器都能认识?

一、基础

(一)名字和用途

其实CSS自定义属性还有很多小名,比如 CSS变量原生变量CSS自定义属性级联变量 ,这些指的都是同个东西。

说到变量,在SCSS\LESS等CSS预处理器中大家都已经经常运用,说来有几点好处:

1、能使用颜色变量统一风格;

2、可以采用一致的组件属性,包括布局和定位等;

3、避免代码冗余。

那既然SCSS就能做到的东西,我们还有这个所谓的CSS自定义变量干什么呢?人家自然有它的独到之处。

1、比如可以在运行时改写,具备动态性;

2、比如方便使用JS读取和改写;

3、比如可继承、可组合、同时具有作用域。

在这几个方面,预处理器完全被CSS自定义变量KO了。

(二)声明变量

语法很简单,分成两步, 声明变量使用变量

声明变量使用的是 -- 前缀。

:root{
    --*: xxxx;
    /* --variety-name: variety-value; */
}
复制代码

这里需要注意几个点:

  1. :root 匹配的就是HTML中的 <html> 元素,具有最高的权重, :root 声明的变量就是全局变量;
  2. CSS自定义变量对大小写敏感, --color--Color 是两个变量;
  3. 变量必须声明在{}中,如果在这里把它理解为属性就更好记忆了,毕竟我们不会把CSS属性写到括号外边去;
  4. *号代表的就是我们给变量起的名字。起名字这事真的很烦人,还好CSS变量的名称限制很少,除了一些特殊关键字符不能使用,正常来说你用数字/字母/下划线_/短横线-都是没问题的,据说还可以使用中文、日文和韩文。
:root{
    --黑色:#000;
}

body{
    background: var(--黑色);
}
复制代码

手贱如我试了一下,真的可以识别。但是,为了世界和平请答应我不要这么写。

(三)使用变量

很简单,就是我们很熟悉的 var 关键字。

/* 定义变量 */
:root{
    --*: #000;
    /* 例如 --color-bg: #000; */
}

/* 使用变量 */
body{
    background: var(--*);
    /* 例如 background: var(--color-bg); */
}
复制代码

还有一种设置默认值的使用,就是在变量名称后面,加上一个默认值。

.div{
    background: var(--变量名称,[默认值]);
    /* 例如 background: var(--color-bg, #000); */
}
复制代码

也就是说,当这个变量没有被声明过的话,就会使用默认值,不至于没着没落的。

注意这里的情况是变量没有被声明过,要是变量是声明过的,但是使用起来是不合法的,那么就会采用原来属性的缺省默认值,并不是后面这个你设定的默认值。

p{
    background-color: var(--color, #000);
    /* --color没有声明过,所以这里的p元素背景颜色时候用了默认值#000 */
}
复制代码
div{
    --color: 20px;
    background-color: var(--color, #000);
    /* 很明显,background-color: 20px;是有语法错误的,所以这里div的背景色为透明,取的是这个属性的默认值 */
}
复制代码

(四)作用域和权重

1、如果你需要定义一个全局的变量,那么可以放在 :root 根元素下面;

2、如果只需要在部分元素/组件下使用,就定义在相关的类下面;

3、另外还可以在 @media 媒体查询中或者 :hover 等伪类中使用。

理解了作用域,那么权重也是同样的道理,因为CSS自定义变量是可以继承的,所以权重跟我们平时的属性权重理解是一样的。

这里引用一下张鑫旭大神的例子给大家出道题。

:root{
    --color: purple;
}
div{
    --color: green;
}
#alert{
    --color: red;
}
*{
    color: var(--color);
}
复制代码
<p>请问我是什么颜色</p>
<div>请问我是什么颜色</div>
<div id="alert">
    请问我是什么颜色
    <p>请问我是什么颜色</p>
    <p style="--color: grey;">请问我是什么颜色</p>
</div>
复制代码

答案如下:

[CSS] 自定义变量带你随心所欲,一键换肤

(五)变量的其他组合

除了上述的一些用法,CSS自定义变量也可以使用 calc() 函数进行计算,或者进行字符串拼接。

这里举了三个例子,具体的说明在注释中。

p{
    --fz: 50;
    font-size: var(--fz)px;
    /* 不要太天真,这样是错的 */
}
复制代码
p{
    --fz: 50;
    font-szie: calc(var(--fz) * 1px);
    /* 如果你一定要这么用,可以使用calc计算函数 */
}
复制代码
p::after{
    --text: "hellp";
    content: var(--text) " word";
    /* 但是字符串的拼接是可以实现的 */
}
复制代码

当然,变量不止可以直接使用,直接或者通过计算把值传递给另一个变量也是可行的。

p{
    --fz: 20px;
    --fz-lg: var(--fz);
    font-size: var(--fz-lg);
    /* 直接传递 */
}
复制代码
p{
    --fz: 20px;
    --fz-lg: calc(var(--fz) * 1.5);
    font-size: var(--fz-lg);
    /* 通过计算后传递 */
}
复制代码

二、在JS中使用

读:getPropertyValue( )

写:setProperty( )

比如说,你在 :root 上定义了一个color变量,用于设置页面的主题色,那么通过下面的JS,你就可以很简单地改变color变量的值,从而改变页面的主题色。换个皮肤,so easy。

// 读取数据
const rootStyles = getComputedStyle(document.documentElement);
const varValue = rootStyles.getPropertyValue('--color').trim();

// 改写数据
document.documentElement.style.setProperty('--color', value);
复制代码

当然用处不止用来换肤,充分发挥你的想象力,看看CSS变量与JS的结合能产生什么样奇妙的效果~附上大漠老师的小DEMO。

[CSS] 自定义变量带你随心所欲,一键换肤

应用CSS自定义变量

介绍了这么多,那么CSS自定义变量到底都在什么场景下应用呢?

一、CSS禅意花园

最强的应用当然是一键换肤啦!

一般情况下,我们若是想根据不同的合作方或者不同的应用更换主题颜色,一般使用预处理器先定义一个全局主题颜色,如:

$theme-color: #f00;

button{
    background: $theme-color;
}
复制代码

最后编译得到一个定制的CSS文件,如:

button{
    background: #f00;
}
复制代码

这样我们就可以通过引入这个特殊的CSS文件,得到一套主题色为红色的页面样式。

第一种形式适用于,功能通用但是最后根据配置输出 一个产品的独立管理台一个独立小程序 等,这样用自己一套独有的CSS文件就很方便。

但是如果我们提供一个通用的产品去接入不同的合作方,接入方都有定制主题的需求,就可以选择预处理器或CSS自定义属性。

/* 预处理器方式,先定义不同的主题色 */
$theme-color-a: #f00;
$theme-color-b: #0f0;

/* 在页面层级最外层加上定制的类名,类名中所有样式都需要重新覆盖一遍 */
.project-a{
    button{
        background: $theme-color-a;
    }
    a{
        color: $theme-color-a;
    }
}
.project-b{
    button{
        background: $theme-color-b;
    }
    a{
        color: $theme-color-b;
    }
}

/* 或者在媒体查询中需要重置样式 */
$fz-sm: 12px;
$fz-md: 14px;

button{
    font-size: $fz-sm;
}
a{
    font-size: $fz-sm;
}

@media (min-width: 375px){
    button{
        font-size: $fz-md;
    }
    a{
        font-size: $fz-md;
    }
}
复制代码
:root{
    --FZ: 12px;
}
/* 照常写一套样式 */
button{
    background: var(--THEME-COLOR, #fff);
}
a{
    color: var(--THEME-COLOR, #fff);
}

/* 根据不同的接入方设置主题色 */
.project-a{
    --THEME-COLOR: #f00;
}
.project-b{
    --THEME-COLOR: #0f0;
}

@media (min-width: 375px){
    :root{
        --FZ: 14px;
    }
}
复制代码

这种需求在CSS预处理器中无法实现一个没有复制代码的方案,总是需要覆盖实现的值和规则,这也经常会导致CSS冗余。

使用CSS自定义属性,解决方案是尽可能的简洁,也避免复制和粘贴代码,因为只要重新定义变量的值,不需要去覆盖一次样式。

第二种方式中两个方式的区别则是,预处理器中变量的作用域是无法继承的,而CSS自定义变量则相对灵活,这样一旦接入方多了之后,两种方式的代码量就会有质的区别。

以上两种方式都还是直接把主题色配置在CSS中。但是如果需要接入管理台,让合作方直接在管理台设置主题色的话,预处理器这种静态的方式就直接退出了竞争,CSS自定义属性的绝对优势就出来了。

:root{
    --THEME-COLOR: #fff;
}
button{
    background: var(--THEME-COLOR);
}
a{
    color: var(--THEME-COLOR);
}
复制代码
let value = #f00; //或者通过请求获取配置的主题色
document.documentElement.style.setProperty('--THEME-COLOR', value);
复制代码

第三种方式则非常灵活,我们可以通过管理台或者其他配置的方式,传递合作方主题色,一键应用即可。

历史性的时刻诞生了,从此接入就是分分钟的事,直接读取管理台的配置,更改CSS自定义属性。来个小DEMO体验一下吧。

[CSS] 自定义变量带你随心所欲,一键换肤
codepen.io/Apollozz/pe…

二、主题色处理

预处理器提供了很多高级的颜色方法,可以实现颜色的高亮、变暗或去饱和等等;

$color: #f00; 

.lighten{
    background: lighten($color,10%);
}
.darken{
    background: darken($color,10%);
}
.desaturate{
    background: desaturate($color,10%);
}
复制代码

这样编译出来的结果就是

.lighten{
    background: #ff3333;
}
.darken{
    background: #cc0000;
}
.desaturate{
    background: #f20d0d;
}
复制代码

这些方法无法直接使用在CSS自定义属性中,但是我们可以通过rgb( )或者hsl( )来调整主题颜色的色调或亮度。

(一)使用rgb改变颜色

rgb颜色变亮变暗的原理相对简单,只需修改 --COLOR-R / --COLOR-G / --COLOR-B 的值,利用calc函数对rgb的值进行线性增减即可。

:root{
  --COLOR-R: 25;
  --COLOR-G: 153;
  --COLOR-B: 112;
  --DARKEN: 30; // 加深程度
  --LIGHTEN: 30; // 变亮程度
  --THEME-COLOR: rgb(var(--COLOR-R), var(--COLOR-G), var(--COLOR-B));
  --THEME-COLOR-DARKEN: rgb(calc(var(--COLOR-R) - var(--DARKEN)), calc(var(--COLOR-G)  - var(--DARKEN)), calc(var(--COLOR-B) - var(--DARKEN)));
  --THEME-COLOR-LIGHTEN: rgb(calc(var(--COLOR-R) + var(--LIGHTEN)), calc(var(--COLOR-G)  + var(--LIGHTEN)), calc(var(--COLOR-B) + var(--LIGHTEN)));
}
复制代码
[CSS] 自定义变量带你随心所欲,一键换肤
codepen.io/Apollozz/pe…

(二)使用hsl改变颜色

rgb我们可能相对熟悉,但是hsl用得比较少,下面简单介绍一下hsl的原理,详细内容请点击链接。

与RGB使用的三色光不同,HSL同样使用了3个分量来描述色彩,HSL色彩的表述方式是:H(hue)色相,S(saturation)饱和度,以及L(lightness)亮度。

HSL的H(hue)分量,代表的是人眼所能感知的颜色范围,这些颜色分布在一个平面的色相环上,取值范围是0°到360°的圆心角,每个角度可以代表一种颜色。

HSL的S(saturation)分量,指的是色彩的饱和度,它用0%至100%的值描述了相同色相、明度下色彩纯度的变化。数值越大,颜色中的灰色越少,颜色越鲜艳,呈现一种从理性(灰度)到感性(纯色)的变化。

HSL的L(lightness)分量,指的是色彩的明度,作用是控制色彩的明暗变化。它同样使用了0%至100%的取值范围。数值越小,色彩越暗,越接近于黑色;数值越大,色彩越亮,越接近于白色。

一般来说,我们需要按钮在hover状态时加深颜色,此时应用的原理是将颜色的hsl值中的L也就是亮度调低。

:root{
  --COLOR-H: 29;
  --COLOR-S: 100;
  --COLOR-L: 50;
  --DARKEN: 0.15;
  --THEME-COLOR: hsl(var(--COLOR-H), calc(var(--COLOR-S) * 1%), calc(var(--COLOR-L) * 1%));
  --THEME-COLOR-DARKEN: hsl(var(--COLOR-H), calc(var(--COLOR-S) * 1%), calc(var(--COLOR-L) * (1 - var(--DARKEN)) *  1%));
  --THEME-COLOR-LIGHTEN: hsl(var(--COLOR-H), calc(var(--COLOR-S) * 1%), calc(var(--COLOR-L) * (1 + var(--DARKEN)) *  1%));
}
复制代码
[CSS] 自定义变量带你随心所欲,一键换肤
codepen.io/Apollozz/pe…

(三)使用遮罩改变颜色

如果不通过改变色值来改变颜色的话,可以选择遮上一个半透明的蒙层来改变颜色,加深颜色则选择黑色半透明蒙层,提亮颜色则选择白色半透明蒙层。

.button_color{
    position: relative;
    color: #fff;
    background: var(--THEME-COLOR);
    border: 1px solid var(--THEME-COLOR);
    &:after{
        content: "";
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        transition: all 0.2s;
    }
    /* 黑色半透明蒙层 */
    &:hover:after{
        background: rgba(0,0,0,0.05);
    }
    /* 白色半透明蒙层 */
    &.lighten:hover:after{
        background: rgba(255,255,255,0.1);
    }
}
复制代码
[CSS] 自定义变量带你随心所欲,一键换肤
codepen.io/Apollozz/pe…

三、兼容性

目前CSS自定义变量的兼容性还是比较可观的,新的主流浏览器都支持。

PC端主要是IE这块硬石头,而移动端则主要是低端机型系统例如ios9.2及以下/安卓4.4及以下不支持,这样的兼容性已经足以允许让我们在项目中开始使用CSS自定义属性,并对一些低端版本进行降低兼容处理。

[CSS] 自定义变量带你随心所欲,一键换肤

对于不支持的浏览器可以采用下列兼容方式:

方案1:直接设置一个默认颜色

直接使用普通的属性定义,兼容所有的浏览器,保证显示正常。

button{
    background: #F00;
    /* 默认颜色,若不支持CSS自定义属性则应用该默认颜色 */
    background: var(--THEME-COLOR, #F00);
    /* 在实践中发现有些机型虽然能识别到CSS自定义变量但是无法获取正确颜色,只能获取到默认值 */
}
复制代码

方案2:CSS根据@supports判断是否兼容并适配

低端机型也无法正确识别@supports,@supports的兼容性只比CSS自定义变量好一丢丢。

@supports ( (--a: 0)) {
  /* supported */
}

@supports ( not (--a: 0)) {
  /* not supported */
}
复制代码

方案3:js根据@supports判断是否兼容并适配

const isSupported =
  window.CSS &&
  window.CSS.supports &&
  window.CSS.supports('--a', 0);

if (isSupported) {
  /* supported 引入支持自定义变量的CSS,允许更改CSS自定义变量 */
} else {
  /* not supported 引入兼容的CSS文件 */
}
复制代码

四、注意事项

  1. 在一些浏览器中,针对CSS变量的复杂 calc() 运算可能不能工作;
  2. 进行 calc() 运算时,最好能提供默认值: calc(var(--base-line-height, 0) * 1rem)
  3. 不能作为媒体查询值使用:
@media screen and (min-width: var(--desktop-breakpoint) ) { 
};
复制代码
url( var(--image-url) )
html
.container{
    --THEME-COLOR: #f00;
}
复制代码
<view class="container" style="--THEME-COLOR: #0f0;"> 
    <!-- 该结构下的元素,重置为行内样式的主题色 -->
</view>
复制代码

五、小结

  1. CSS自定义变量目前已支持各主流浏览器,低端版本可以采用兼容方案;
  2. SCSS变量和CSS自定义变量有本质上的区别,用来解决不同场景下的问题,CSS自定义属性用于动态主题,预处理器变量用于静态模板,项目中可以根据情况结合运用效果更佳;
  3. 在媒体查询中使用自定义变量的话,这样响应式设计相关的逻辑与正常的设计虽然分离,但是无论我们在哪里看到var( )声明语句,我们都能很明显的知道这个属性会发生变化。而使用传统的CSS方式,我们是无法察觉这一点的,这样代码的可读性就高了很多。

参考资料

  1. 【译】CSS自定义属性的策略指南
  2. 深入学习CSS自定义属性
  3. 小tips:了解CSS/CSS3原生变量var

以上所述就是小编给大家介绍的《[CSS] 自定义变量带你随心所欲,一键换肤》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

注意力商人

注意力商人

吳修銘 / 黃庭敏 / 天下雜誌 / 2018-4-2 / NT$650

電子郵件,免費!照片分享,無上限! 你是否想過,隨手可得的免費內容、便利的免費服務,到底都是誰在付費? 如果商品免費,那你就不是消費者,而是商品! 你我可能都不知不覺地把自己賣給了注意力商人! 「『媒體轉型、網路演化與資訊浪潮」此一主題最具洞見的作者。』──黃哲斌(資深媒體人) 「這是少有的關注產業發展的傳播史,對現在或未來的『注意力產業』」中人來說,不可不讀。」──......一起来看看 《注意力商人》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具