用JavaScript修改CSS样式表是可行的吗?(不是对象的样式,而是样式表本身)

57

能否使用JavaScript更改CSS样式表?

是在讨论以下内容:

document.getElementById('id').style._____='.....';

我指的是修改:

#id {
    param: value;
}

除了做一些“肮脏的事情”(我们还没有尝试过),比如在头部创建一个新对象,在其中innerHTML一个样式标签等等。虽然如此,即使它起作用,也会带来一些问题,因为样式块已经在其他地方定义了,而且我不确定浏览器何时/是否会解析动态创建的样式块。


值得一试的是,在JavaScript中创建一个<style>元素,然后将其附加到<head>元素的末尾。我猜它会在被附加时立即应用,就像链接到样式表的<link>一样。这可能比尝试编辑样式表本身更可靠。 - Paul D. Waite
8个回答

45

是的,你可以;每个浏览器都支持这一点,包括IE9+。

  • insertRule() 方法允许动态添加样式规则到样式表中。

  • 使用 deleteRule() 方法,可以从样式表中移除现有的规则。

  • 样式表中的规则可以通过样式表的 cssRules 属性进行访问。


16

我们可以使用 .insertRule.cssRules 的组合方式,以便能够在 IE9 上实现这一点:

function changeStylesheetRule(stylesheet, selector, property, value) {
    // Make the strings lowercase
    selector = selector.toLowerCase();
    property = property.toLowerCase();
    value = value.toLowerCase();
    
    // Change it if it exists
    for(var i = 0; i < stylesheet.cssRules.length; i++) {
        var rule = stylesheet.cssRules[i];
        if(rule.selectorText === selector) {
            rule.style[property] = value;
            return;
        }
    }
  
    // Add it if it does not
    stylesheet.insertRule(selector + " { " + property + ": " + value + "; }", 0);
}

// Used like so:
changeStylesheetRule(s, "body", "color", "rebeccapurple");

演示


如果您在旧浏览器上遇到问题,将“.cssRules”更改为“.rules”可能会有所帮助。对于Chrome,您还可以省略“.insertRule”的第二个参数,但其他浏览器(如FF)则需要它。 - Zach Saucier
1
如果您在修改样式时浏览器没有更新,您可以先删除样式,然后再重新添加。这可以通过更改“for”循环并添加s.deleteRule(i)以及删除“return”语句来完成。 - u01jmg3
2
值得注意的是,由于小写化,诸如backgroundPosition之类的属性将无法工作。为了在insertRule()中使用,这也需要转换为其连字符等效形式(background-position)。 - u01jmg3
这并不符合原始发布者的意图。编辑后的规则被分配给了一个<style>对象,如检查器中所见,而不是实际的样式表。 - Banderi

6

2020

此方法的一些优点:

  • 不需要(但允许)指定样式表。
  • 允许同时添加/修改多个样式。
  • 接受!important 属性。
  • 匹配CSS选择器时忽略额外的空格。
  • 更改最后一个匹配的现有规则,或追加到最后一个匹配的样式表中。(其他答案会添加/更改第一个规则,可能会被覆盖。)

用法:

adjustCSSRules('#myDiv', 'width: 300px !important');

方法:

function adjustCSSRules(selector, props, sheets){

    // get stylesheet(s)
    if (!sheets) sheets = [...document.styleSheets];
    else if (sheets.sup){    // sheets is a string
        let absoluteURL = new URL(sheets, document.baseURI).href;
        sheets = [...document.styleSheets].filter(i => i.href == absoluteURL);
        }
    else sheets = [sheets];  // sheets is a stylesheet

    // CSS (& HTML) reduce spaces in selector to one.
    selector = selector.replace(/\s+/g, ' ');
    const findRule = s => [...s.cssRules].reverse().find(i => i.selectorText == selector)
    let rule = sheets.map(findRule).filter(i=>i).pop()

    const propsArr = props.sup
        ? props.split(/\s*;\s*/).map(i => i.split(/\s*:\s*/)) // from string
        : Object.entries(props);                              // from Object

    if (rule) for (let [prop, val] of propsArr){
        // rule.style[prop] = val; is against the spec, and does not support !important.
        rule.style.setProperty(prop, ...val.split(/ *!(?=important)/));
        }
    else {
        sheet = sheets.pop();
        if (!props.sup) props = propsArr.reduce((str, [k, v]) => `${str}; ${k}: ${v}`, '');
        sheet.insertRule(`${selector} { ${props} }`, sheet.cssRules.length);
        }
    }

示例

该方法需要三个参数:

  • selector [字符串] - CSS 选择器,例如:'#myDiv'
    空格会被自动缩减(.myClass #myDiv 将匹配 .myClass #myDiv
  • rules [CSS 字符串、对象] - 例如(两种方式都可以接受):
    • { border: "solid 3px green", color: "white" }
    • 'border: solid 3px green; color: white'
  • sheet (可选) [字符串, 样式表]
    • 如果为空,则会检查所有样式表。
    • 'myStyles.css' 相对或绝对 URL
    • document.styleSheets[1] - 指向样式表的引用

其他示例:

adjustCSSRules('#myDiv', {width: '30px'}); // all stylesheets
adjustCSSRules('#myDiv', 'width: 30px', 'style.css'); // style.css only  
adjustCSSRules('#myDiv  .myClass', 'width: 30px', document.styleSheets[0]); // only first stylesheet

4

当我想要通过编程方式为对象添加一堆样式时,我发现将一个类编程地添加到对象中更容易(这个类在你的CSS中有与之相关联的样式)。你可以在你的CSS中控制优先级顺序,以便来自新类的新样式可以覆盖以前的样式。这通常比直接修改样式表要容易得多,并且可以完美地跨浏览器工作。


这是一个很好的想法。今晚我们将测试各种做事情的方式,并会回来告诉你哪种方法对我们最有效 :) - anonymous-one

2

更改样式规则中的属性

function change_css_style (titulo,selector,propiedad,valor) {        
        let i=0;
        while (i<document.styleSheets.length) {
            if (document.styleSheets[i].title==titulo) {
                let y=0;
                while (y<document.styleSheets[i].cssRules.length) {
                    if (document.styleSheets[i].cssRules[y].selectorText==selector) {                                               
                        document.styleSheets[i].cssRules[y].style[propiedad] = valor;                                                                       
                        y = document.styleSheets[i].cssRules.length;
                    } 
                    y++;
                }               
                i=document.styleSheets.length;
            } 
            i++;
        }

    }

演示

<style title="chat_inicio">
    .contenido .mensajes {
          width: 100px;
          height: 300px;    
    }
</style>

使用选择器.contenido .mensajes,将标题为chat_inicio的样式表中的width属性更改为475px
<script>
     cambiar_css_style ('chat_inicio','.contenido .mensajes','width','475px');
</script>

0

.style.cssText属性可用,尝试使用以下代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    *{
        margin: 0%;
        padding: 0%;
    }

    html {
        --theme-orange: orangered;
        --theme-blue: rgb(67, 67, 197);
        --theme-green: darkgreen;
        --theme-black: black;
        --theme-color: var(--theme-orange);
    }

    body {
        font-family: 'Roboto', sans-serif;
        background-color: rgb(251, 251, 251);
    }

    .nav-bar ul {
        display: flex;
        width: 100%;
        background-color: var(--theme-color);
        flex-wrap: wrap;
        flex-direction: row;
        align-items: center;
        width: 100%;
    }

    .nav-bar ul a {
        text-decoration: none;
        margin: 15px 10px;
    }

    .nav-bar .theme {
        background-color: white;
        display: flex;
        height: fit-content;
        margin-left: auto;
        margin-right: 20px;
        border-radius: 10px;
    }

    .nav-bar .theme .box {
        width: 20px;
        height: 20px;
        border: 1px solid black;
        cursor: pointer;  
    }

    .nav-bar .theme .orange {
        background-color: var(--theme-orange);
    }

    .nav-bar .theme .blue {
        background-color: var(--theme-blue);
    }

    .nav-bar .theme .green {
        background-color: var(--theme-green);
    }

    .nav-bar .theme .black {
        background-color: var(--theme-black);
    }

    .nav-bar ul li {
        color: white;
        font-weight: 500;
        list-style: none;
        padding: 10px 30px;
        background-color: var(--theme-color);
        transition: 0.2s;
    }

    .nav-bar ul li:hover {
        box-shadow: inset 10px 10px 10px -12px;
        scale: 0.95;
    }

</style>
<body>
    <div class="nav-bar">
        <ul>
            <a href=""><li>Home</li></a>
            <a href=""><li>Page 1</li></a>
            <a href=""><li>Page 2</li></a>
            <a href=""><li>About Us</li></a>
            <a href=""><li>Contact Us</li></a>
            <div class="theme">
                <a><div class="box orange" id="orange"></div></a>
                <a><div class="box blue" id="blue"></div></a>
                <a><div class="box green" id="green"></div></a>
                <a><div class="box black" id="black"></div></a>
            </div>
        </ul>
    </div>

    <script>
        function colorChange(color) {
            const htmlTag = document.getElementsByTagName("*")[0];
            htmlTag.style.cssText = `--theme-orange: orangered;
            --theme-blue: rgb(67, 67, 197);
            --theme-green: darkgreen;
            --theme-black: black;
            --theme-color: var(--theme-${color});`;
        }

        function addEventListenerForBox() {
            allBox = document.querySelectorAll('.box');
            allBox.forEach(box => {
                box.addEventListener('click', (event) => {
                    colorChange(event.target.id);
                });
            });
        }

        document.addEventListener('DOMContentLoaded', addEventListenerForBox);
    </script>
