4

CSS自定义属性与前端页面的主题切换

 2 years ago
source link: https://www.fly63.com/article/detial/11278
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.

基于级联变量的css自定义属性,已经出来很多年了。
虽然有less、sass等预处理器大行其道,但是自定义属性也有它的特点和用处,诸如在js中读写、作用域设置等等,在处理UI主题切换等功能上也发挥着很大的作用。

自定义属性

CSS自定义属性(Custom Properties),在一个css选择器内部进行定义,使用两个短横连接线 -- 作为开头命名的名称即被称为自定义属性。
可以给该自定义属性设置任意css属性值。
该自定义属性赋值后,将可以作为变量赋值给css样式属性,会立马生效。

定义:--custom-property-name: custom-property-value。

body {
  /* 声明自定义属性 */
  --bg-color: #f00;
  /* 使用 */
  background-color: var(--bg-color);
}

上面的代码,即在body下定义了一个名为 --bg-color 的自定属性,并设置值为红色的颜色值 #f00。
被body的背景色 background-color 引用后,则整个页面将会呈现为红色背景。

在使用自定义属性给css样式赋值时,需要使用var()函数,见后文。

自定义属性的的命名规则,具体的如下:

  • 可以使用数字[0-9]、字母[a-zA-Z]、下划线[_]和短横线[-]组合
  • 可以使用中文等文字字符
  • 不能使用 $、[、^、(、% 等字符
  • 大小写敏感
div {
  --1: #0f0;
  --背景: yellow;
  --Fontsize: 20px;
  color: var(--1);
  font-size: var(--Fontsize, 30px);
  background-color: var(--背景);
}

如上,使用数字、中文等方式定义,都能生效。

在自定义属性声明的时候,需要给属性赋值,可以使用任意css样式属性值支持的格式。
如 #000、12px、center、字符串、数字等等。

{
  --1: #0f0;
  --2: center;
  --f: '测试';
  --n: 22;
  --z: 12px;
}

css自定义属性存在作用域,即它声明时候所处的css选择器。

  • 当自定义属性属性声明在某个css选择器内的时候,则该选择器的元素和它的所有子元素,都可以使用该自定义属性。
  • 当声明在 :root 下的时候,则全文档范围内皆可使用。

:root 是一个伪类选择器,用来匹配文档的根元素。而在 html 中,根元素即为 <html> 元素,但:root优先级更高,其他则相同。

:root {
  --color: red;
}
body {
  --bg-color: #ddd;
  color: --color;
  background-color: var(--bg-color);
  width: var(--width); /*自定义属性变量无效*/
}
body .header {
  --width: 1000px;
  color: var(--color);
  background-color: var(--bg-color);
  width: var(--width);
}

上面的示例代码,:root中声明的全局变量,将可以使用在任何地方,而body中的可以被body以及.header引用,在.header中声明的则不能被body引用。

使用自定义属性,必须要使用var()函数,下面我们将了解var()函数。

var()函数

var()函数会返回所引用自定义属性对应的值,并被应用到相应的CSS属性上。
var()函数只能作为属性的值使用,而且是可以代替样式属性中的值的任何部分。
var()函数不能作为属性名、选择器或除属性值外的其他值,如果这样做,只会产生无效语法或无效值。

定义:var(custom-property-name, value)。

  • custom-property-name 必需,自定义属性的名称。
  • value 可选,默认回退值。
div {
  --1: #0f0;
  --border-color: yellow;
  color: var(--1);
  border: 1px solid var(--border-color);
}

--border-color 作为border属性的颜色部分被引用。

默认值参数

var()函数的第二可选参数,表示默认回退值;如果该自定义属性不存在,就会使用这个默认参数值作为属性值。

div {
  font-size: var(--Fontsize, 30px);
}

如上面的代码,当 --Fontsize 不存在时,则 font-size 属性的值就为 30px。

需要注意:只有当我们的自定义属性没有定义时,才会使用默认回退值
如果自定义属性的值是错误值或不合法的,就不会使用默认值,而是会用样式属性的缺省值代替。
如果默认值也是是错误的值,则会使用属性的缺省值。

<div style="--text-color: 11px;">
  <span style="color: var(--text-color, #f00);">欢迎进入我们的网站</span>
  <span style="color: var(--1color, #f00);">今天是星期天</span>
  <span style="color: var(--1color, 22px);">晴到多云</span>
</div>

如上面的代码所示,color属性的缺省值是黑色 #000,几段文字中:

  • "欢迎进入我们的网站" 因为 --text-color 的值不是颜色值,所以默认值不起作用,显示黑色;
  • "晴到多云" 因为 --1color 不存在, 并且默认值 22px 不是颜色值,所以也显示缺省值黑色;
  • "今天是星期天" 因为 --1color 不存在, 默认值 #f00 红色有效,所以显示为红色。

不同值的使用情况

var()函数变量在使用时,有几种特殊的情况,需要注意。

用于自定义属性的值

var() 函数变量还能应用于自定义属性声明中,作为值被引用,使用方式一样。

div {
  --1: #0f0;
  --背景: var(--1);
  color: var(--1);
  border: 1px solid var(--背景);
}

--背景 属性使用了 -1 属性来进行赋值。

用于字符串组合

当自定义属性的值是字符串的时候,可以与样式属性值的字符串直接拼接,多用于content属性,如下:

:root {
  --wait-copy: ',请复制';
}
div:after {
  content: '正文'var(--wait-copy);
}

这样就能在页面上显示拼接的 content:正文,请复制。

用于calc()数字计算

当自定义属性的值是数字的时候,除了可以用于 opacity、z-index等使用数字的css属性以外,还可以使用calc函数进行计算处理。
如下所示:

:root {
  --size: 5;
  --width: calc(100px * 5);
}
.div {
  width: var(--width);
  font-size: calc(var(--size) * 10px);
}

可以通过calc计算改变样式属性。

行内样式中的使用

自定义属性和一般的css属性一样,我们同样可以在元素的行内样式中使用这些属性。
如下所示:

<div style="--text-color: red;">
  <span style="color: var(--text-color);">欢迎进入我们的网站</span>
  <span class="week">今天是星期天</span>
</div>
.week {
  color: var(--text-color);
}

在 div 元素的行内样式中声明了一个颜色属性 --text-color,在div的子元素中,通过行内样式和类样式都可以引用生效。

在SVG中使用

svg在html中的使用,既可以像jpg、png等一样以图片形式使用,也可以直接以标签的形式使用。
当我们在页面上以标签形式使用svg的时候,就可以直接引用自定变量属性,和在html中一样使用,如下所示:

:root {
  --color: red;
}
body {
  --color: green;
  --bg-color: #ddd;
  background-color: var(--bg-color);
}
<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg">
  <g fill="none" fill-rule="evenodd">
    <circle stroke="var(--color)" cx="16" cy="16" r="12"/>
    <path d="M16.5 21.5c.672 0 1.5-.084 1.5-.5V11a1 1 0 0 0-1-1h-3.5a.5.5 0 0 0-.5.5v1.112c0 .223.18.404.404.404.135 0 .667.161 1.596.484V21c0 .416.828.5 1.5.5Z" fill="var(--color)" fill-rule="nonzero"/>
  </g>
</svg>

而图片形式引用的svg图标,则无法使用自定义属性。如果确实想要修改svg图标的颜色,可以使用drop-shadow。

drop-shadow 修改svg图标颜色

给icon加样式 (利用原图标的阴影区域进行处理):

  • 给svg图标icon元素加上transform属性,移动到视觉区域以外隐藏
  • 给icon元素加上filter属性,利用drop-shadow阴影值的方式处理,阴影位移与translateX移动距离要一样
  • 给父元素加上overflow属性,隐藏超出范围的内容,把移动的原图标隐藏掉,显示阴影区域
/*父元素*/
.parent {
  overflow:hidden;
}

/*svg图标*/
img.icon {
  transform: translateX(-80px);
  filter: drop-shadow(red 80px 0);
}

这种方式对于不需要进行事件操作的svg图标较合适。

在javascript中读写

自定义属性变量,可以通过javascript进行读写,就能很方便的进行操作。
这里主要用到样式对象的 setProperty() 和 getPropertyValue() 方法。

  • 操作全局属性
:root {
  --color: red;
}
const root = getComputedStyle(document.documentElement)
// 获取全局属性值
const color1 = root.getPropertyValue('--color').trim()
// 设置属性值
document.documentElement.style.setProperty('--color', 'green')
const color2 = root.getPropertyValue('--color').trim()

console.log(color1, color2) // red green

// 给元素设置样式
const body = document.querySelector('body')
document.querySelector('body').style.backgroundColor = color2
// body的背景色将被设置为绿色
  • 读写元素属性
<div id="welc" style="-text-pos: center;">
</div>
// 获取welc元素下定义的属性值,给body设置该值
const welc = document.getElementById('welc')
const align = welc.style.getPropertyValue('--text-pos')
// welc.style.setProperty('--text-pos', 'left')
document.querySelector('body').style.textAlign = align

使用:root主题切换

当我们使用:root选择器定义全局属性,就可以通过该选择器进行主题切换的工作。
这里,我们还需要引入 theme,结合:root选择器和js就可以较好的处理了,具体如下:

  • 定义不同主题的全局属性,如下就是定义了黑色和白色主题:
:root[theme="black"] {
  --color: #000;
}
:root[theme="white"] {
  --color: #fff;
}
  • 在web页面中使用这些自定义属性变量,略过
  • 通过js改变theme的值,就可以切换主题,如下:
const setDocumentTheme = (theme = 'white') => {
  const docElm = document.documentElement
  if (!docElm.hasAttribute('theme')) {
    docElm.setAttribute('theme', theme)
  } else {
    docElm.removeAttribute('theme')
  }
}

通过调用上面的js函数,就可以切换主题,改变web页面的UI样式。

大部分主流浏览器都能使用,当然,除了IE。

623925c2dd2bb.jpg

也可以使用js进行检测,ie下支持这种方式检测:

// 是否支持自定义属性
window.CSS && window.CSS.supports && window.CSS.supports('--a', 0)

也可以使用css的 @supports 进行判断,但ie不支持该css特性,所以几乎没用:

@supports ((--a: 0)) {
  /* 支持 */
}
@supports (not (--a: 0)) {
  /* 不支持 */
}

来自:https://www.cnblogs.com/jimojianghu/archive/2022/03/21/16016516.html

链接: https://www.fly63.com/article/detial/11278


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK