东莞网页设计:CSS自定义属性的策略指南

2019.08.13 mf_web

136

现在,所有现代浏览器都支持CSS自定义属性(有时称为“CSS变量”),人们开始在生产中使用它们。这很好,但它们与预处理器中的变量不同,我已经看到许多人在不考虑它们提供的优势的情况下使用它们的例子。

东莞网页设计自定义属性具有巨大的潜力,可以改变我们编写和构建CSS的方式,在较小程度上,我们如何使用JavaScript与UI组件进行交互。我不会专注于语法及其工作原理(为此我建议您阅读“ 是时候开始使用自定义属性 ”)。相反,我想深入了解如何充分利用CSS Custom Properties。

它们与预处理器中的变量有何相似之处?

自定义属性有点像预处理器中的变量,但有一些重要的区别。第一个也是最明显的区别是语法。

随着SCSS我们用一个美元符号来表示一个变量:

$smashing-red: #d33a2c;
复制

在Less中我们使用@符号:

@smashing-red: #d33a2c;
复制

自定义属性遵循类似的约定并使用--前缀:

:root { --smashing-red: #d33a2c; }.smashing-text { 
  color: var(--smashing-red);}
复制

自定义属性和预处理器中的变量之间的一个重要区别是,自定义属性具有不同的语法,用于分配值和检索该值。检索自定义属性的值时,我们使用该var()函数。

下一个最明显的区别在于名称。它们被称为“自定义属性”,因为它们确实是CSS属性。在预处理器中,您几乎可以在任何地方声明和使用变量,包括外部声明块,媒体规则,甚至作为选择器的一部分。

$breakpoint: 800px;$smashing-red: #d33a2c;$smashing-things: ".smashing-text, .cats";@media screen and (min-width: $breakpoint) {
  #{$smashing-things} {
    color: $smashing-red;
  }}
复制

使用自定义属性,上面的大多数示例都是无效的。

自定义属性具有相同的规则,可以将它们用作普通CSS属性。将它们视为动态属性而不是变量要好得多。这意味着它们只能在声明块中使用,换句话说,自定义属性绑定到选择器。这可以是:root选择器或任何其他有效选择器。

:root { --smashing-red: #d33a2c; }@media screen and (min-width: 800px) {
  .smashing-text, .cats {
    --margin-left:  1em;
  }}
复制

您可以在属性声明中使用值的任何位置检索自定义属性的值。这意味着它们可以用作单个值,作为简写陈述的一部分,甚至可以用在calc()方程内。

.smashing-text, .cats {
  color: var(--smashing-red);
  margin: 0 var(--margin-horizontal);
  padding: calc(var(--margin-horizontal) / 2)}
复制

但是,它们不能用于媒体查询或选择器:nth-child()。

您可能想了解更多有关语法和自定义属性如何工作的信息,例如如何使用回退值以及是否可以将变量分配给其他变量(是),但是这个基本的介绍应该足以理解其余的本文中的概念。有关自定义属性如何工作的详细信息,您可以阅读Serg Hospodarets编写的“ 这是开始使用自定义属性的时间 ”。

动态与静态

除了化妆品差异之外,预处理器和自定义属性中变量之间最显着的差异在于它们的范围。我们可以将变量称为静态或动态范围。预处理器中的变量是静态的,而自定义属性是动态的。

在涉及CSS的地方,静态意味着您可以在编译过程中的不同点更新变量的值,但这不能更改之前的代码值。

$background: blue;
.blue {
  background: $background;}$background: red;
.red {
  background: $background;}
复制

结果是:

.blue {
  background: blue;}.red {
  background: red;}
复制

一旦将其呈现给CSS,变量就会消失。这意味着我们可能会在.scss不知道HTML,浏览器或其他输入的情况下读取文件并确定其输出。自定义属性不是这种情况。

预处理器确实有一种“块范围”,可以在选择器,函数或mixin中临时更改变量。这会更改块内变量的值,但它仍然是静态的。这与块相关,而不是选择器。在下面的示例中,变量$background在.example块内更改。即使我们使用相同的选择器,它也会更改回块外的初始值。