</body>
</html>

结果: 在此输入图片描述

enter image description here

enter image description here

enter image description here


0
一个解决方案是:
内容CSS文件:
#casesDndDropdown {
    background: #FFFFFF;
    border: 4px
}

您可以通过在标签内的<style>标签中定义来覆盖#casesDndDropdown或任何CSS类

jQuery

$('<style>#id{background: #428bca;border: 0px}</style>').appendTo('body');

0

2023/2

几年前我在w3schools: HTML style Tag中读到,<style>元素支持HTML全局属性HTML事件属性

上述意味着,在hrefreltarget之外,任何样式表都可以通过切换其disabled属性来禁用。我不得不深入挖掘以验证此规范是何时和如何实现的,并找到了一份旧的(2000年11月W3C文档,其中已经提到了对样式表的disabled属性的支持。

tl;dr

  • <style disabled>这样将disabled直接放在样式定义中是无效的。
  • 使用Javascript切换disabled属性false/true禁用/启用整个引用的<style>...</style>块,不管此块位于文档中的何处。
  • 现在,规划文档中样式块的位置成为了一个问题,因为常规浏览器逻辑是'后来居上'。

您只需要一个样式表元素的引用以及几个Javascript一行代码:

function disabledToggle(e) { e.disabled = !e.disabled }
function disabledOff   (e) { e.disabled = false }
function disabledOn    (e) { e.disabled = true }

知道了

  • 请查看上述W3C文档中的media属性规范。
  • <link>元素还支持上述提到的HTML全局属性HTML事件属性

本质上,一直以来都可以用一个简单的方法摧毁样式表

一个简单的概念证明

<html>
<head>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

<!-- Alternate font, activated in default <style>, but can be toggled on/off -->
<link id="lnk-poppins" href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet">

    <!-- Default styling, considered 'always active' -->
    <style>
        *    { box-sizing: border-box }
        body { font-family: Poppins, sans-serif }

        .square {
            margin: 5rem auto;
            width : 50vmin; aspect-ratio: 1;
            background-color: CornflowerBlue;
        }
    </style>

    <!-- Media controlled style, only active on small devices -->
    <style media="all and (max-width: 640px)">
        body { 
            margin: 0; padding: 1rem;
            width: 100%; min-height: 100vh;
            background-color: hsl(90,100%,50%,.3);
        }

    </style>

    <!-- Alternative styles: last in, first serve, so order matters -->
    <style id="stl-red"  >.square { background-color: Red   }</style>
    <style id="stl-green">.square { background-color: Green }</style>
    <style id="stl-blue" >.square { background-color: Blue  }</style>
    
    <!-- Default style, but can be toggled: overrides all above when enabled -->
    <style id="stl-default" >.square { background-color: Black }</style>
</head>

<body>
    <fieldset>
        <legend>&nbsp;Style Toggles&nbsp;</legend>
        <p>Colors:</p>
        <label for="default">
            <input id="default" class="radio" type="radio" name="group" checked
                   oninput="disabledOff(defa);">
            Default
        </label>
        <label for="red">
            <input id="red" class="radio" type="radio" name="group"
                   oninput="disabledOff(red);disabledOn(defa);disabledOn(blue);disabledOn(green);">
            Red
        </label>
        <label for="green">
            <input id="green" class="radio" type="radio" name="group"
                   oninput="disabledOff(green);disabledOn(defa);disabledOn(blue);">
            Green
        </label>
        <label for="blue">
            <input id="blue" class="radio" type="radio" name="group"
                   oninput="disabledOff(blue);disabledOn(defa);">
            Blue
        </label>
        <p>Font:</p>
        <label for="poppins">
            <input id="poppins" type="checkbox" oninput="disabledToggle(popp);" checked>
            Poppins
        </label>
        
        <br><br>
        <span>Old W3C Reference: <a target="_blank" href="https://www.w3.org/TR/DOM-Level-2-Style/stylesheets.html#StyleSheets-StyleSheet-disabled">Attributes: <b>disabled</b> of type boolean</a></span>
    </fieldset>

    <div class="square"></div>
    
<script>
const red   = document.getElementById('stl-red');
const green = document.getElementById('stl-green');
const blue  = document.getElementById('stl-blue');
const defa  = document.getElementById('stl-default');
const popp  = document.getElementById('lnk-poppins');
    
function disabledToggle(e) { e.disabled = !e.disabled }
function disabledOff   (e) { e.disabled = false }
function disabledOn    (e) { e.disabled = true }
</script>
</body>
</html>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接