如何修改style标签内指定CSS样式而不覆盖原有全部样式?
我在网上找到如下代码:
function largeFont() { const dStyle = document.querySelector('style'); dStyle.innerHTML = 'p {font-size: 2rem;}'; }
但上述代码会清空<style></style>标签内的所有原有内容,仅写入p {font-size: 2rem;}。我想了解是否可以直接修改<style></style>标签内的指定样式规则,例如类似如下的调用形式:
document.querySelector('style').body or document.querySelector('style').#box document.querySelector('style').box.background-color
或是其他等效实现方式。我知晓内联样式的实现方法,但当前场景下不希望使用内联样式。我也考虑过解析style标签内的全部文本,通过查找替换的方式修改指定内容,想确认是否有更规范的实现方案。
你预想的那种链式属性访问style标签内部规则的写法不存在,浏览器原生提供了CSSOM系列接口专门操作样式表,不需要手动解析替换style标签的文本内容,也不会覆盖原有样式,是目前的标准实现方案。
直接修改已有样式规则
通过document.querySelector('style')拿到的style标签节点,自带sheet属性,对应该标签的CSSStyleSheet实例,标签内所有样式规则都存放在实例的cssRules类数组列表中,遍历找到对应选择器的规则后,就可以像操作内联样式一样直接修改属性:
function largeFont() { // 获取style标签对应的样式表实例 const styleSheet = document.querySelector('style').sheet; const rules = styleSheet.cssRules; // 遍历查找匹配p选择器的规则 for (const rule of rules) { if (rule.selectorText === 'p') { // 直接修改对应样式属性,驼峰写法和element.style一致 rule.style.fontSize = '2rem'; return; } } // 没找到对应规则就新增一条 styleSheet.insertRule('p {font-size: 2rem;}', rules.length); }
如果要修改#box的背景色,只需要把判断条件改成rule.selectorText === '#box',再设置rule.style.backgroundColor = 'xxx'即可,逻辑和你预期的操作方式一致,只是需要先从规则列表中匹配到目标选择器。
追加新规则覆盖原有样式
如果不需要改动旧规则,只是要让新的样式生效,完全不需要遍历查找旧规则,直接在样式表末尾插入新规则即可。由于CSS后写的同优先级规则会覆盖前面的规则,效果和修改旧规则完全一致,实现更简单:
function largeFont() { const styleSheet = document.querySelector('style').sheet; // 在样式表末尾插入新规则,不会影响任何已有规则 styleSheet.insertRule('p {font-size: 2rem;}', styleSheet.cssRules.length); }
注意事项
- 不要用手动拼接、替换style标签innerHTML的方式修改样式,很容易因为转义错误、选择器匹配偏差损坏原有样式,CSSOM接口是浏览器原生解析规则,不存在这类问题。
- 跨域引入的外部样式表受同源策略限制,无法访问
cssRules内容,但操作页面内嵌入的style标签没有这个限制。 cssRules列表里除了普通样式规则,还会包含媒体查询、关键帧动画等特殊规则,遍历的时候如果只需要修改普通元素样式,可以加一层判断rule.type === CSSRule.STYLE_RULE过滤其他类型规则。
内容的提问来源于stack exchange,提问作者A bonafide dabbler

