博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CSS Custom Properties 自定义属性
阅读量:5782 次
发布时间:2019-06-18

本文共 6823 字,大约阅读时间需要 22 分钟。

hot3.png

为何要使用CSS自定义属性?

因为css preprocessor在变量的使用上有局限性:

  1. 不能动态修改变量值

  2. 在渲染时无法参考DOM的结构

  3. 变量值不能被javascript引用

 

如何声明CSS自定义属性?

类似于css preprocessor 的variables, $ in Sass, @ in Less, css custom propertiy 使用 -- 声明一个属性

.box{  --box-color: #4d4e53;  --box-padding: 0 10px;}

 

如何使用CSS自定义属性?

使用var()函数

box
box div
.box{      --box-color:rgba(200, 10, 100, .5);      --box-padding: 0 10px;      padding: var(--box-padding);    }    .box div{      color: var(--box-color);    }

 

114931_thYA_2510955.png

 

如何设置默认值?作为var()函数的第二个参数

.box{  --box-color:#4d4e53;  --box-padding: 0 10px;  /* 10px is used because --box-margin is not defined. */  margin: var(--box-margin, 10px);}

 

CSS自定义属性的计算

使用calc()函数

:root{  --indent-size: 10px;  --indent-xl: calc(2*var(--indent-size));  --indent-l: calc(var(--indent-size) + 2px);  --indent-s: calc(var(--indent-size) - 2px);  --indent-xs: calc(var(--indent-size)/2);}

这里的:root代表html标签

如果使用了非单位数值(非px, rem等等),需要结合使用calc(),看下面的例子

:root{  --gap: 10;}.box{  padding: var(--spacer)px 0; /* DOESN'T work */  padding: calc(var(--spacer)*1px) 0; /* WORKS */}

 

CSS自定义属性的作用域和继承性

先来看看Sass变量的作用域

120052_AH8J_2510955.png

图片来源:smashingmagazine

可见,Sass变量的作用域依赖于代码的结构,然而css 自定义属性和css其他属性是一样的,是默认继承的(根据DOM的结构)

那么css 自定义变量的全局作用域在哪里?是:root

看个css 自定义属性的例子

html:

global
enclosing
closure

css:

Tip: .closure 继承了.enclosing的属性,但是font-size又是自己定义的,而且使用了.enclosing中定义的属性--enclosingVar

:root {  --globalVar: 10px;}.enclosing {  --enclosingVar: 20px;}.enclosing .closure {  --closureVar: 30px;  font-size: calc(var(--closureVar) + var(--enclosingVar) + var(--globalVar));  /* 60px for now */}

其实css写成下面这样效果也是一样的,因为class 是天然 cascading (根据DOM的结构)

:root {      --globalVar: 10px;    }    .enclosing {      --enclosingVar: 20px;    }    .closure {      --closureVar: 30px;      font-size: calc(var(--closureVar) + var(--enclosingVar) + var(--globalVar));      /* 60px for now */    }

 

到这里我们再来看看前面说到的css preprocessor 变量的三个问题

  1. 不能动态修改变量值

  2. 在渲染时无法参考DOM的结构

  3. 变量值不能被javascript引用

第一个,动态修改变量值,个人感觉这个没啥用,但css 自定义属性可以解决这个问题

:root {  --globalVar: 10px;}.enclosing {  --enclosingVar: 20px;}.enclosing .closure {  --closureVar: 30px;  font-size: calc(var(--closureVar) + var(--enclosingVar) + var(--globalVar)); /* 80px for now, --closureVar: 50px is used */    --closureVar: 50px;}

一旦修改了自定义的属性值,浏览器就会重新计算相关变量值

 

第二个问题,渲染时没有参考DOM结构

还是看例子吧,比如有这么个需求,默认情况下,字体大小为10px, 在“highlighted”class时字体大小为30px

html:

default
default highlighted

sass:

.highlighted {  $highlighted-size: 30px;}.default {  $default-size: 10px;  @if variable-exists(highlighted-size) {    font-size: $highlighted-size;  }  @else {    font-size: $default-size;  }}

结果:

095907_r5HG_2510955.png

分析:sass的结果是class=highlighted的文字的font-size还是为10px, 变量highlighted-size: 30px并没有起作用,这是为什么?

前面说过,css preprocessor变量的作用域是依赖于code的结构的,在.default{}的作用域中,访问.highlighted类中的变量,当然是未定义,所以font-size走else分支,使用default-size。为什么没有参考DOM结构呢?其实是因为sass变量的计算和处理都是在编译过程中,此时她完全不知道也无法知道DOM结果,所以,变量的作用域只能依赖于code的结构。

一个解决方法是.default{}加上.highlighted class:  .default.highlighted {}

但是css 自定义属性在作用域和属性的层级结构上却有天然的优势,她可以像css其他的属性一样,参考页面的DOM结构

css:

.highlighted {  --highlighted-size: 30px;}.default {  --default-size: 10px;    /* use the "default-size" except the "highlighted-size" is provided */  font-size: var(--highlighted-size, var(--default-size));}

 

结果:

101203_RY6e_2510955.png

第三个问题,css preprocessor 变量值不能被javascript引用

但css 自定义变量却可以使用getPropertyValue和setProperty()读、写变量值

/*** Gives a CSS custom property value applied at the element* element {Element}* varName {String} without '--'** For example:* readCssVar(document.querySelector('.box'), 'color');*/function readCssVar(element, varName){  const elementStyles = getComputedStyle(element);  return elementStyles.getPropertyValue(`--${varName}`).trim();}/*** Writes a CSS custom property value at the element* element {Element}* varName {String} without '--'** For example:* readCssVar(document.querySelector('.box'), 'color', 'white');*/function writeCssVar(element, varName, value){  return element.style.setProperty(`--${varName}`, value);}

 

CSS 属性4个常用属性值和all属性

css的属性有4个通用的属性值:initial, inherit, unset, revert, 它们也可以使用在css自定义属性上

  • initial: 缺省值,使用官方的css specification, 比如<p>元素,text-align为left;display为inline;
  • inherit: 使用父元素的属性值,如果父元素的该属性没有定义,就相当于revert的效果
  • unset: initial + inherti, 表示没定义时怎么办,有些属性会使用inherit,继承父元素的属性定义,比如color, 有些属性会使用initial,比如border
  • revert: 以前叫做“default”, 当任何属性值在作者的stylesheet都没有定义时,采用下面的顺序寻找属性值
  1. 用户定义的stylesheet
  2. useragent stylesheet
  3. unset

详情参考这篇文章,里面的例子很详细:http://126kr.com/article/7ssx9rd04t6

现在,假如有个需求,某个组件要使用模块化的样式,可以使用all属性

.my-wonderful-clean-component{  all: initial;}

上面的代码表示重置了my-wonderful-clean-component类的样式,所有元素的属性值都使用官方css specification中的定义,排除了inherit; 但是all对于css 自定义属性并不起作用

未来理想的样子:

.my-wonderful-clean-component{  --: initial; /* reset all CSS custom properties */  all: initial; /* reset all other CSS styles */}

 

浏览器支持情况

113516_6zTA_2510955.png

http://caniuse.com/#search=custom%20properties

 

CSS自定义属性使用javascript动态改变三维视图例子

核心css:

#world{    --translateZ:0;    --rotateX:65;    --rotateY:0;    transform-style:preserve-3d;    transform:translateZ(calc(var(--translateZ) * 1px)) rotateX(calc(var(--rotateX) * 1deg)) rotateY(calc(var(--rotateY) * 1deg));}

定义了三个变量,分别控制视图的缩放,x轴、y轴的旋转,通过监听鼠标的mousewheel和mouseover事件,动态改变这三个变量,实现视图的三维动态响应

核心js:

class css3dCube {  constructor() {    this.worldEl = document.querySelector('#world');    this.worldZ = 0;    this.worldXAngle = 0;    this.worldYAngle = 0;    this.bindEvents();  }  // CSS  updateView() {    this.worldEl.style.setProperty('--translateZ', this.worldZ);    this.worldEl.style.setProperty('--rotateX', this.worldXAngle);    this.worldEl.style.setProperty('--rotateY', this.worldYAngle);  }  // EVENTS  onMouseWheel(e) {    let delta;    if (e.detail) {      delta = e.detail * -5;    } else if (e.wheelDelta) {      delta = e.wheelDelta / 8;    } else {      delta = e.deltaY;    }    if (!delta) return;    this.worldZ += delta * 5;    // scroll/perspective check    if (this.worldZ > 300) {      this.worldZ = 300;    } else if (this.worldZ < -3000) {      this.worldZ = -3000;    } else {      e.preventDefault();    }    this.updateView();  };  onMouseMove(e) {    this.worldXAngle = (.5 - (e.clientY / window.innerHeight)) * 180;    this.worldYAngle = -(.5 - (e.clientX / window.innerWidth)) * 180;    this.updateView();  };  bindEvents() {    window.addEventListener('mousewheel', this.onMouseWheel.bind(this));    window.addEventListener('DOMMouseScroll', this.onMouseWheel.bind(this));    window.addEventListener('mousemove', this.onMouseMove.bind(this));  };}new css3dCube();

监听鼠标的变化,动态改变worldZ, worldXAngel, worldYAngel三个成员变量的值,然后通过updateView()方法修改DOM中元素的css 自定义属性值

详见:http://codepen.io/malyw/pen/xgdEQp

参考资料:

https://www.smashingmagazine.com/2017/04/start-using-css-custom-properties/?utm_source=frontendfocus&utm_medium=email

http://126kr.com/article/7ssx9rd04t6

转载于:https://my.oschina.net/u/2510955/blog/884260

你可能感兴趣的文章
XP 安装ORACLE
查看>>
八、 vSphere 6.7 U1(八):分布式交换机配置(vMotion迁移网段)
查看>>
php5编译安装常见错误和解决办法集锦
查看>>
我的友情链接
查看>>
JS中比较数字大小
查看>>
jQuery插件的开发
查看>>
基础,基础,还是基础之JAVA基础
查看>>
haproxy mysql实例配置
查看>>
MySQL 8.0 压缩包版安装方法
查看>>
JS prototype 属性
查看>>
iphone-common-codes-ccteam源代码 CCEncoding.m
查看>>
nginx中配置文件的讲解
查看>>
HTTP库Axios
查看>>
CentOS7下安装python-pip
查看>>
gen already exists but is not a source folder. Convert to a source folder or rename it 的解决办法...
查看>>
20个Linux服务器性能调优技巧
查看>>
填坑记:Uncaught RangeError: Maximum call stack size exceeded
查看>>
SpringCloud之消息总线(Spring Cloud Bus)(八)
查看>>
实时编辑
查看>>
KVO原理分析及使用进阶
查看>>