$background: red;
.example {
  $background: blue;
  background: $background;}.example {
  background: $background;}
复制

这将导致:

.example {
  background: blue;}.example {
  background: red;}
复制

自定义属性以不同方式 在涉及自定义属性的地方,动态范围意味着它们受继承和级联的约束。该属性绑定到选择器,如果值更改,则会像任何其他CSS属性一样影响所有匹配的DOM元素。

这很棒,因为您可以使用伪选择器(例如悬停)或甚至使用JavaScript更改媒体查询中的自定义属性的值。

a {
  --link-color: black;}a:hover,
a:focus {
  --link-color: tomato;}@media screen and (min-width: 600px) {
  a {
    --link-color: blue;
  }}a {
  color: var(--link-color);}
复制

我们不必更改自定义属性的使用位置 - 我们使用CSS更改自定义属性的值。这意味着使用相同的自定义属性,我们可以在同一页面上的不同位置或上下文中具有不同的值。

全球与本地

除静态或动态之外,变量也可以是全局变量或本地变量。如果您编写JavaScript,您将熟悉它。变量既可以应用于应用程序内部的所有内容,也可以将其范围限制为特定函数或代码块。

CSS类似。我们有一些全局应用的东西和一些更本地化的东西。品牌颜色,垂直间距和排版都是您可能希望在您的网站或应用程序中全局和一致地应用的事例。我们也有当地的东西。例如,按钮组件可能具有小型和大型变体。您不希望这些按钮的大小应用于所有输入元素甚至页面上的每个元素。

这是CSS中我们熟悉的。我们开发了设计系统,命名约定和JavaScript库,所有这些都有助于隔离本地组件和全局设计元素。自定义属性为处理此旧问题提供了新选项。

默认情况下,CSS自定义属性本地作用于我们应用它们的特定选择器。所以他们有点像局部变量。但是,自定义属性也是继承的,因此在许多情况下它们的行为类似于全局变量 - 尤其是在应用于:root选择器时。这意味着我们需要考虑如何使用它们。

这么多示例显示了应用于:root元素的自定义属性,虽然这对于演示来说很好,但它可能会导致全局范围混乱以及继承的意外问题。幸运的是,我们已经学到了这些教训。

全局变量趋于静态

有一些小的例外,但一般来说,CSS中的大多数全局事物也是静态的。

品牌颜色,排版和间距等全局变量从一个组件到下一个组件的变化不大。当它们确实发生变化时,这往往是全球品牌重塑或其他一些在成熟产品上很少发生的重大变化。这些东西仍然是变量,它们在很多地方使用,变量有助于保持一致性。但是他们没有动力是没有意义的。这些变量的值不会以任何动态方式改变。

因此,我强烈建议对全局(静态)变量使用预处理器。这不仅可以确保它们始终是静态的,而且可以在代码中直观地表示它们。这可以使CSS更易读,更易于维护。

本地静态变量没问题(有时候)

您可能会认为,鉴于全局变量是静态的强烈立场,通过反射,所有局部变量可能需要是动态的。虽然局部变量确实倾向于动态,但这远不如全局变量趋于静态的趋势那么强。

在许多情况下,局部静态变量完全可以。我在组件文件中使用预处理器变量主要是为了方便开发人员。

考虑具有多个大小变化的按钮组件的经典示例。

纽扣

我scss可能看起来像这样:

$button-sml: 1em;$button-med: 1.5em;$button-lrg: 2em;

.btn {
  // Visual styles}.btn-sml {
  font-size: $button-sml;}.btn-med {
  font-size: $button-med;}.btn-lrg {
  font-size: $button-lrg;}
复制

显然,如果我多次使用变量或从大小变量中导出margin和padding值,这个例子会更有意义。但是,快速制作不同尺寸原型的能力可能是一个充分的理由。

因为大多数静态变量是全局的,所以我喜欢区分仅在组件内部使用的静态变量。为此,您可以使用组件名称为这些变量添加前缀,或者可以使用其他前缀,例如c-variable-namecomponent或l-variable-namelocal。您可以使用您想要的任何前缀,也可以为全局变量添加前缀。无论您选择什么,特别是在将现有代码库转换为使用自定义属性时,区分是有帮助的。

何时使用自定义属性

如果在组件内部使用静态变量是可以的,那么我们何时应该使用自定义属性?将现有的预处理器变量转换为自定义属性通常没有多大意义。毕竟,自定义属性的原因完全不同。自定义属性意义的时候,我们有改变相对于DOM中的条件CSS属性-尤其是一个动态的条件,例如:focus,:hover媒体查询或使用JavaScript。

我怀疑我们将始终使用某种形式的静态变量,尽管将来我们可能需要更少,因为自定义属性提供了组织逻辑和代码的新方法。在那之前,我认为在大多数情况下,我们将使用预处理器变量和自定义属性的组合。

知道我们可以将静态变量分配给自定义属性是有帮助的。无论它们是全局的还是本地的,在许多情况下将静态变量转换为本地动态自定义属性是有意义的。

注意:您知道这$var是自定义属性的有效值吗?最新版本的Sass认识到这一点,因此我们需要插入分配给自定义属性的变量,如下所示:#{$var}。这告诉Sass你想输出变量的值,而不是仅仅$var在样式表中输出。这仅适用于自定义属性等情况,其中变量名称也可以是有效的CSS。

如果我们采用上面的按钮示例并确定所有按钮都应该使用移动设备上的小变体,无论HTML中应用哪个类,这都是一个更加动态的情况。为此,我们应该使用自定义属性。

$button-sml: 1em;$button-med: 1.5em;$button-lrg: 2em;

.btn {
  --button-size: #{$button-sml};}@media screen and (min-width: 600px) {
  .btn-med {
    --button-size: #{$button-med};
  }
  .btn-lrg {
    --button-size: #{$button-lrg};
  }}.btn {
  font-size: var(--button-size);}
复制

在这里,我创建了一个自定义属性:--button-size。此自定义属性最初使用btn该类限定为所有按钮元素。然后我改变的价值--button-size为阶级之上600px的btn-med和btn-lrg。最后,我将此自定义属性应用于一个位置的所有按钮元素。

不要太聪明

自定义属性的动态特性使我们能够创建一些聪明而复杂的组件。

随着预处理器的引入,我们中的许多人使用mixins和自定义函数创建了具有巧妙抽象的库。在有限的情况下,这样的例子今天仍然有用,但是在大多数情况下,我使用预处理器的时间越长,我使用的功能就越少。今天,我几乎只使用预处理器来处理静态变量。

自定义属性不会(也不应该)不受此类实验的影响,我期待看到许多聪明的例子。但从长远来看,可读和可维护的代码总是会胜过聪明的抽象(至少在生产中)。

我最近在Free Code Camp Medium上阅读了一篇关于这个主题的优秀文章。它由Bill Sourour编写,被称为“ 不要在运行时做它。在设计时做它。“而不是解释他的论点,我会让你读它。

预处理器变量和自定义属性之间的一个关键区别是自定义属性在运行时工作。这意味着在复杂性方面可能已被边界接受的事物与预处理器一起使用自定义属性可能不是一个好主意。

最近为我说明这一点的一个例子是:

:root {
  --font-scale: 1.2;
  --font-size-1: calc(var(--font-scale) * var(--font-size-2));
  --font-size-2: calc(var(--font-scale) * var(--font-size-3)); 
  --font-size-3: calc(var(--font-scale) * var(--font-size-4));   
  --font-size-4: 1rem;     }
复制

这会生成模块化比例。模块化比例是使用比率彼此相关的一系列数字。它们通常用于网页设计和开发,以设置字体大小或间距。

在此示例中,calc()通过获取先前自定义属性的值并将其乘以比率来确定每个自定义属性。这样做,我们可以获得规模中的下一个数字。

这意味着比率是在运行时计算的,您可以通过仅更新--font-scale属性的值来更改它们。例如:

@media screen and (min-width: 800px) {
  :root {
    --font-scale: 1.33;
  }}
复制

如果您想要更改比例,这比再次计算所有值更聪明,更简洁,更快捷。这也是我在生产代码中不会做的事情。

虽然上面的例子对于原型设计很有用,但在生产中,我更喜欢看到这样的东西:

:root {
  --font-size-1: 1.728rem;
  --font-size-2: 1.44rem;
  --font-size-3: 1.2em;
  --font-size-4: 1em;}@media screen and (min-width: 800px) {
  :root {
    --font-size-1: 2.369rem; 
    --font-size-2: 1.777rem;     
    --font-size-3: 1.333rem; 
    --font-size-4: 1rem;     
  }}
复制

与Bill的文章中的示例类似,我发现查看实际值是有帮助的。我们阅读代码的次数比编写它的次数多很多,并且字体比例等全局值在生产中不经常更改。

上面的例子仍然不完美。它违反了早先的规则,即全局值应该是静态的。我更喜欢使用预处理器变量,并使用前面演示的技术将它们转换为本地动态自定义属性。

避免使用一个自定义属性到另一个自定义属性的情况也很重要。当我们命名这样的属性时会发生这种情况。

更改值不是变量

更改值而不是变量是有效使用自定义属性的最重要策略之一。

作为一般规则,您永远不应该更改用于任何单一用途的自定义属性。这很容易做到,因为这正是我们使用预处理器执行操作的方式,但对于自定义属性来说却没有多大意义。

在此示例中,我们有两个在示例组件上使用的自定义属性。我从使用值切换--font-size-small到--font-size-large取决于屏幕大小。

:root {
  --font-size-small: 1.2em;
  --font-size-large: 2em;            }.example {
  font-size: var(--font-size-small);}@media screen and (min-width: 800px) {
  .example {
    font-size: var(--font-size-large);
  }}
复制

更好的方法是定义一个作用于组件的自定义属性。然后使用媒体查询或任何其他选择器更改其值。

.example {
  --example-font-size: 1.2em;}@media screen and (min-width: 800px) {                             
  .example {
    --example-font-size: 2em;            
  }}
复制

最后,在一个地方,我使用这个自定义属性的值:

.example {
  font-size: var(--example-font-size);}
复制

在此示例中以及之前的其他示例中,媒体查询仅用于更改自定义属性的值。您可能还注意到只有一个位置var()使用该语句,并且更新了常规CSS属性。

变量声明和属性声明之间的这种分离是有意的。这有很多原因,但在考虑响应式设计时,其好处最为明显。

自定义属性的响应式设计

响应式设计在严重依赖媒体查询时遇到的一个难点是,无论您如何组织CSS,与特定组件相关的样式都会在样式表中变得分散。

要知道哪些CSS属性会发生变化可能非常困难。尽管如此,CSS Custom Properties可以帮助我们组织一些与响应式设计相关的逻辑,并使得处理媒体查询变得更加容易。

如果它改变,它是一个变量

使用媒体查询更改的属性本质上是动态的,自定义属性提供了在CSS中表达动态值的方法。这意味着如果您使用媒体查询来更改任何CSS属性,则应将此值放在自定义属性中。

然后,您可以将此以及定义值如何更改的所有媒体规则,悬停状态或任何动态选择器移动到文档顶部。

从设计中分离逻辑

正确完成后,逻辑和设计的分离意味着媒体查询仅用于更改自定义属性的值。这意味着与响应式设计相关的所有逻辑都应该位于文档的顶部,无论我们var()在CSS中看到哪个语句,我们都会立即知道这个属性会发生变化。使用传统的CSS编写方法,一眼就无法了解这一点。

我们中的许多人一眼就能很好地阅读和解释CSS,同时在我们的脑海中跟踪哪些属性在不同情况下发生了变化。我已经厌倦了,我不想再这样做了!自定义属性现在提供逻辑与其实现之间的链接,因此我们不需要跟踪它,这非常有用!

逻辑折叠

在文档或函数顶部声明变量的想法并不是一个新想法。这是我们在大多数语言中所做的事情,现在我们可以在CSS中做些什么。以这种方式编写CSS会在文档顶部和下面的CSS之间创建清晰的视觉区别。当我谈到它们时,我需要一种方法来区分这些部分,而“逻辑折叠”的概念是我开始使用的一个比喻。
首屏包含所有预处理器变量和自定义属性。这包括自定义属性可以具有的所有不同值。跟踪自定义属性如何更改应该很容易。

下方的CSS非常简单,高度声明且易于阅读。在媒体查询和现代CSS的其他必要复杂性之前感觉就像CSS一样。

看一下六列flexbox网格系统的一个非常简单的例子:

.row {
  --row-display: block;}@media screen and (min-width: 600px) {
  .row {
    --row-display: flex;
  }}
复制

该--row-display自定义属性的初始设置为block。高于600px时,显示模式设置为flex。

折叠下方可能如下所示:

.row {
  display: var(--row-display);
  flex-direction: row;
  flex-wrap: nowrap;}.col-1, .col-2, .col-3,
.col-4, .col-5, .col-6 {
  flex-grow: 0;
  flex-shrink: 0;}.col-1 { flex-basis: 16.66%; }.col-2 { flex-basis: 33.33%; }.col-3 { flex-basis: 50%; }.col-4 { flex-basis: 66.66%; }.col-5 { flex-basis: 83.33%; }.col-6 { flex-basis: 100%; }
复制

我们立即知道的--row-display是一个变化的价值。最初,它将是block,因此将忽略flex值。

这个例子非常简单,但是如果我们将它扩展为包含一个填充剩余空间的灵活宽度列,那么很可能flex-grow,flex-shrink并且flex-basis值需要转换为自定义属性。你可以尝试这个,或者在这里看一个更详细的例子。

主题的自定义属性

我主要反对使用全局动态变量的自定义属性,并希望暗示将自定义属性附加到:root选择器在许多情况下被认为是有害的。但是每个规则都有一个例外,对于自定义属性,它就是主题。

全球定制属性的有限使用可以使它们变得更容易。

主题通常是指让用户以某种方式自定义UI。这可能类似于更改个人资料页面上的颜色。或者它可能是更本地化的东西。例如,您可以在Google Keep应用程序中选择备注的颜色。

Google Keep App

主题通常涉及编译单独的样式表以使用用户首选项覆盖默认值,或者为每个用户编译不同的样式表。这两者都很困难并且会对性能产生影响。

使用自定义属性,我们不需要编译不同的样式表; 我们只需要根据用户的偏好更新属性的值。由于它们是继承的值,如果我们在根元素上执行此操作,则可以在我们的应用程序中的任何位置使用它们。

资本化全球动态属性

自定义属性区分大小写,并且由于大多数自定义属性都是本地属性,因此如果使用全局动态属性,则可以将它们大写。

