CSS 现在有了自定义属性。 我们最近 写了很多关于它们的文章。 浏览器支持 良好,但当然,像 Internet Explorer 这样的旧版非 Evergreen 浏览器不支持它们,并且永远不会支持。 我可以理解使用“未来 CSS”进行创作的吸引力,并让预处理器将其回传到与旧版浏览器兼容的 CSS。 CSS 的 Babel!为什么不呢?!
不过,这让我感到不安——因为只有某些自定义属性的用例可以进行预处理。 在很多情况下,您对自定义属性的操作根本无法进行预处理。 因此,如果您这样做,您将陷入非常奇怪的境地。
如果您处于可以预处理它们并获得预期结果的情况,那么您可能应该只使用预处理器变量。
预处理器无法理解 DOM 结构
直到构建完整的 DOM 的“运行时”,CSS 才会应用。 更不用说任何给定 CSS 文件很可能只是影响页面的众多文件之一。
postcss-custom-properties 可能是最流行的自定义属性预处理器(它与 cssnext 捆绑在一起),它只允许您在:root
中设置变量,例如
:root {
--backgroundColor: white;
}
.header {
background-color: var(--backgroundColor);
}
但也许 CSS 自定义属性最有用的一点是它们可以在级联中使用。 这是一个人为的例子,但您会明白我的意思
:root {
--backgroundColor: white;
}
.header {
background-color: var(--backgroundColor);
}
.header.is-about-page {
--backgroundColor: yellow;
}
使用 postcss-custom-properties,它将处理根变量,但不会处理状态变化,从而留下一些非常无用的 CSS
.header {
background-color: white;
}
.header.is-about-page {
--backgroundColor: yellow;
}
他们意识到了这一点
转换不完整,并且无法完成(基于自定义属性的动态级联变量依赖于 DOM 树)。 它目前只是旨在提供一种面向未来的方法来使用原生 CSS 自定义属性提供的功能的有限子集(到
:root
选择器)。 由于我们不知道此插件上下文中 DOM,因此我们无法生成安全输出。
您可以阅读关于所有这些的有趣对话,例如这个。
还有一个名为 postcss-css-variables 的自定义属性处理器试图做更多的事情。 例如
.header {
background-color: var(--backgroundColor, white);
}
.header:hover {
--backgroundColor: orange;
}
.header.is-about-page {
--backgroundColor: yellow;
}
输出
.header {
background-color: white;
}
.header:hover {
background-color: orange;
}
它可以正确处理悬停,但仍然放弃了声明的选择器。
这两个插件都同意:在 CSS 预处理器中根本无法完美复制 CSS 自定义属性的功能。
因此,如果您这样做,您要么必须限制自己使用它们的方式,要么获得不正确的结果。
您将失去使用 JavaScript 更改它们的能力
除了级联之外,CSS 自定义属性的另一个杀手级功能是能够使用 JavaScript 更改它们。 因此,与其使用 JavaScript 查询 DOM 以获取您需要更改的 X 个事物并分别更改所有事物,不如只更改一个自定义属性,并使其按预期渗透。
通过预处理 CSS 自定义属性,它们在处理后的 CSS 中不存在,因此您将失去此功能。
何时关闭它?
也许您只是将此预处理视为权宜之计。 在某些时候,您将关闭它,然后原生交付自定义属性。 您需要做一些工作以确保
- 原生处理方式与预处理器处理方式完全相同
- 预处理过程的其他任何部分都不会被它们混淆
- 您的回退方案很可靠,如果您仍然需要在不支持它们的浏览器中获得可行的体验
🙃
抱歉,我知道这感觉像是我在批评别人的东西。 实际上,我认为像这样的探索非常酷,值得去做和分享。 制作它们的人毫无疑问比我聪明。
有些人对此感到兴奋。 Mike Street
我在一家必须支持跨浏览器(包括 IE11,不幸的是)的代理机构工作。 尽管我们还无法在生产环境中完全使用 CSS 变量,但它们在开发和将其后处理为原始属性方面提供了许多优势。
我们的 gulp 进程包括 postcss-css-variables,它将样式表中的任何 CSS 变量更改为您为其设置的值。 类似于 SCSS 变量(以相同的方式进行处理),但允许您编写更小的 SCSS,并且在时机成熟时,删除处理并使用已就位的自定义属性部署样式表。
我只是认为分享一些谨慎的建议是值得的。 cssnext 的网站上有一条巨大的横幅写着“今天使用明天的 CSS 语法”,我担心这种营销方式将一些看似简单的东西宣传得过于简单,而实际上它复杂且微妙。
如果您正在预处理自定义属性,您不妨使用实际的预处理器变量
无论如何,这对我来说似乎是一个明智的选择。
Sass、Less 和 Stylus 都有效果很好的变量。 它们甚至具有一定的作用域,尽管不如真正的级联强大。
如果您使用 PostCSS,则有一些 允许使用变量的插件,它们使用不与原生 CSS 语法重叠的语法。
Mike Street 有一个非常酷的用例,他通过对 CSS 自定义属性进行微小更改来翻转媒体查询中渐变的方向(这是 它们可以执行的超级有用的操作)。
div {
--direction: to bottom;
background: linear-gradient(
var(--direction),
rgba(0, 0, 0, 1) 0,
rgba(0, 0, 0, 0.1) 100%);
@media (max-width: 1000px) {
--direction: to right;
}
}
只有 postcss-css-variables(我认为)会尝试处理这个问题。 它简洁明了,但可以使用 SCSS 获得几乎相同的抽象级别 抽象级别。
@mixin specificGradient($direction) {
background: linear-gradient(
$direction,
rgba(0, 0, 0, 1) 0,
rgba(0, 0, 0, 0.1) 100%
);
}
div {
@include specificGradient(to bottom);
@media (max-width: 1000px) {
@include specificGradient(to right);
}
}
同时使用它们/立即处理回退
您可以完全使用任何预处理器和 CSS 自定义属性。
您甚至可以将某些内容(如您的$brandColor
等)保留为预处理器变量。 然后,同时利用 CSS 自定义属性来处理您将来可能需要动态化的内容。 您甚至可以立即处理回退,以便在处理过程中处理跨浏览器支持,而不是将其视为您正在预处理的内容。
$brandColor: #f06d06;
html {
background: $brandColor;
--base-font-size: 100%;
font-size: 100%;
font-size: var(--base-font-size);
}
是的,确实,出于这些确切的原因,我一直在使用 SCSS 类变量进行值预处理。 总结得很好。
它们的工作方式不同,它们的实际使用方法也不同,因此只需使用不同的工具来操作它们(SCSS 与 CSS/JavaScript)。
很好的观点,Chris。 作为一名 SCSS 用户,我也一直在纠结这个问题。 也就是说,“在哪里可以使用自定义属性代替 SCSS 变量?”,更重要的是,“何时可以开始使用它们?”
正如您指出的那样,自定义属性在利用级联时最强大。 我将其概括为:“自定义属性最适合可能更改的任何值。”
我特别期待使用自定义属性来设置列间距、标题字体大小和其他响应式变量。 使我们的 CSS 更简洁高效的机会对我来说真的令人兴奋。
我正在生产环境中使用它们和 SCSS,借助 css-vars sass 混合或另一种简单的方法实现 sass 回退
https://vgpena.github.io/winning-with-css-variables/
怀疑IE是否支持它们
我认为,文章中未提及的一个相关方面是,预处理器变量可以做什么而自定义属性做不到?我想到属性名称插值,但还有什么其他功能吗?
如果一个网站*不*使用任何这些额外功能,那么有没有理由不切换到自定义属性?
var()
语法有点繁琐,但这对于“转向标准”来说是一个小代价。换句话说,如果浏览器支持不允许你使用自定义属性的特殊功能,并且你*不需要*预处理器变量的特殊功能,那么选择两者实际上仅仅是个人偏好问题,对吗?
另一件深奥的事情是能够从预处理器变量中去除单位。
但更重要的是,上面提到的两个自定义属性预处理器在处理不支持的操作时有不同的方式。即使在我的简单测试中,一个保留了一些不再起作用的自定义属性代码(因为它预处理了其他部分),而另一个则全部删除了。因此,你需要非常清楚它如何处理 CSS 自定义属性的完全有效的浏览器用法,否则最终得到一些已删除或破坏其功能的处理后的代码。
我只是想知道是否有可能有一个 main.css 使用自定义属性,以及多个其他文件,其中只有一个文件在每个页面/类别/任何内容中加载,并且在这些文件中自定义属性获取其值。
例如。
main.css
home.css
contact.css
main.css 将用于每个页面,而 home.css 和 contact.css 仅用于相应的页面。
我使用自定义属性超过一年,使用 cssnext,从未觉得这是一个大问题。你只会失去在媒体查询中定义变量的灵活性,让你编写覆盖而不是仅仅更改变量。但这并不是让你减速的东西。我觉得我可以接受后退一步,更接近 CSS,并换取可持续的代码。