前言
其实CSS Variables并不是最近才出现的新生事物,早在2012年W3C就已经公布了CSS Variables的首个公开草案;2017年3月微软_Edge_浏览器也宣布支持 CSS 变量,此时所有主要浏览器都已经支持这个 CSS 新功能。
CSS Variables本质是定义一系列样式属性,本质上和 color 和 font-size 属性是一样的,只是没有默认含义,且可以被其他属性引用,并且提供了 JavaScript 基层API进行管理。因此 CSS Variables 天生就是为动态主题而生的,能够在运行时直接以简洁明了,灵活的方式调整页面样式。
Antd 在antd@4.17.0-alpha.0推出了实验性的动态主题方案,就是采用 CSS Variables 的方式来实现的,接下来本文将结合 Antd动态主题 来仔细探究 CSS Variables 和动态主题的内在联系。
本文分为CSS Variables基础和Antd动态主题底层探究两部分,依据循序渐进的方式,先介绍基础原理,再介绍动态主题的底层原理,已经熟悉基础原理的同学请跳过这一部分,直接进入干货部分。
CSS Variables基础
1、变量声明
声明变量时,变量名之前必须加两个连词线(--),之所以使用--这个符号来表示,是因为$被 Sass 用掉了,@ 被 Less 用掉了。
html {--ant-primary-color: #1890ff;--ant-primary-color-hover: #40a9ff;--ant-primary-color-active: #096dd9;--ant-primary-color-outline: rgba(24, 144, 255, 0.2);
}
后续的单词一般采用HTML的属性的声明方式,使用 - 进行链接。
CSS Variables 又叫做CSS 自定义属性,它的值类型和 CSS 属性值的类型是一样的,可以放入字符串、色值、时间等。
变量名大小写敏感,--header-color和--Header-Color是两个不同变量。
@keyframes waveEffect {100% {box-shadow: 0 0 0 var(--cmsAnt-primary-color);box-shadow: 0 0 0 6px var(--antd-wave-shadow-color);}
}
@media screen and (min-width: 768px) {body {--primary:#F7EFD2;--secondary: #7F583F;}
}
并且支持在响应式布局@media和动画@keyframes中使用。
同样支持变量依赖声明。
html {--antd-wave-shadow-color: var(--ant-primary-color);--scroll-bar: 0;
}
2、var()函数
var()是用于读取变量,并且支持第二个参数作为默认值,这是个很棒的设计。
color: var(--foo, #7F583F);
以下是注意事项:
- 1、 读取变量值只能作用于属性值,而不能作用于属性名。
.foo {--side: margin-top;/* 无效 */var(--side): 20px;
}
- 2、可以字符串拼接,但是带单位的变量值不可以拼接
body:after {content: '--screen-category : 'var(--screen-category);
}
假如假如需要带单位,则需要使用calc()函数。
.foo {--gap: 20;/* 无效 */margin-top: var(--gap)px;/* 有效 */margin-top: calc(var(--gap) * 1px);
}
如果变量值带有单位,就不能写成字符串。
/* 无效 */
.foo {--foo: '20px';font-size: var(--foo);
}
/* 有效 */
.foo {--foo: 20px;font-size: var(--foo);
}
3、作用域
同一个 CSS 变量,可以在多个选择器内声明。读取的时候,优先级最好的声明生效。
<style> html {--color: pink;}:root { --color: blue; }div { --color: green; }#alert { --color: red; }* { color: var(--color); } </style>
<p>蓝色</p>
<div>绿色</div>
<div id="alert">红色</div>
:root除了优先级更高之外,其他和html保持一致,因此p标签生效的是:root的作用域的变量定义,如果想对动态主题进行强制覆盖,目前动态主题方案一般是使用html作用域下,则可以使用:root作用域声明进行强制覆盖。
选择器的优先级则是按照 html < div < ID 选择器。
4、兼容性处理
CSS variables在一些旧版本主流浏览器或者IE浏览器是无法使用的,可以采用以下写法进行规避。
a {color: #7F583F;color: var(--primary);
}
或者使用@supports进行检测。
@supports ( (--a: 0)) {/* supported */
}
@supports ( not (--a: 0)) {/* not supported */
}
5、JavaScript 操作
首先 JavaScript 可以检测浏览器是否支持 CSS 变量。
const isSupported =window.CSS &&window.CSS.supports &&window.CSS.supports('--a', 0);
if (isSupported) {/* supported */
} else {/* not supported */
}
JavaScript API 写法。
// 设置变量
document.body.style.setProperty('--primary', '#7F583F');
// 读取变量
document.body.style.getPropertyValue('--primary').trim();
// '#7F583F'
// 删除变量
document.body.style.removeProperty('--primary');
这里补充一些其他文章没有提到的信息。
首先<style>内定义的样式变量,无法通过 JavaScript API 来获取。
// 在作用域的例子中,执行下面的逻辑
document.querySelector(':root').style.getPropertyValue('--color')
// 返回 ''
document.querySelector(':root').style.setProperty('--color', 'gray')
// 返回 undefined 并且字体颜色变成灰色
document.querySelector(':root').style.getPropertyValue('--color')
// 返回 'gray'
到这里大家就明白了其内在限制了。
Antd 动态主题底层探究
首先看下 Antd 动态主题的文档,最主要的改动是修改引入的样式文件。
-- import 'antd/dist/antd.min.css';
++ import 'antd/dist/antd.variable.min.css';
本文抓取了最终引入的文件内容如下:
html {--ant-primary-color: #1890ff;--ant-primary-color-hover: #40a9ff;--ant-primary-color-active: #096dd9;...
}
...
a {color: var(--ant-primary-color);text-decoration: none;background-color: transparent;outline: none;cursor: pointer;transition: color 0.3s;-webkit-text-decoration-skip: objects;
}
...
这里就显而易见了,底层就是CSS Variables的设计。下面的语法实际也是对上面的 CSS Variables 的修改。
ConfigProvider.config({ prefixCls: 'custom', theme: { primaryColor: '#25b864', }, });
到这里你是不是会疑惑?CSS Variables 是不是唯一的动态主题实现方案?实际上并不是的,antd-theme-generator库就是就是基于 Less api 的动态主题方案,有兴趣的可以详细看下我的另外一篇文章《高度兼容低版本的 antd 的动态主题方案》。这篇文章具体介绍antd-theme-generator库的优缺点以及如何解决其中的问题落实到实际项目中去。
CSS Variables 是不是唯一的动态主题实现方案?
正如上面所说,Less 基础 API 也对样式变量进行了支持,而且相对于CSS Variables的语法丰富度更高。以 Antd Button 的样式文件为例。
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './mixin';
@btn-prefix-cls: ~'@{ant-prefix}-btn';
// for compatible
@btn-ghost-color: @text-color;
@btn-ghost-bg: transparent;
@btn-ghost-border: @border-color-base;
// Button styles
// -----------------------------
.@{btn-prefix-cls} {&-primary {.btn-primary();.@{btn-prefix-cls}-group &:not(:first-child):not(:last-child) {border-right-color: @btn-group-border;border-left-color: @btn-group-border;&:disabled {border-color: @btn-default-border;}}}
}
如果你直接在HTML中引入类似上面 less 样式文件,
<script> less = { env: "development" }; </script>
<script src="less.js" data-env="development"></script>
那么你就可以通过下面的语法进行样式动态调整。
less.modifyVars({'@buttonFace': '#5B83AD','@buttonText': '#D9EEF2',
});
只是大家日常为了做到更好的浏览器兼容,没有直接使用 less 样式文件,都是使用经过编译后的 css 文件。
这里还要提到一点就是 Less 命令行支持 Less variables 到 CSS Variables 的转换,这个就相当实用,例如在 Antd 动态主题中提到可以使用以下命令重新生成一份新前缀的 css 文件。
lessc --js --modify-var="ant-prefix=custom" antd/dist/antd.variable.less modified.css
更多的命令可以参考 Less 官网命令行使用。
结语
到这里为止,本文分析了 CSS Variables 和动态主题互为表里的关系,有道是纸上得来终觉浅,绝知此事要躬行,大家可以在实际项目中可以多体验下动态主题的相关方案,毕竟动态主题的用户体验要远远高于传统的主题定制。
就我自己的使用体验而言,相对于传统静态主题定制的方式,动态主题在实际使用过程中也存在以下局限性的。
- 性能差,无法进行压缩、混淆,文件体积大
- 和
css in js的思想有一定的冲突,无法使用css module,实际代码开发体验不好 - 不适用于微前端等应用场景,CSS 隔离会遇到很大的麻烦
- 兼容性差
因此在决策是否使用动态主题时,还是要从自身项目的实际需要进行综合考量的,按需选取。
最后
整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。




有需要的小伙伴,可以点击下方卡片领取,无偿分享
Nodejs 高并发原理详解
本文探讨Nodejs实现高并发的原理,首先回顾CSS Variables的基础知识,包括变量声明、函数、作用域、兼容性和JavaScript操作。接着深入分析Antd动态主题的底层实现,指出动态主题并非唯一方案,并对比了与Less变量的支持。最后,讨论动态主题的局限性和适用场景,提醒开发者在项目中综合考量选择。
270

被折叠的 条评论
为什么被折叠?



