如何在SCSS中利用HTML自定义属性简化明暗主题切换代码?
优化明暗主题切换的SCSS代码冗余问题
现有实现方案
HTML标记
<body name="body" theme="dark">
JavaScript切换逻辑
let themeToggle = document.getElementById("theme-toggle") let body = document.getElementsByName("body").item(0) let currentTheme = body.getAttribute("theme") function toggleTheme() { currentTheme = (currentTheme == "dark") ? "light" : "dark" body.setAttribute("theme", currentTheme) }
SCSS的冗余问题
当前拆分的dark.scss和light.scss代码高度重复,仅主题变量和选择器条件不同:
dark.scss:
@use 'colors' as c; body[theme="dark"] { background-color: c.$dark-background; #theme-toggle { border-color: c.$light-background; } div { background-color: c.$dark-accent; } }
light.scss:
@use 'colors' as c; body[theme="light"] { background-color: c.$light-background; #theme-toggle { border-color: c.$dark-background; } div { background-color: c.$light-accent; } }
你之前尝试的写法失败原因:attr(theme)是CSS运行时函数,无法在SCSS预编译阶段获取HTML属性值,SCSS的变量逻辑是编译时执行的,无法感知运行时的DOM状态。
正确的SCSS优化方案
利用SCSS的@each循环遍历主题配置,一次性生成两种主题的样式,彻底消除代码冗余:
首先确保_colors.scss变量命名规范:
// _colors.scss $dark-background: #1a1a1a; $light-background: #ffffff; $dark-accent: #2d2d2d; $light-accent: #f5f5f5;
创建统一的主题样式文件_themes.scss:
@use 'colors' as c; // 定义主题映射:激活主题 => 对应反主题 $themes: ( dark: light, light: dark ); @each $active-theme, $inactive-theme in $themes { body[theme="#{$active-theme}"] { background-color: c.$#{$active-theme}-background; #theme-toggle { border-color: c.$#{$inactive-theme}-background; } div { background-color: c.$#{$active-theme}-accent; } } }
最后在主样式文件style.scss中引入:
// style.scss @use 'themes'; // 其他布局样式代码...
原理说明
- SCSS的
@each循环在编译阶段遍历主题配置,自动生成body[theme="dark"]和body[theme="light"]两个选择器的完整样式,和手动编写两个文件的效果完全一致,但代码只需维护一次。 - 通过插值语法
#{$variable}动态拼接变量名和选择器字符串,实现根据主题名调用对应颜色变量。
后续修改主题样式时,仅需调整循环内的代码块即可,无需同时修改多个文件。
内容的提问来源于stack exchange,提问作者Lolmerkat
相关产品推荐
相关产品推荐

