如何通过编程方式启用样式表?

前端开发 2026-07-08

我正在处理一些用于主题切换的代码。于是我查看CSSOM,它有一个 StyleSheet.disabled 属性。看起来很直接。只要根据样式表/链接是否代表当前主题来设置disabled属性。这给了我一个类似这样的(过于简化的)JavaScript:

for (const styleSheet of document.styleSheets) {
  styleSheet.disabled = styleSheet.title !== currentThemeName;
}

我试了一下。禁用工作正常,但我遇到非常奇怪的行为:有些样式表有时会被启用,但有时不会,且没有解释(至少在Chromium上如此,Firefox上却能工作)。我通过手动测试确认该属性确实被正确设置。

于是我在MDN文档中注意到这一点:

Note that disabled === false does not guarantee the style sheet is applied (it could be removed from the document, for instance).

The standard 甚至更模糊:

Note: Even when unset it does not necessarily mean that the CSS style sheet is actually used for rendering.

好吧,我发现link元素和style元素有一个 disabled 标志。也许那就是解决办法。于是得到类似这样的:

const styleElems = [...document.querySelectorAll('style[title]'), ...document.querySelectorAll('link[rel="stylesheet"][title]');

for (const styleElem of styleElems) {
  styleElem.disabled = styleElem.title !== currentThemeName;
}

同样的行为。再次,我查看标准,对于 HTMLStyleElement,它只是为在相关的样式表上设置 StyleSheet.disabled 的一个快捷方式。

看起来 disabled 属性在实际作用上几乎没有用处,如果你不能保证启用样式表会工作。还有别的办法吗?

解决方案

问题在于,通过在你的 <link><style> 元素上设置 title 属性,你在选择 替代样式表 模式(MDN链接,不过其中的 title 属性在其中是隐藏的) 。

这是一个鲜为人知的特性(至少在你的问题之前我也没听说过),它使用户代理能够向用户显示一个选项,让用户直接从浏览器UI切换不同的主题。

因此,借助这个特性,你可以让浏览器本身来处理主题切换,只需把 title 属性设置为任意主题名即可。这样用户就可以在浏览器中切换主题,而无需任何JS。例如在Firefox中,它在View > Page Style > Your theme中。其他浏览器则需要一个扩展来实现切换,不过它们仍然会遵守规格所规定的公开行为。

这也就意味着如果用户自己不切换到那个主题,即使你把 disabled 属性关掉,浏览器也会自动禁用它。

因此,如果你想通过JS控制主题切换(这可能更好,因为这是一个鲜为人知的特性,且没有浏览器级的广泛支持),你就不应该设置 title 属性。相反,你可以使用一个 data- 属性:

const select = document.querySelector("select");
select.onchange = e => {
  const currentThemeName = select.value;
  for (const styleElem of document.querySelectorAll(":is(link,style)[data-title]")) {
    styleElem.disabled = styleElem.dataset.title !== currentThemeName;
  }
}
select.onchange();
<link data-title="red" rel=stylesheet href="data:text/css,body{color:red}">
<link data-title="green" rel=stylesheet href="data:text/css,body{color:green}">
<style data-title="red">p { border: 1px solid blue }</style>
<style data-title="green">p { border: 1px solid pink }</style>

<select>
  <option>red</option>
  <option>green</option>
</select>
<p>I should change color and border.</p>
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章