Obeta

CSS4 Custom properties

Custom properties (自定义属性), 它补充了css语言中最大的不足--不支持变量. 避免了我们到处复制和粘贴代码,并简化了开发和重构的成本.

这是 css 的一个实验性属性,还未得到大部分浏览器厂商的认同或者各自实现方式不一致,且属性不稳定,后期说不定就会改掉,因此不建议在生产环境上实用.

来源于caniuse

IE 全挂,因此如果你的网站大部分客户有使用 IE 的话,建议别使用这个特性.

为何需要使用变量

由于 css 并不算一门真正的编程语言,因此使用 css 时候相信很多人都使用过 CSS 预处理器,而变量是 CSS 预处理器存在的主要原因之一,为某种颜色设置一个变量的能力,这非常有用.出于同样的原因,你可以使用 CSS 本来就支持的 CSS 变量(CSS Custom properties),但也有一些重要的区别需要明确。

一个简单的预处理器

// scss
$brandColor: #f06d06;

.main-header {
	color: $brandColor;
}
.main-footer {
	background-color: $brandColor;
}

上面那些 css 并不会理解到写的是什么,所以我们需要进一步进行处理,scss 预处理器将会把上面这部分转换为 css:

.main-header {
	color: #f06d06;
}
.main-footer {
	background-color: #f06d06;
}

现在就是合法的 css 格式了,css 预处理器有很多,比如Stylus,Less,PostCSS,Scss,Sass等等.

Custom properties

现在开始介绍一下 css 自带的自定义变量特性了.

:root {
	--main-color: #f06d06;
}

.main-header {
	color: var(--main-color);
}
.main-footer {
	background-color: var(--main-color);
}

这不需要预处理器进行转换,如果你的浏览器足够新,那么它是可以理解并使用的.

跟大多数语言一样,变量是有作用域的,:root中的变量是全局作用域,也就是哪里都可以使用,我们也还可以使用局部的变量:

:root {
	--main-color: #f06d06;
}

.main-header {
	--main-color: #fff;
	color: var(--main-color);
}
.main-footer {
	background-color: var(--main-color);
}

此时.main-header中的变量覆盖了:root的变量.

为了保证开发时候不会出现意外覆盖的情况,建议对于全局变量加上特殊的前缀,比如--global-main-color.

我们还可以使用自定义变量做很多事情:

:root {
	/* --global-concept-size */
	--global-spacer-sm: 0.5rem;
	--global-spacer-md: 1rem;
	--global-spacer-lg: 2rem;

	/* --global-concept-PropertyCamelCase */
	--global-main-title-FontSize: 2rem;
	--global-secondary-title-FontSize: 1.8rem;
	--global-body-FontSize: 1rem;

	/* --global-state-PropertyCamelCase */
	--global-hover-BackgroundColor: #ccc;
}

如何选择

那么,我们到底使用预处理器还是说使用自定义变量呢?

首先我们来看看使用自定义变量的好处有哪些?

  • 你不需要预处理器处理.
  • 支持覆盖,你可以在任何选择器中设置一个变量来设置或覆盖它的当前值.
  • 当它们的值发生变化时(例如媒体查询或其他状态),浏览器就会根据需要重新绘制.
  • 你可以用JavaScript访问和操纵它们

你可以点击这里看看如何通过 js 操控自定义变量,关键的地方在于这行:

document.documentElement.style.setProperty('--global-main-color', '#fff');

那么预处理器的好处呢:

  • 不需要考虑浏览器的支持情况,比如IE.
  • 更多的函数支持,更像编程语言.
  • 更多的功能使用.

现在看起来好像都很不错,那么怎么办呢?

那就都用起来!

比如 scss:

css4: true;
$compatibility: true;
//it is nessesary to define the variables in sass map instead of :root, for compatibility reasons.
$variables: (
	--color: white,
	--background: skyblue,
	--font: sans-serif,
);

//如果支持css4
@if ($css4) {
	:root {
		@each $variable, $value in $variables {
			#{$variable}: $value;
		}
	}
}

//这是一个魔法函数,hack了var,使向下兼容IE
@function var($variable) {
	@if ($css4) {
		@return unquote('var(' + $variable + ')');
	} @else {
		@return map-get($variables, $variable);
	}
}

//the mixin temporally sets the $css4 variable to false, compiles the css3 fallback, then makes the variable true again and compiles the css4 code. It should contain properties that use css4 variables, otherwise there will be unnessesary duplication of properties.
@mixin css4 {
	@if ($css4) {
		$css4-backup: $css4;
		@if ($compatibility) {
			$css4: false !global;
			@content;
		}
		$css4: true !global;
		@content;
		$css4: $css4-backup;
	} @else {
		@content;
	}
}

//the body does not use fallback, its styles will be visible only in compatible browsers
body {
	max-width: 500px;
	margin: 0 auto;
	padding: 30px;
	color: var(--color);
	background: var(--background);
	font: {
		family: var(--font);
	}
}

// the p and button tags uses the css4 mixin so a fall-back is provided and they will work on all browsers.
p {
	text-align: justify;
	@include css4 {
		color: var(--color);
	}
}

button {
	@include css4 {
		background: var(--color);
		color: var(--background);
		border: 2px solid currentcolor;
		box-shadow: 0 0 0 5px var(--color);
	}
	&:hover {
		@include css4 {
			background: var(--background);
			color: var(--color);
			box-shadow: 0 0 0 5px var(--background);
		}
	}
}

具体请看

参考文章:

个人随笔记录,内容不保证完全正确,若需要转载,请注明作者和出处.