Wie erstelle ich eine CSS-Klasse dynamisch in JavaScript und wende sie an?


Antworten:


394

Obwohl ich nicht sicher bin, warum Sie CSS-Klassen mit JavaScript erstellen möchten, ist hier eine Option:

var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = '.cssClass { color: #F00; }';
document.getElementsByTagName('head')[0].appendChild(style);

document.getElementById('someElementId').className = 'cssClass';

10
Mein Anwendungsfall ist ein Lesezeichen, das bestimmte Elemente für QS-Zwecke hervorhebt.
TomG

25
Ziemlich sicher, dass dies zu einem unbekannten Laufzeitfehler in IE 8 und weniger führt.
Andy Hume

1
Mein Anwendungsfall ist das Laden einer zufälligen Google-Webschriftart und das anschließende Zuweisen der Schriftfamilie zur randomFont-Klasse :-)
w00t

26
Ein anderer Anwendungsfall wäre, wenn Sie eine einzelne JS-Bibliothek ohne Abhängigkeiten von CSS-Dateien möchten. In meinem Fall möchte ich sofort ein leichtes Warn-Popup im Knurrstil.
Xeolabs

1
Ich mache so etwas wie w00t. Ich arbeite an einer interaktiven HTML5-App, die auf einer Leinwand geschrieben wird, und möchte, dass mein Benutzer aus einer Vielzahl von zu verwendenden Schriftarten auswählen kann. Anstatt ein langes CSS mit der gesamten Schriftart zu haben, plane ich, ein Backend zu erstellen, in das ich nur die Schriftartdaten hochlade. Wenn das Programm geladen wird, bringt ein kleiner Aufruf eines Webservices die Schriftart und fügt sie hinzu
CJLopez

117

Es wurde eine bessere Lösung gefunden, die in allen Browsern funktioniert.
Verwendet document.styleSheet, um Regeln hinzuzufügen oder zu ersetzen. Die akzeptierte Antwort ist kurz und praktisch, funktioniert jedoch in IE8 und weniger.

function createCSSSelector (selector, style) {
  if (!document.styleSheets) return;
  if (document.getElementsByTagName('head').length == 0) return;

  var styleSheet,mediaType;

  if (document.styleSheets.length > 0) {
    for (var i = 0, l = document.styleSheets.length; i < l; i++) {
      if (document.styleSheets[i].disabled) 
        continue;
      var media = document.styleSheets[i].media;
      mediaType = typeof media;

      if (mediaType === 'string') {
        if (media === '' || (media.indexOf('screen') !== -1)) {
          styleSheet = document.styleSheets[i];
        }
      }
      else if (mediaType=='object') {
        if (media.mediaText === '' || (media.mediaText.indexOf('screen') !== -1)) {
          styleSheet = document.styleSheets[i];
        }
      }

      if (typeof styleSheet !== 'undefined') 
        break;
    }
  }

  if (typeof styleSheet === 'undefined') {
    var styleSheetElement = document.createElement('style');
    styleSheetElement.type = 'text/css';
    document.getElementsByTagName('head')[0].appendChild(styleSheetElement);

    for (i = 0; i < document.styleSheets.length; i++) {
      if (document.styleSheets[i].disabled) {
        continue;
      }
      styleSheet = document.styleSheets[i];
    }

    mediaType = typeof styleSheet.media;
  }

  if (mediaType === 'string') {
    for (var i = 0, l = styleSheet.rules.length; i < l; i++) {
      if(styleSheet.rules[i].selectorText && styleSheet.rules[i].selectorText.toLowerCase()==selector.toLowerCase()) {
        styleSheet.rules[i].style.cssText = style;
        return;
      }
    }
    styleSheet.addRule(selector,style);
  }
  else if (mediaType === 'object') {
    var styleSheetLength = (styleSheet.cssRules) ? styleSheet.cssRules.length : 0;
    for (var i = 0; i < styleSheetLength; i++) {
      if (styleSheet.cssRules[i].selectorText && styleSheet.cssRules[i].selectorText.toLowerCase() == selector.toLowerCase()) {
        styleSheet.cssRules[i].style.cssText = style;
        return;
      }
    }
    styleSheet.insertRule(selector + '{' + style + '}', styleSheetLength);
  }
}

Die Funktion wird wie folgt verwendet.

createCSSSelector('.mycssclass', 'display:none');

2
Bestätigte Arbeit mit IE8. Ich musste ein "styleSheet.cssRules [i] .selectorText &&" und ein "styleSheet.rules [i] .selectorText &&" in die for-Schleife ifs von mediaType einfügen, da dies in Chrome nicht funktionierte, anscheinend ist manchmal der selectorText nicht nicht definiert.
w00t

@ w00t Könnten Sie bitte den Code einfügen oder bearbeiten, damit er funktioniert?
Hengjie

Ich habe gerade Chrome (Version 34.0.1847.132) geöffnet, die Funktionen eingefügt und ausgeführt, aber es hat nicht funktioniert: "TypeError: Eigenschaft 'Länge' von null kann nicht gelesen werden". Kann es sein, dass es nicht funktioniert, es von der Entwicklerkonsole aus zu erstellen?
dnuske

Es stellt sich heraus, dass einige Versionen von Chrom (oder Chrom) das Einfügen von Regeln in Index 0 nicht zulassen. Hier ist der Fix: styleSheet.insertRule (Selektor + "{" + Stil + "}", styleSheet.cssRules.length);
dnuske

1
@dnuske Ich bin auf das gleiche Problem gestoßen. Es stellt sich heraus, dass styleSheet.cssRules null ergibt. Das Update, das ich verwendet habe, besteht darin, eine neue Variable zu erstellen var styleSheetLength = styleSheet.cssRules ? styleSheet.cssRules.length : 0und ihre Verwendung durch die Implementierung der Funktion zu ersetzen.
Raj Nathani

27

Kurze Antwort, dies ist "auf allen Browsern" kompatibel (speziell IE8 / 7):

function createClass(name,rules){
    var style = document.createElement('style');
    style.type = 'text/css';
    document.getElementsByTagName('head')[0].appendChild(style);
    if(!(style.sheet||{}).insertRule) 
        (style.styleSheet || style.sheet).addRule(name, rules);
    else
        style.sheet.insertRule(name+"{"+rules+"}",0);
}
createClass('.whatever',"background-color: green;");

Und dieses letzte Bit wendet die Klasse auf ein Element an:

function applyClass(name,element,doRemove){
    if(typeof element.valueOf() == "string"){
        element = document.getElementById(element);
    }
    if(!element) return;
    if(doRemove){
        element.className = element.className.replace(new RegExp("\\b" + name + "\\b","g"));
    }else{      
        element.className = element.className + " " + name;
    }
}

Hier ist auch eine kleine Testseite: https://gist.github.com/shadybones/9816763

Das Wichtigste ist die Tatsache, dass Stilelemente eine "styleSheet" / "sheet" -Eigenschaft haben, mit der Sie Regeln hinzufügen / entfernen können.


Das schafft also bei jeder Klassenerstellung ein neues "Stil" -Element? Wenn ich also mehr als 1000 Klassen in einer for-Schleife basierend auf Daten erstellen würde, müsste document.head.appendChild 1000 Mal angewendet werden?
Bluejayke

für mich in chrome style.sheet und style.styleSheet existiert nicht
bluejayke


7

YUI hat mit Abstand das beste Stylesheet-Dienstprogramm, das ich je gesehen habe. Ich ermutige Sie, es auszuprobieren, aber hier ist ein Vorgeschmack:

// style element or locally sourced link element
var sheet = YAHOO.util.StyleSheet(YAHOO.util.Selector.query('style',null,true));

sheet = YAHOO.util.StyleSheet(YAHOO.util.Dom.get('local'));


// OR the id of a style element or locally sourced link element
sheet = YAHOO.util.StyleSheet('local');


// OR string of css text
var css = ".moduleX .alert { background: #fcc; font-weight: bold; } " +
          ".moduleX .warn  { background: #eec; } " +
          ".hide_messages .moduleX .alert, " +
          ".hide_messages .moduleX .warn { display: none; }";

sheet = new YAHOO.util.StyleSheet(css);

Es gibt offensichtlich andere viel einfachere Möglichkeiten, Stile im laufenden Betrieb zu ändern, wie die hier vorgeschlagenen. Wenn sie für Ihr Problem sinnvoll sind, sind sie vielleicht am besten, aber es gibt definitiv Gründe, warum das Ändern von CSS eine bessere Lösung ist. Der offensichtlichste Fall ist, wenn Sie eine große Anzahl von Elementen ändern müssen. Der andere wichtige Fall ist, wenn Sie Ihre Stiländerungen benötigen, um die Kaskade einzubeziehen. Die Verwendung des Doms zum Ändern eines Elements hat immer eine höhere Priorität. Dies ist der Vorschlaghammer-Ansatz und entspricht der Verwendung des style-Attributs direkt für das HTML-Element. Das ist nicht immer der gewünschte Effekt.


5

Ab IE 9. Sie können jetzt eine Textdatei laden und eine style.innerHTML-Eigenschaft festlegen. Im Wesentlichen können Sie jetzt eine CSS-Datei über Ajax laden (und den Rückruf erhalten) und dann einfach den Text in einem Style-Tag wie diesem festlegen.

Dies funktioniert in anderen Browsern, nicht sicher, wie weit zurück. Aber solange Sie IE8 nicht unterstützen müssen, würde es funktionieren.

// RESULT: doesn't work in IE8 and below. Works in IE9 and other browsers.
$(document).ready(function() {
    // we want to load the css as a text file and append it with a style.
    $.ajax({
        url:'myCss.css',
        success: function(result) {
            var s = document.createElement('style');
            s.setAttribute('type', 'text/css');
            s.innerHTML = result;
            document.getElementsByTagName("head")[0].appendChild(s);
        },
        fail: function() {
            alert('fail');
        }
    })
});

und dann können Sie es eine externe Datei wie die myCss.css ziehen lassen

.myClass { background:#F00; }

5

Hier ist Vishwanaths Lösung, die mit Kommentaren leicht umgeschrieben wurde:

function setStyle(cssRules, aSelector, aStyle){
    for(var i = 0; i < cssRules.length; i++) {
        if(cssRules[i].selectorText && cssRules[i].selectorText.toLowerCase() == aSelector.toLowerCase()) {
            cssRules[i].style.cssText = aStyle;
            return true;
        }
    }
    return false;
}

function createCSSSelector(selector, style) {
    var doc = document;
    var allSS = doc.styleSheets;
    if(!allSS) return;

    var headElts = doc.getElementsByTagName("head");
    if(!headElts.length) return;

    var styleSheet, media, iSS = allSS.length; // scope is global in a function
    /* 1. search for media == "screen" */
    while(iSS){ --iSS;
        if(allSS[iSS].disabled) continue; /* dont take into account the disabled stylesheets */
        media = allSS[iSS].media;
        if(typeof media == "object")
            media = media.mediaText;
        if(media == "" || media=='all' || media.indexOf("screen") != -1){
            styleSheet = allSS[iSS];
            iSS = -1;   // indication that media=="screen" was found (if not, then iSS==0)
            break;
        }
    }

    /* 2. if not found, create one */
    if(iSS != -1) {
        var styleSheetElement = doc.createElement("style");
        styleSheetElement.type = "text/css";
        headElts[0].appendChild(styleSheetElement);
        styleSheet = doc.styleSheets[allSS.length]; /* take the new stylesheet to add the selector and the style */
    }

    /* 3. add the selector and style */
    switch (typeof styleSheet.media) {
    case "string":
        if(!setStyle(styleSheet.rules, selector, style));
            styleSheet.addRule(selector, style);
        break;
    case "object":
        if(!setStyle(styleSheet.cssRules, selector, style));
            styleSheet.insertRule(selector + "{" + style + "}", styleSheet.cssRules.length);
        break;
    }

4

Ein interessantes Projekt, das Ihnen bei Ihrer Aufgabe helfen könnte, ist JSS .

JSS ist eine bessere Abstraktion gegenüber CSS. Es verwendet JavaScript als Sprache, um Stile deklarativ und wartbar zu beschreiben. Es handelt sich um einen leistungsstarken JS-CSS-Compiler, der zur Laufzeit in den Browsern und auf der Serverseite ausgeführt wird.

Mit der JSS-Bibliothek können Sie mithilfe der .attach()Funktion in den DOM / Head-Bereich injizieren .

Repl Online-Version zur Bewertung.

Weitere Informationen zu JSS .

Ein Beispiel:

// Use plugins.
jss.use(camelCase())

// Create your style.
const style = {
  myButton: {
    color: 'green'
  }
}

// Compile styles, apply plugins.
const sheet = jss.createStyleSheet(style)

// If you want to render on the client, insert it into DOM.
sheet.attach()

3

Verwenden von Google Closure:

Sie können einfach das ccsom-Modul verwenden:

goog.require('goog.cssom');
var css_node = goog.cssom.addCssText('.cssClass { color: #F00; }');

Der Javascript-Code versucht, browserübergreifend zu sein, wenn der CSS-Knoten in den Dokumentkopf eingefügt wird.


3

https://jsfiddle.net/xk6Ut/256/

Eine Option zum dynamischen Erstellen und Aktualisieren von CSS-Klassen in JavaScript:

  • Verwenden von Style Element zum Erstellen eines CSS-Abschnitts
  • Verwenden einer ID für das Stilelement, damit wir die CSS-
    Klasse aktualisieren können

..... .....

function writeStyles(styleName, cssText) {
    var styleElement = document.getElementById(styleName);
    if (styleElement) 
             document.getElementsByTagName('head')[0].removeChild(
        styleElement);
    styleElement = document.createElement('style');
    styleElement.type = 'text/css';
    styleElement.id = styleName;
    styleElement.innerHTML = cssText;
    document.getElementsByTagName('head')[0].appendChild(styleElement);
}

...

    var cssText = '.testDIV{ height:' + height + 'px !important; }';
    writeStyles('styles_js', cssText)

1

Durchgesehen durch die Antworten und das offensichtlichste und direkteste fehlt: Verwenden Sie document.write(), um einen Teil des CSS zu schreiben, den Sie benötigen.

Hier ist ein Beispiel (siehe Codepen: http://codepen.io/ssh33/pen/zGjWga ):

<style>
   @import url(http://fonts.googleapis.com/css?family=Open+Sans:800);
   .d, body{ font: 3vw 'Open Sans'; padding-top: 1em; }
   .d {
       text-align: center; background: #aaf;
       margin: auto; color: #fff; overflow: hidden; 
       width: 12em; height: 5em;
   }
</style>

<script>
   function w(s){document.write(s)}
   w("<style>.long-shadow { text-shadow: ");
   for(var i=0; i<449; i++) {
      if(i!= 0) w(","); w(i+"px "+i+"px #444");
   }
   w(";}</style>");
</script> 

<div class="d">
    <div class="long-shadow">Long Shadow<br> Short Code</div>
</div>

Dies ist in Ordnung, es sei denn, Sie müssen nach dem Laden der Seite CSS-Regeln erstellen oder verwenden XHTML.
Tim Down

1
function createCSSClass(selector, style, hoverstyle) 
{
    if (!document.styleSheets) 
    {
        return;
    }

    if (document.getElementsByTagName("head").length == 0) 
    {

        return;
    }
    var stylesheet;
    var mediaType;
    if (document.styleSheets.length > 0) 
    {
        for (i = 0; i < document.styleSheets.length; i++) 
        {
            if (document.styleSheets[i].disabled) 
            {
                continue;
            }
            var media = document.styleSheets[i].media;
            mediaType = typeof media;

            if (mediaType == "string") 
            {
                if (media == "" || (media.indexOf("screen") != -1)) 
                {
                    styleSheet = document.styleSheets[i];
                }
            } 
            else if (mediaType == "object") 
            {
                if (media.mediaText == "" || (media.mediaText.indexOf("screen") != -1)) 
                {
                    styleSheet = document.styleSheets[i];
                }
            }

            if (typeof styleSheet != "undefined") 
            {
                break;
            }
        }
    }

    if (typeof styleSheet == "undefined") {
        var styleSheetElement = document.createElement("style");
        styleSheetElement.type = "text/css";
        document.getElementsByTagName("head")[0].appendChild(styleSheetElement);
        for (i = 0; i < document.styleSheets.length; i++) {
            if (document.styleSheets[i].disabled) {
                continue;
            }
            styleSheet = document.styleSheets[i];
        }

        var media = styleSheet.media;
        mediaType = typeof media;
    }

    if (mediaType == "string") {
        for (i = 0; i < styleSheet.rules.length; i++) 
        {
            if (styleSheet.rules[i].selectorText.toLowerCase() == selector.toLowerCase()) 
            {
                styleSheet.rules[i].style.cssText = style;
                return;
            }
        }

        styleSheet.addRule(selector, style);
    }
    else if (mediaType == "object") 
    {
        for (i = 0; i < styleSheet.cssRules.length; i++) 
        {
            if (styleSheet.cssRules[i].selectorText.toLowerCase() == selector.toLowerCase()) 
            {
                styleSheet.cssRules[i].style.cssText = style;
                return;
            }
        }

        if (hoverstyle != null) 
        {
            styleSheet.insertRule(selector + "{" + style + "}", 0);
            styleSheet.insertRule(selector + ":hover{" + hoverstyle + "}", 1);
        }
        else 
        {
            styleSheet.insertRule(selector + "{" + style + "}", 0);
        }
    }
}





createCSSClass(".modalPopup  .header",
                                 " background-color: " + lightest + ";" +
                                  "height: 10%;" +
                                  "color: White;" +
                                  "line-height: 30px;" +
                                  "text-align: center;" +
                                  " width: 100%;" +
                                  "font-weight: bold; ", null);

Was ist, wenn es kein aktuelles Stylesheet auf dem Dokument gibt
Bluejayke

1

Hier ist meine modulare Lösung:

var final_style = document.createElement('style');
final_style.type = 'text/css';

function addNewStyle(selector, style){
  final_style.innerHTML += selector + '{ ' + style + ' } \n';
};

function submitNewStyle(){
  document.getElementsByTagName('head')[0].appendChild(final_style);

  final_style = document.createElement('style');
  final_style.type = 'text/css';
};

function submitNewStyleWithMedia(mediaSelector){
  final_style.innerHTML = '@media(' + mediaSelector + '){\n' + final_style.innerHTML + '\n};';
    submitNewStyle();
};

Sie tun im Grunde überall in Ihrem Code :
addNewStyle('body', 'color: ' + color1);, wo color1eine Variable definiert ist.

Wenn Sie möchten , „post“ die aktuelle CSS - Datei Sie einfach tun submitNewStyle(),
und dann können Sie noch mehr CSS später hinzufügen.

Wenn Sie es mit "Medienabfragen" hinzufügen möchten, haben Sie die Option.
Nach "Hinzufügen von NewStyles" verwenden Sie einfach submitNewStyleWithMedia('min-width: 1280px');.


Es war ziemlich nützlich für meinen Anwendungsfall, da ich das CSS der öffentlichen (nicht meiner) Website gemäß der aktuellen Zeit geändert habe. Ich reiche eine CSS-Datei ein, bevor ich "aktive" Skripte verwende, und den Rest danach (lässt die Site vor dem Zugriff auf Elemente irgendwie so aussehen, wie sie sein sollte querySelector).


Ich werde das heute ausprobieren. Lassen Sie Sie wissen, wie dies in meinem Anwendungsfall funktioniert. Daumen drücken!!!!
lopezdp

0

Zum Nutzen der Suchenden; Wenn Sie jQuery verwenden, können Sie Folgendes tun:

var currentOverride = $('#customoverridestyles');

if (currentOverride) {
 currentOverride.remove();
}

$('body').append("<style id=\"customoverridestyles\">body{background-color:pink;}</style>");

Natürlich können Sie das innere CSS nach Belieben ändern.

Schätzen Sie, dass einige Leute reines JavaScript bevorzugen, aber es funktioniert und war ziemlich robust für das dynamische Schreiben / Überschreiben von Stilen.


0

Ich habe einige der Antworten hier durchgesehen und konnte nichts finden, das automatisch ein neues Stylesheet hinzufügt, wenn es keines gibt, und wenn nicht einfach ein vorhandenes ändert, das bereits den benötigten Stil enthält, habe ich eine neue Funktion erstellt ( sollte in allen Browsern funktionieren, obwohl nicht getestet, verwendet addRule und außerdem nur einfaches natives JavaScript, lassen Sie mich wissen, ob es funktioniert):

function myCSS(data) {
    var head = document.head || document.getElementsByTagName("head")[0];
    if(head) {
        if(data && data.constructor == Object) {
            for(var k in data) {
                var selector = k;
                var rules = data[k];

                var allSheets = document.styleSheets;
                var cur = null;

                var indexOfPossibleRule = null,
                    indexOfSheet = null;
                for(var i = 0; i < allSheets.length; i++) {
                    indexOfPossibleRule = findIndexOfObjPropInArray("selectorText",selector,allSheets[i].cssRules);
                    if(indexOfPossibleRule != null) {
                        indexOfSheet = i;
                        break;
                    }
                }

                var ruleToEdit = null;
                if(indexOfSheet != null) {

                    ruleToEdit = allSheets[indexOfSheet].cssRules[indexOfPossibleRule];

                } else {
                    cur = document.createElement("style");
                    cur.type =  "text/css";
                    head.appendChild(cur);
                    cur.sheet.addRule(selector,"");
                    ruleToEdit = cur.sheet.cssRules[0];
                    console.log("NOPE, but here's a new one:", cur);
                }
                applyCustomCSSruleListToExistingCSSruleList(rules, ruleToEdit, (err) => {
                    if(err) {
                        console.log(err);
                    } else {
                        console.log("successfully added ", rules, " to ", ruleToEdit);
                    }
                });
            }
        } else {
            console.log("provide one paramter as an object containing the cssStyles, like: {\"#myID\":{position:\"absolute\"}, \".myClass\":{background:\"red\"}}, etc...");
        }
    } else {
        console.log("run this after the page loads");
    }

};  

Fügen Sie dann einfach diese 2 Hilfsfunktionen entweder innerhalb der obigen Funktion oder irgendwo anders hinzu:

function applyCustomCSSruleListToExistingCSSruleList(customRuleList, existingRuleList, cb) {
    var err = null;
    console.log("trying to apply ", customRuleList, " to ", existingRuleList);
    if(customRuleList && customRuleList.constructor == Object && existingRuleList && existingRuleList.constructor == CSSStyleRule) {
        for(var k in customRuleList) {
            existingRuleList["style"][k] = customRuleList[k];
        }

    } else {
        err = ("provide first argument as an object containing the selectors for the keys, and the second argument is the CSSRuleList to modify");
    }
    if(cb) {
        cb(err);
    }
}

function findIndexOfObjPropInArray(objPropKey, objPropValue, arr) {
    var index = null;
    for(var i = 0; i < arr.length; i++) {
        if(arr[i][objPropKey] == objPropValue) {
            index = i;
            break;
        }
    }
    return index;
}

(Beachten Sie, dass ich in beiden Fällen eine for-Schleife anstelle von .filter verwende, da die CSS-Stil- / Regellistenklassen nur eine length-Eigenschaft und keine .filter-Methode haben.)

Dann um es zu nennen:

myCSS({
    "#coby": {
        position:"absolute",
        color:"blue"
    },
    ".myError": {
        padding:"4px",
        background:"salmon"
    }
})

Lassen Sie mich wissen, ob es für Ihren Browser funktioniert oder einen Fehler gibt.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.