SASS中如何基于data-theme属性条件导入明暗主题CSS文件
问题根因
当前写法不生效的核心原因是CSS原生语法要求@import规则必须放在样式表最顶部(仅允许出现在@charset、@layer定义语句之后),不能嵌套在任意选择器内部。
把@import写在:root、[data-theme="dark"]这类选择器内部时,浏览器解析CSS会直接忽略这些导入语句的嵌套位置,把所有@import提到样式表最顶部按书写顺序加载。示例代码里dark-theme.css导入顺序更靠后,样式优先级更高,会始终覆盖前面的浅色主题规则,因此无论怎么切换data-theme属性,页面都只显示暗色样式。
另外注意:SCSS 自身的嵌套导入能力仅对.scss文件生效,导入纯.css外部文件时,SCSS 只会原样输出标准CSS的@import语句,不会把CSS内容嵌套进外层选择器。
可行方案(无需手动修改两个外部大体积CSS文件)
方案1:JS动态控制样式表启用(大体积文件首选,性能最优)
首屏只加载当前激活的主题样式,不会加载冗余CSS,切换无闪烁,适配大体积样式文件场景:
- 在HTML中提前引入两个主题样式表,给非默认主题加
disabled属性禁止默认加载:
<!-- 默认加载浅色主题 --> <link rel="stylesheet" href="light-theme.css" data-theme-asset="light"> <link rel="stylesheet" href="dark-theme.css" data-theme-asset="dark" disabled>
- 写主题切换逻辑,切换
data-theme属性时同步控制两个样式表的启用状态:
// 主题设置方法 const applyTheme = (themeName) => { // 同步设置根节点属性 document.documentElement.setAttribute('data-theme', themeName); // 切换样式表启用状态 document.querySelectorAll('[data-theme-asset]').forEach(link => { link.disabled = link.dataset.themeAsset !== themeName; }); // 持久化用户选择 localStorage.setItem('preferred-theme', themeName); } // 初始化:优先读取用户本地存储的主题配置,没有则默认用浅色 const initTheme = localStorage.getItem('preferred-theme') || 'light'; applyTheme(initTheme); // 绑定主题切换按钮事件示例 document.querySelector('#themeToggleBtn').addEventListener('click', () => { const currentTheme = document.documentElement.getAttribute('data-theme'); applyTheme(currentTheme === 'light' ? 'dark' : 'light'); });
方案2:构建时自动注入选择器前缀(无运行时开销,适合有构建流程的项目)
如果你项目使用Vite、Webpack、Rollup等构建工具,可以用CSS前缀类插件,在构建阶段自动给两个主题文件的所有样式规则前面加上对应的属性选择器,全程不需要手动修改原CSS文件:
- 给
light-theme.css的所有选择器自动添加前缀[data-theme="light"] - 给
dark-theme.css的所有选择器自动添加前缀[data-theme="dark"]
配置完成后直接在SCSS顶部正常导入两个CSS文件即可,浏览器会自动根据根节点的data-theme属性匹配对应样式,切换属性时样式自动生效,不需要额外写JS控制样式加载。
注意:该方案会把两个主题CSS都打包到产物中,首屏会加载两份主题样式,如果单份主题CSS体积超过200KB,更推荐用方案1的动态加载方式。
内容的提问来源于stack exchange,提问作者Vikash Balasubramanian
相关产品推荐
相关产品推荐