:root {
  --THEME-COLOR: var(--user-theme-color, #d33a2c);            }
复制

变量的大写通常表示全局常量。对我们来说,这意味着该属性已在应用程序的其他位置设置,我们可能不应在本地更改它。

避免直接设置全局动态属性

自定义属性接受回退值。避免直接覆盖全局自定义属性的值并保持用户值分开是有用的。我们可以使用后备值来执行此操作。

上面的示例将值设置--THEME-COLOR为--user-theme-colorif 的值。如果--user-theme-color未设置,#d33a2c将使用值。这样,我们每次使用时都不需要提供后备--THEME-COLOR。

您可能希望在下面的示例中将背景设置为green。但是,--user-theme-color尚未在根元素上设置值,因此值--THEME-COLOR未更改。

:root {
  --THEME-COLOR: var(--user-theme-color, #d33a2c);            }body {
  --user-theme-color: green;
  background: var(--THEME-COLOR);}
复制

间接设置这样的全局动态属性可以防止它们被本地覆盖,并确保用户设置始终从根元素继承。这是保护主题值并避免意外继承的有用约定。

如果我们确实希望将特定属性公开给继承,我们可以用:root选择器替换选择*器:

* {
  --THEME-COLOR: var(--user-theme-color, #d33a2c);            }body {
  --user-theme-color: green;
  background: var(--THEME-COLOR);}
复制

现在--THEME-COLOR重新计算每个元素的值,--user-theme-color因此可以使用本地值。换句话说,此示例中的背景颜色将是green。

您可以在“ 使用自定义属性操作颜色 ”一节中查看此模式的一些更详细的示例。

使用JAVASCRIPT更新自定义属性

如果你想使用JavaScript设置自定义属性,有一个相当简单的API,它看起来像这样:

const elm = document.documentElement;elm.style.setProperty('--USER-THEME-COLOR', 'tomato');
复制

这里我设置--USER-THEME-COLOR文档元素的值,换句话说,:root它是所有元素将继承它的元素。

这不是一个新的API; 它与更新元素样式的JavaScript方法相同。这些是内联样式,因此它们具有比常规CSS更高的特异性。

这意味着可以轻松应用本地自定义:

.note {
  --note-color: #eaeaea;}.note {
  background: var(--note-color);}
复制

在这里,我为组件设置了默认值--note-color并将其作为范围.note。即使在这个简单的例子中,我也将变量声明与属性声明分开。

const elm = document.querySelector('#note-uid');elm.style.setProperty('--note-color', 'yellow');
复制

然后,我定位.note元素的特定实例,并仅更改该元素的--note-color自定义属性的值。现在,这将具有比默认值更高的特异性。

您可以使用React查看此示例的工作原理。这些用户首选项可以保存在本地存储中,或者在较大的应用程序的情况下,可以保存在数据库中。

使用自定义属性操作颜色

除了十六进制值和命名颜色,CSS还有颜色函数,如rgb()和hsl()。这些允许我们指定颜色的各个组件,例如色调或亮度。自定义属性可与颜色功能结合使用。

:root {
  --hue: 25;}body {
  background: hsl(var(--hue), 80%, 50%);}
复制

这很有用,但预处理器中一些最广泛使用的功能是高级颜色函数,它们允许我们使用变亮,变暗或去饱和等功能来操作颜色:

darken($base-color, 10%);lighten($base-color, 10%);desaturate($base-color, 20%);
复制

在浏览器中使用这些功能会很有用。它们即将到来,但在我们在CSS中使用原生颜色修改功能之前,自定义属性可以填补一些空白。

我们已经看到自定义属性可以在现有的颜色函数中使用rgb(),hsl()但它们也可以用于calc()。这意味着我们可以通过乘以它将实数转换为百分比,例如calc(50 * 1%)= 50%。

:root {
  --lightness: 50;}body {
  background: hsl(25, 80%, calc(var(--lightness) * 1%));}
复制

我们希望将亮度值存储为实数的原因是我们可以calc在将其转换为百分比之前对其进行操作。例如,如果我想要使颜色变暗20%,我可以将其亮度乘以0.8。通过将亮度计算分成局部范围的自定义属性,我们可以使这更容易阅读:

:root {
  --lightness: 50;}body {
  --lightness: calc(var(--lightness * 0.8));
  background: hsl(25, 80%, calc(var(--lightness) * 1%));}
复制

我们甚至可以抽象出更多的计算,并使用自定义属性在CSS中创建类似颜色修改函数的东西。对于大多数实际的主题,这个例子可能过于复杂,但它展示了动态自定义属性的全部功能。

简化主题

使用自定义属性的一个优点是可以简化主题。应用程序无需了解自定义属性的使用方式。相反,我们使用JavaScript或服务器端代码来设置自定义属性的值。如何使用这些值由样式表决定。

这再次意味着我们能够将逻辑与设计分开。如果您有技术设计团队,作者可以更新样式表并决定如何应用自定义属性而无需更改单行JavaScript或后端代码。

自定义属性还允许将主题的一些复杂性移动到CSS中,这种复杂性会对CSS的可维护性产生负面影响,因此请记住尽可能保持简单。

今天使用自定义属性

即使您支持IE10和11,也可以立即开始使用自定义属性。本文中的大多数示例都与我们编写和构造CSS的方式有关。在可维护性方面的好处是显着的,但是,大多数示例仅减少了使用更复杂的代码所能完成的任务。

我使用一个名为postcss-css-variables的工具将自定义属性的大部分功能转换为相同代码的静态表示。其他类似的工具忽略了媒体查询或复杂选择器中的自定义属性,处理自定义属性很像预处理器变量。

这些工具不能做的是模拟自定义属性的运行时功能。这意味着没有动态功能,如主题或使用JavaScript更改属性。在许多情况下这可能没问题。根据具体情况,UI自定义可能被视为渐进增强,默认主题可能完全可以接受旧浏览器。

加载正确的样式表

有很多方法可以使用postCSS。我使用一个gulp进程为新旧浏览器编译单独的样式表。我的gulp任务的简化版本如下所示:

import gulp from "gulp";import sass from "gulp-sass";import postcss from "gulp-postcss";import rename from "gulp-rename";import cssvariables from "postcss-css-variables";import autoprefixer from "autoprefixer";import cssnano from "cssnano";gulp.task("css-no-vars", () =>
  gulp
    .src("./src/css/*.scss")
    .pipe(sass().on("error", sass.logError))
    .pipe(postcss([cssvariables(), cssnano()]))
    .pipe(rename({ extname: ".no-vars.css" }))
    .pipe(gulp.dest("./dist/css")));gulp.task("css", () =>
  gulp
    .src("./src/css/*.scss")
    .pipe(sass().on("error", sass.logError))
    .pipe(postcss([cssnano()]))
    .pipe(rename({ extname: ".css" }))
    .pipe(gulp.dest("./dist/css")));
复制

这会产生两个CSS文件:一个带有自定义属性的常规文件(styles.css)和一个用于旧浏览器的文件(styles.no-vars.css)。我想要提供IE10和11 styles.no-vars.css以及其他浏览器来获取常规CSS文件。

通常,我主张使用功能查询,但IE11不支持功能查询,我们已广泛使用自定义属性,因此在这种情况下提供不同的样式表是有意义的。

智能地提供不同的样式表并避免闪烁的无格式内容并不是一项简单的任务。如果您不需要自定义属性的动态功能,则可以考虑将所有浏览器styles.no-vars.css作为开发工具使用自定义属性。

如果您想充分利用自定义属性的所有动态功能,我建议使用关键的CSS技术。遵循这些技术,主要样式表是异步加载的,而关键CSS是内联呈现的。您的页眉可能如下所示:

<head>
  <style> /* inlined critical CSS */ </style>
  <script> loadCSS('non-critical.css'); </script></head>
复制

我们可以将其扩展为加载styles.css或styles.no-vars.css根据浏览器是否支持自定义属性。我们可以检测到这样的支持:

if ( window.CSS && CSS.supports('color', 'var(--test)') ) {
  loadCSS('styles.css');} else {
  loadCSS('styles.no-vars.css');}
复制

结论

东莞网页设计如果您一直在努力有效地组织CSS,难以使用响应式组件,想要实现客户端主题,或者只是想通过自定义属性开始,那么本指南应该告诉您需要知道的一切。

它归结为理解CSS中动态和静态变量之间的区别以及一些简单的规则:

  1. 将逻辑与设计分开;

  2. 如果CSS属性发生更改,请考虑使用自定义属性;

  3. 更改自定义属性的值,而不是使用哪个自定义属性;

  4. 全局变量通常是静态的。

如果您遵循这些约定,您会发现使用自定义属性比您想象的要容易得多。这甚至可能会改变您通常使用CSS的方式。


最新案例

联系电话 400-6065-301

留言