5

如何在CSS中使用变量 - chuckQu

 2 years ago
source link: https://www.cnblogs.com/chuckQu/p/16609638.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

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

除了更加简洁以及不重复的代码,CSS变量可用于构建调色板,提高响应能力,并创建动态类型系统。

定义CSS变量

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

下面是个例子:

--primarycolor: #0ad0f9ff; /* RGB alpha 16进制颜色 */

--向CSS解释器表明这是一个自定义属性。当作为一个变量使用时,解释器引擎会将该属性替换为其值。

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

与其他属性一样,比如说display或者font,CSS自定义属性必须定义在声明块内。一个常见的模式是使用 :root 伪元素作为选择器来定义自定义属性。

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

:root是一个伪元素,它指向文档中的根元素。对HTML文档而言,指向的就是<html>元素。对SVG文档而言,指向的就是<svg>元素。使用: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自定义属性 VS CSS变量

"自定义属性"是一个面向未来的名称,它说明了这个功能有一天可能会被使用。然而,如果浏览器供应商实施了CSS扩展规范,这种情况就会改变。该规范定义了用自定义选择器组合、函数和at-rules来扩展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>元素中继承了color值。

解析自定义属性的方式与解析其他CSS值的方式相同。倘若值是无效的或者未定义的,如果属性是可继承的,CSS解析器就会使用继承的值(比如说colorfont)。如果属性是不可继承的,CSS解析器就会使用初始值(比如说background-color)。

自定义属性也遵循层叠的规则。它们的值会被后续的规则所覆盖:

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

在上述示例中,body字体颜色将会是深灰色。我们还可以在每个选择器的基础上重置值。让我们向这个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代表hue, saturation, lightness 。这是一款基于亮度的颜色模型,类似于RGB。我们可以在CSS中使用HSL,这要归功于hsl()hsla()颜色函数。hsl()函数接收三个参数,分别是hue, saturation, 和 lightness,也就是色相、饱和度、亮度。hsla() 函数同时接收第四个参数,表示颜色的alpha透明度(取值范围是0-1之间)。

RGB系统用红、绿、蓝的比例来表达颜色,而HSL则使用一个颜色圈,色相是该圈上的一个度数位置,而色调或阴影则用饱和度和亮度值来定义。饱和度的范围从0%到100%,其中0%是灰色,100%是全色。亮度的范围也是从0%到100%,其中0%是黑色,100%是白色,50%是正常颜色。

调色板.png

在HSL颜色系统中,主要颜色红、绿、蓝三原色在0度/360度、120度和240度处相距120度。二级颜色--青色、品红和黄色--也相距120度,但位于主要颜色的对面,分别为180度、300度和60度/420度。三级、四级和其他颜色则以大约10度的增量介于两者之间。蓝色用HSL来写的话,将会是hsl(240, 100%, 50%)

HSL参数单位

当你在hsl()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()和hsla()可以接受逗号分隔的参数或空格分隔的参数。
    但旧的浏览器(如Internet Explorer 11)只支持逗号分隔的参数。
  */

    --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

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

健全的调色板生成

另一个想法是结合自定义属性和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自定义变量为你的网站,定义与深色和浅色主题相关的一系列的变量。

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

: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选择器及其内容,但要为其添加一个带有dark值的主题属性:

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

如果带有dark值的主题属性被添加到<html>元素上,那么该主题将被激活。

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

添加如下代码到: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()过滤器会反转所选元素的所有颜色(在本例中是每个元素)。反转的值可以用百分比或数字来指定。参数值100%或1将完全反转元素的色相、饱和度和亮度值。

brightness()过滤器使元素更加明亮或者暗黑。如果数值为0,就会出现一个完全暗黑的元素。

invert()过滤器会使一些元素变得非常明亮。需要通过设置brightness(0.6)来降低亮度。

具有不同程度深色的深色主题:

dark-theme.png

使用JavaScript切换主题

现在,当用户点击深色/浅色按钮时,我们使用JavaScript来切换深色和浅色主题。在HTML</body>标签闭合前添加行内<script>标签,标签内具有如下代码:

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()方法检查theme属性是否存在。如果不存在,就将dark添加到该属性上,从而导致切换到深色主题。否则,它将删除该属性,从而导致切换到浅色主题。

注意:你还应该把它与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%);
  }
}

同样地,我们可以使用自定义属性来改变适合于屏幕与打印的基准字体大小。

: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个单位的基准字体大小,对于屏幕来说是像素(px),对于打印来说是点(pt)。我们还将使用--base-font-size:的值来为我们的根元素(html)设置一个起始尺寸。然后我们可以rem单位来调整相对于基准字体尺寸的排版。

在JavaScript中使用自定义属性

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

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

// 如果浏览器支持自定义属性,则打印true
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)';

还有,你不能使用style对象的方括号语法或驼峰属性来设置自定义属性。换句话说,document.body.style.--bg-homedocument.body.style['--bg-home'] 都无法发挥作用。

在组件中使用自定义属性

像React、Angular和Vue这样的JavaScript框架让开发者使用JavaScript来创建可重用、可共享的HTML块,通常会在组件层面上定义CSS。

这是一个有关React组件的示例,使用JSX语法编写:

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没有定义。在这里,我们可以在全局样式表或通过style属性设置--button-bg-color 的值。

让我们将值设置为React属性。React props(简称为属性)模仿元素属性。它们是一种将数据传入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属性的值,并为按钮添加style属性。

使用style属性可能与你所学到的关于编写CSS的知识相悖。CSS的一个卖点是,我们可以定义一套样式,在多个HTML和XML文档中使用。另一方面,style属性将CSS的范围限制在它所应用的元素上,导致我们不能重用它。并且也不能利用层叠的优势。

但在一个基于组件的前端架构中,一个组件可能在多种情况下被多个团队使用,甚至可能在客户端项目中共享。在这些情况下,你可能想把层叠的全局范围style属性所提供的局部范围结合起来。

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

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

  • 创建可重用的、主题化的组件
  • 轻松调整内边距、外边距以及排版,以适应各种视口尺寸和媒体
  • 改进CSS颜色值的一致性

变量有一系列的应用,在基于组件的设计系统中特别有用。我希望你现在对如何在CSS中使用变量或自定义属性有了更好的理解。

以上就是全部内容,如果对你有所帮助,欢迎点赞收藏转发~


Recommend

  • 5
    • www.lfhacks.com 3 years ago
    • Cache

    Jmeter 如何在变量名中使用变量

    Jmeter 如何在变量名中使用变量 在Jmeter的变量名中使用变量(叫做嵌套变量名),这在循环中尤其有用,本文讨论这种实践。...

  • 13

    正文从这开始~ 组件不能作为JSX组件使用,出现该错误有多个原因: 返回JSX元素数组,而不是单个元素。 从组件中返回JSX元素或者null以外的任何值。 使用过时的React类型声明。

  • 3

    使用CSS变量实现主题定制真的很简单更新日期: 2022-10-19阅读: 11标签: ...

  • 9

    循环允许我们通过循环数组或对象中的项并做一些事情,比如说打印它们,修改它们,或执行其他类型的任务或动作。JavaScript有各种各样的循环,for循环允许我们对一个集合(如数组)进行迭代。 在这篇文章中,我们将了解JavaScript提供的for...

  • 7
    • www.cnblogs.com 2 years ago
    • Cache

    如何使用zx编写shell脚本 - chuckQu

    在这篇文章中,我们将学习谷歌的zx库提供了什么,以及我们如何使用它来用Node.js编写shell脚本。然后,我们将学习如何通过构建一个命令行工具来使用zx的功能,帮助我们为新的Node.js项目引导配置。 编写Shell脚本的问...

  • 9

    Vue 3已经稳定了相当长一段时间了。许多代码库都在生产环境中使用它,其他人最终都将不得不迁移到Vue 3。我现在有机会使用它并记录了我的错误,下面这些错误你可能想要避免。 使用Reactive声明原始值 数据声明在过去都...

  • 7
    • www.cnblogs.com 2 years ago
    • Cache

    如何在2023年学习React - chuckQu

    在2023年学习React并不是一件容易的事情。自2019年React Hooks发布以来,我们已经拥有了很多稳定性,但现在形势正在再次变化。而这次变化可能比使用React Hooks时更加不稳定。在本文中,我想比较两种学习React的方式:以库的方式和以框架的方式。 为了让事情...

  • 5
    • www.cnblogs.com 2 years ago
    • Cache

    使用Ref还是Reactive? - chuckQu

    我喜欢Vue 3的Composition API,它提供了两种方法来为Vue组件添加响应式状态:ref和reactive。当你使用ref时到处使用.value是很麻烦的,但当你用reactive创建的响应式对象进行重构时,也很容易丢...

  • 5
    • www.cnblogs.com 1 year ago
    • Cache

    如何使用Map处理Dom节点 - chuckQu

    如何使用Map处理Dom节点 本文浅析一下为什么Map...

  • 1

    在这里,我想给你一个新的React项目入门的简要概述。我想反思一下优点和缺点,反思一下作为一个开发者所需要的技术水平,反思一下作为一个React开发者,每个启动项目都能为你提供哪些功能。最后,你将了解到针对不同需求的3种解决方案。 免责声明

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK