×

Web前端之家:如何在 CSS 中优雅合理使用变量

作者:Terry2022.06.07来源:Web前端之家浏览:4865评论:0
关键词:csscss变量

500.jpg

CSS 变量(官方称为自定义属性)是用户定义的值,可以在整个代码库中设置一次并多次使用。它们使管理颜色、字体、大小和动画值变得更加容易,并确保 Web 应用程序的一致性。

例如,您可以将品牌颜色设置为 CSS 属性 ( --primarycolor: #7232FA),并在使用品牌颜色 ( ) 的任何组件或样式中使用此值background: var(--primarycolor);

除了提供更简洁且不重复的代码外,CSS 变量还可用于构建调色板、提高响应能力和创建动态类型系统。

定义 CSS 变量

要定义自定义属性,请选择一个名称并在其前面加上两个连字符。任何字母数字字符都可以是名称的一部分。也允许使用连字符 ( -) 和下划线 ( ) 字符。_广泛的 Unicode 字符可以是自定义属性名称的一部分。这包括表情符号,但为了清晰和可读性,请坚持使用字母数字名称。

这是一个例子:

--primarycolor: #0ad0f9ff; /* RGB alpha hexadecimal color notation */

-- 向 CSS 解析器指示这是一个自定义属性。 当用作变量时,解析引擎将属性替换为其值。

自定义属性名称 区分大小写。这意味着 --primaryColor 并且 --primarycolor 被认为是两个不同的属性名称。这与传统的 CSS 不同,在传统 CSS 中,属性和值大小写无关紧要。但是,它与 ECMAScript 中的变量名规则是一致的。

与其他属性(例如 display or  )一样font,CSS 自定义属性必须在声明块中定义。:root 一种常见的模式是使用伪元素作为选择器来定义自定义属性 :

:root {
  --primarycolor: #0ad0f9ff;
}

:root 是一个伪元素,指的是文档的根元素。对于 HTML 文档,这就是 <html> 元素。对于 SVG 文档,它是 <svg> 元素。Using :root 使属性在整个文档中立即可用。

使用 CSS 变量

要将自定义属性用作变量,我们需要使用该 var() 函数。例如,如果我们想使用我们的 --primarycolor 自定义属性作为背景颜色,我们将执行以下操作:

body {
    background-color: var(--primarycolor);
}

我们自定义属性的值将成为该属性的计算值 background-color 。

迄今为止,自定义属性只能用作设置标准 CSS 属性值的变量。例如,您不能将属性 名称存储 为变量然后重用它。以下 CSS 不起作用:

:root {
    --top-border: border-top; /* Can't set a property as custom property's value */
    var(--top-border): 10px solid #bc84d8; /* Can't use a variable as a property */
}

您也不能将属性-值 对存储 为变量并重用它。下面的例子也是无效的:

:root {
    --text-color: 'color: orange'; /* Invalid property value */
}
body {
    var(--text-color); /* Invalid use of a property */
}

最后,您不能将变量连接为值字符串的一部分:

:root {
    --base-font-size: 10;
}
body {
    font: var(--base-font-size)px / 1.25 sans-serif; /* Invalid CSS syntax */
}

CSS 自定义属性与 CSS 变量

“自定义属性”是一个面向未来的名称,它说明了将来如何使用此功能。但是,如果  浏览器供应商实施CSS 扩展规范,这可能会改变。该规范定义了使用自定义选择器组合、函数和规则扩展 CSS 的方法。

我们通常将自定义属性称为“变量”,迄今为止,这是我们使用它们的唯一方式。从理论上讲,它们并不是完全可以互换的术语。在实践中和现在,他们是。我将在这篇文章中主要使用 自定义属性 ,因为这是它们的专有名称。 当它使句子更清晰时,我将使用 变量。

设置后备值

该 var() 函数最多接受两个参数。第一个参数应该是自定义属性名称。第二个参数是可选的,但必须是声明值。此声明值用作未定义自定义属性值时应用的后备或默认值。

让我们采用以下 CSS:

.btn__call-to-action {
    background: var(--accent-color, deepskyblue);
}

如果 --accent-color 定义了——假设它的值是 #f30 ——那么任何具有类属性的路径的填充颜色 .btn__call-to-action 都将具有红橙色填充。如果未定义,填充将是深天蓝色。

声明值也可以嵌套。换句话说,您可以使用变量作为 var 函数的后备值:

body {
    background-color: var(--books-bg, var(--arts-bg));
}

在上面的 CSS 中,如果 --books-bg 定义了,背景颜色将被设置为该 --books-bg 属性的值。如果不是,则背景颜色将改为分配给 的任何值 --arts-bg。如果这两个都没有定义,背景颜色将是属性的初始值——在这种情况下,  transparent.

当自定义属性的值对其使用的属性无效时,也会发生类似的情况。考虑以下 CSS:

:root {
    --text-primary: #600;
    --footer-link-hover: #0cg; /* Not a valid color value */
}
body {
    color: var(--text-primary);
}
a:link {
    color: blue;
}
a:hover {
    color: red;
}
footer a:hover {
    color: var(--footer-link-hover);
}

在这种情况下, --footer-link-hover 属性的值不是有效的颜色。相反, footer a:hover 从 <body> 元素的颜色继承其颜色。

自定义属性的解析方式与解析其他 CSS 值的方式相同。如果值无效或未定义,如果属性是可继承的(例如 color or  font),CSS 解析器将使用继承的值,如果不是(例如 ),则使用初始值 background-color

级联值

自定义属性也遵守级联规则。它们的值可以被后续规则覆盖:

:root {
    --text-color: #190736; /* navy */
}
body {
    --text-color: #333;  /* dark gray */
}
body {
    color: var(--text-color);
}

在上面的示例中,我们的正文将是深灰色。我们还可以在每个选择器的基础上重置值。让我们在这个 CSS 中添加更多规则:

:root {
    --text-color: #190736; /* navy */
}
body {
    --text-color: #333;   /* dark gray */
}
p {
    --text-color: #f60;  /* orange */
}
body {
    color: var(--text-color);
}
p {
    color: var(--text-color)
}

<p> 在这种情况下,任何包含在元素标签中的文本 都是橙色的。但其中的文本 <div> 或其他元素仍将是深灰色。

您还可以使用 style 属性设置自定义属性的值,例如 style="--brand-color: #9a09af".

自定义属性和调色板

自定义属性特别适用于管理 HSL 调色板。 HSL 代表 色调、饱和度、亮度。它是一种基于光的颜色模型,类似于 RGB。由于 hsl() 和 hsla() color 函数,我们可以在 CSS 中使用 HSL 值。该 hsl() 函数接受三个参数:色调、饱和度和亮度。该 hlsa() 函数还接受第四个参数,指示颜色的 alpha 透明度(介于 0 和 1 之间的值)。

虽然 RGB 系统将颜色表示为红色、绿色和蓝色的比例,但 HSL 使用色环,其中色调是该环上的度数位置,色调或阴影使用饱和度和亮度值定义。饱和度的范围可以从 0% 到 100%,其中 0% 是灰色,100% 是全色。亮度范围也可以从 0% 到 100%,其中 0% 为黑色,100% 为白色,50% 为正常颜色。

image.png

在 HSL 颜色系统中,红、绿、蓝三原色在 0 度/360 度、120 度和 240 度之间相隔 120 度。二次色(青色、品红色和黄色)也相隔 120 度,但与原色相对,分别为 180 度、300 度和 60 度/420 度。第三色、第四色和其他颜色以大约 10 度的增量介于两者之间。使用 HSL 表示法编写的蓝色将是 hsl(240, 100%, 50%).

HSL 参数单位

hsl() 当您对and 函数的第一个参数使用无单位值时 hsla() ,浏览器会假定它是以度为单位的角度。但是,您可以使用任何 受支持的 CSS 角度单位。蓝色也可以表示为 hsl(240deg, 100%, 50%)、 hsl(4.188rad, 100%, 50%) 或 hsla(0.66turn, 100% 50%)

这就是有趣的地方。我们可以使用自定义属性设置色调值,并通过调整饱和度和亮度值来设置更亮和更暗的阴影:

:root {
    --brand-hue:      270deg;  /* purple */
    --brand-hue-alt:  .25turn; /* green */

  /*
    hsl() and hsla() can accept comma-separated or space-separated arguments,
    but older browsers (such as Internet Explorer 11) only support
    comma-separated arguments.
  */

    --brand-primary:   hsl( var( --brand-hue ) 100% 50% );
    --brand-highlight: hsl( var( --brand-hue ) 100% 75% );
    --brand-lowlight:  hsl( var( --brand-hue ) 100% 25% );
    --brand-inactive:  hsl( var( --brand-hue )  50% 50% );

    --brand-secondary:     hsl( var( --brand-hue-alt ) 100% 50% );
    --brand-2nd-highlight: hsl( var( --brand-hue-alt ) 100% 75% );
    --brand-2nd-lowlight:  hsl( var( --brand-hue-alt ) 100% 25% );
    --brand-2nd-inactive:  hsl( var( --brand-hue-alt )  50% 50% );
}

上面的 CSS 为我们提供了如下所示的调色板。

image.png

这是一个简单的版本,但您也可以使用自定义属性来调整饱和度和亮度值。

强大的调色板生成

Dieter Raber 在“使用自定义属性、HSL 和一点 calc() 创建颜色主题”中讨论了一种强大的调色板生成技术 。页面地址是:https://css-tricks.com/creating-color-themes-with-custom-properties-hsl-and-a-little-calc/

另一个想法是结合自定义属性和 calc() 函数以从基本色调生成方形配色方案。让我们在下一个示例中创建一个方形配色方案。方形配色方案 由色轮上彼此等距的四种颜色组成,即相隔 90 度: 

:root {
    --base-hue: 310deg; /* Hot pink */
    --distance: 90deg;

    --color-a: hsl( var(--base-hue), 100%, 50% );
    --color-b: hsl( calc( var(--base-hue) + var( --distance ) ), 100%, 50% );
    --color-c: hsl( calc( var(--base-hue) + ( var( --distance ) * 2 ) ), 100%, 50% );
    --color-d: hsl( calc( var(--base-hue) + ( var( --distance ) * 3 ) ), 100%, 50% );
}

这一点 CSS 为我们提供了如下所示的颇具热带风情的配色方案。

image.png

自定义属性也适用于媒体查询,我们将在后面的部分中看到。

使用 CSS 变量制作深色主题调色板

您可以使用 CSS 自定义属性为您网站上的深色和浅色主题定义变量集。

以下面的页面样式为例,我们可以在为相应颜色定义自定义属性后,将不同选择器中的所有 HSL 颜色替换为变量 :root

:root{
    /*...*/
    --nav-bg-color: hsl(var(--primarycolor) , 50%, 50%);
    --nav-text-color: hsl(var(--primarycolor), 50%, 10%);
    --container-bg-color: hsl(var(--primarycolor) , 50%, 95%);
    --content-text-color: hsl(var(--primarycolor) , 50%, 50%);
    --title-color: hsl(var(--primarycolor) , 50%, 20%);
    --footer-bg-color: hsl(var(--primarycolor) , 93%, 88%);
    --button-text-color: hsl(var(--primarycolor), 50%, 20%);
}

已使用自定义属性的适当名称。例如, --nav-bg-color 指 的是导航背景的颜色,而 --nav-text-color 指 的是导航前景/文本的颜色。

现在复制 :root 选择器及其内容,但添加一个带有 深色 值的主题属性:

:root[theme='dark']{
    /*...*/
}

 如果将具有 深色 值 的主题属性添加到 元素,则将激活此主题 。<html>

我们现在可以手动使用这些变量的值,通过降低 HSL 颜色的亮度值来提供深色主题,或者我们可以使用其他技术,例如 CSS 过滤器,例如 invert() 和 brightness(),它们通常用于调整图像的渲染但也可以与任何其他元素一起使用。

将以下代码添加到 :root[theme='dark']

:root[theme='dark'] {
    --dark-hue: 240;
    --light-hue: 250;
    --primarycolor: var(--dark-hue);
    --nav-bg-color: hsl(var(--primarycolor), 50%, 90%);
    --nav-text-color: hsl(var(--primarycolor), 50%, 10%);
    --container-bg-color: hsl(var(--primarycolor), 50%, 95%);
    --content-text-color: hsl(var(--primarycolor), 50%, 50%);
    --title-color: hsl(--primarycolor, 50%, 20%);
    --footer-bg-color: hsl(var(--primarycolor), 93%, 88%);
    --button-text-color: hsl(var(--primarycolor), 50%, 20%);
    filter: invert(1) brightness(0.6);
}

过滤器反转所选元素中的 invert() 所有颜色(在本例中为每个元素)。inversion 的值可以用百分比或数字指定。100% 或 的值 1 将完全反转元素的色调、饱和度和亮度值。

滤镜使 brightness() 元素更亮或更暗。值会 0 导致元素完全变暗。

invert() 过滤器使某些元素非常明亮。 这些通过设置调低 brightness(0.6)

使用 JavaScript 切换主题

现在让我们使用 JavaScript 在用户单击深色/浅色 按钮时在深色和浅色主题之间切换 。在您的 HTML 中 ,使用以下代码<script> 在结束之前 添加一个内联:</body>

const toggleBtn = document.querySelector("#toggle-theme");
toggleBtn.addEventListener('click', e => {
  console.log("Switching theme");
  if(document.documentElement.hasAttribute('theme')){
    document.documentElement.removeAttribute('theme');
  }
  else{
    document.documentElement.setAttribute('theme', 'dark');
  }
});

Document.documentElement 指的是文档的根 DOM 元素,即 <html>. 此代码  使用该 方法检查主题属性 是否存在,如果该属性不存在,则使用深色.hasAttribute()值 添加该属性 ,从而切换到深色主题。否则,它会删除该属性,从而切换到浅色主题。

注意:您还应该将此与 CSS 中的prefers-color-scheme功能结合使用,该功能可用于从用户的操作系统或用户代理(浏览器)设置中自动更改浅色/深色主题。这将在下一节中显示。

使用自定义属性和媒体查询

我们还可以在媒体查询中使用自定义属性。例如,您可以使用自定义属性来定义浅色和深色配色方案:

:root {
    --background-primary: hsl(34, 78%, 91%);
    --text-primary: hsl(25, 76%, 10%);
    --button-primary-bg: hsl(214, 77%, 10%);
    --button-primary-fg: hsl(214, 77%, 98%);
}
@media screen and ( prefers-color-scheme: dark ) {
    :root {
      --background-primary: hsl(25, 76%, 10%);
      --text-primary: hsl(34, 78%, 91%);
      --button-primary-bg: hsl(214, 77%, 98%);
      --button-primary-fg: hsl(214, 77%, 10%);
  }
}

同样,我们可以使用自定义属性来更改屏幕和打印的基本字体大小:

:r:root {
    --base-font-size: 10px;
}
@media print {
    :root {
        --base-font-size: 10pt;
    }
}
html {
    font: var(--base-font-size) / 1.5 sans-serif;
}
body {
    font-size: 1.6rem;
}

在这种情况下,我们使用适合媒体的单位进行打印和屏幕。对于这两种媒体,我们将使用 10 个单位的基本字体大小——屏幕像素,打印点。我们还将使用 的值 --base-font-size: 来设置根元素 ( html) 的起始大小。然后,我们可以使用 rem 单位相对于基本字体大小来调整排版的大小。

在 JavaScript 中使用自定义属性

请记住:自定义属性是 CSS 属性,我们可以与它们进行交互。例如,我们可以使用 CSS.supports() API 来测试浏览器是否支持自定义属性:

const supportsCustomProps = CSS.supports('--primary-text: #000');

// Logs true to the console in browsers that support custom properties
console.log(supportsCustomProps);

我们还可以使用该 setProperty() 方法设置自定义属性值:

document.body.style.setProperty('--bg-home', 'whitesmoke');

使用 removeProperty() 类似。只需将自定义属性名称作为参数传递:

document.body.style.removeProperty('--bg-home');

要将自定义属性用作 JavaScript 的值,请使用 var() 以属性名称作为参数的函数:

document.body.style.backgroundColor = 'var(--bg-home)';

唉,您不能使用方括号语法或样式对象的驼峰式属性设置自定义属性。换句话说,既不 document.body.style.--bg-home 也不 document.body.style['--bg-home'] 行。

自定义属性和组件

React、Angular 和 Vue 等 JavaScript 框架允许开发人员使用 JavaScript 创建可重用、可共享的 HTML 块,通常使用在组件级别定义的 CSS。

这是一个用JSX编写的 React 组件示例,它 是 JavaScript 的语法扩展:

import React from 'react';

/* Importing the associated CSS into this component */
import '../css/field-button.css';

class FieldButtonGroup extends React.Component {
    render() {
        return (
            <div className="field__button__group">
                <label htmlFor={this.props.id}>{this.props.labelText}</label>
                <div>
                    <input type={this.props.type}
                      name={this.props.name}
                      id={this.props.id}
                      onChange={this.props.onChangeHandler} />
                    <button type="submit">{this.props.buttonText}</button>
                 </div>
            </div>
        );
    }
}

export default FieldButtonGroup;

我们的 React 组件将 CSS 导入到 JavaScript 文件中。编译时, field-button.css 内联加载 的内容。这是将其与自定义属性一起使用的一种可能方法:

.field__button__group label {
    display: block;
}
.field__button__group button {
    flex: 0 1 10rem;
    background-color: var(--button-bg-color, rgb(103, 58, 183)); /* include a default */
    color: #fff;
    border: none;
}

在这个例子中,我们使用了一个自定义属性 --button-bg-color ——按钮的背景颜色,以及一个默认颜色,以防 --button-bg-color 永远不会被定义。从这里,我们可以 --button-bg-color在全局样式表中或通过 style 属性在本地设置 的值。

让我们将值设置为 React “prop”。React  props  (  properties的缩写)模仿元素属性。它们是一种将数据传递到 React 组件的方法。在这种情况下,我们将添加一个名为 的道具 buttonBgColor

import FieldButtonGroup from '../FieldButtonGroup';

class NewsletterSignup extends React.Component {
    render() {
        // For brevity, we've left out the onChangeHandler prop.
        return (
            <FieldButtonGroup type="email" name="newsletter" id="newsletter"
              labelText="E-mail address" buttonText="Subscribe"
              buttonBgColor="rgb(75, 97, 108)" />
        );
    }
}

export default NewsletterSignup;

现在我们需要更新我们的 FieldButtonGroup 以支持此更改:

class FieldButtonGroup extends React.Component {
    render() {
        /*
        In React, the style attribute value must be set using a JavaScript
        object in which the object keys are CSS properties. Properties
        should either be camelCased (e.g. backgroundColor) or enclosed in
        quotes.
        */

        const buttonStyle = {
            '--button-bg-color': this.props.buttonBgColor
        };

        return (
            <div className="field__button__group">
                <label htmlFor={this.props.id}>{this.props.labelText}</label>
                <div>
                    <input type={this.props.type} 
                      name={this.props.name} id={this.props.id}
                      onChange={this.props.onChangeHandler} />
                    <button type="submit" style={buttonStyle}>
                      {this.props.buttonText}
                    </button>
                </div>
            </div>
        );
    }
}

在上面的代码中,我们添加了一个 buttonStyle 对象,该对象包含我们自定义属性的名称并将其值设置为我们的 buttonBgColor prop 的值,并 style 为我们的按钮添加了一个属性。

使用该 style 属性可能与您所学到的有关编写 CSS 的所有内容背道而驰。CSS 的一个卖点是我们可以定义一组样式以用于多个 HTML 和 XML 文档。style 另一方面,该 属性将 CSS 的范围限制在它所应用的元素上。我们不能重复使用它。而且我们不能利用级联。

但是在基于组件的前端架构中,一个组件可以在多个上下文中、由多个团队使用,甚至可以在客户项目之间共享。在这些情况下,您可能希望将级联的“全局范围”与 style 属性提供的狭窄“局部范围”结合起来。

使用属性设置自定义属性值 style 会将效果限制 在组件的这个特定实例 上 FieldButtonGroup 。但是因为我们使用了自定义属性而不是标准 CSS 属性,所以我们仍然可以选择 --button-bg-color 在链接样式表中定义而不是组件属性。

结论

自定义属性采用了预处理器的最佳特性之一——变量——并使它们成为 CSS 原生的。使用自定义属性,我们可以:

  • 创建可重用的主题组件

  • 为一系列视口大小和媒体轻松调整填充、边距和排版

  • 提高 CSS 中颜色值的一致性

变量有一系列应用,在基于组件的设计系统中特别有用。


您的支持是我们创作的动力!
温馨提示:本文作者系Terry ,经Web前端之家编辑修改或补充,转载请注明出处和本文链接:
https://jiangweishan.com/article/cssvar20220607.html

网友评论文明上网理性发言 已有0人参与

发表评论: