Jak utworzyć tag <style> za pomocą Javascript?

336

Szukam sposobu na wstawienie <style>tagu na stronie HTML za pomocą JavaScript.

Najlepszy sposób, jaki do tej pory znalazłem:

var divNode = document.createElement("div");
divNode.innerHTML = "<br><style>h1 { background: red; }</style>";
document.body.appendChild(divNode);

Działa to w Firefox, Opera i Internet Explorer, ale nie w Google Chrome. Jest też trochę brzydki z <br>przodu dla IE.

Czy ktoś wie, jak stworzyć taki <style>tag

  1. Jest milszy

  2. Działa z Chrome?

Albo może

  1. To jest niestandardowa rzecz, której powinienem unikać

  2. Trzy działające przeglądarki są świetne i kto i tak używa Chrome?

Ameena Sana
źródło

Odpowiedzi:

663

Spróbuj dodać styleelement headzamiast do body.

Zostało to przetestowane w IE (7-9), Firefox, Opera i Chrome:

var css = 'h1 { background: red; }',
    head = document.head || document.getElementsByTagName('head')[0],
    style = document.createElement('style');

head.appendChild(style);

style.type = 'text/css';
if (style.styleSheet){
  // This is required for IE8 and below.
  style.styleSheet.cssText = css;
} else {
  style.appendChild(document.createTextNode(css));
}
Christoph
źródło
19
FYI document.headjest obsługiwany we wszystkich głównych przeglądarkach.
Rob W
30
@RobW - Nie jest obsługiwany w IE8 i niższych wersjach. Jest obsługiwany w nowoczesnych przeglądarkach, ale nie we wszystkich głównych.
Tim
5
dlaczego nie po prostu użyć document.querySelector("head")? To wydarzenie obsługiwane przez IE8 według źródła
allenhwkim
8
@allenhwkim: odpowiedź poprzedza wprowadzenie querySelector(); dziś prawdopodobnie wybrałbym z document.head, dostępny od IE9
Christoph
2
Musiałem dołączyć element stylu do głowy przed uzyskaniem dostępu style.styleSheet.cssText. Przed dołączeniem style.styleSheetbył zerowy.
Will Hawker,
38

Oto skrypt, który dodaje style IE createStyleSheet()i addRule()metody do przeglądarek, które ich nie mają:

if(typeof document.createStyleSheet === 'undefined') {
    document.createStyleSheet = (function() {
        function createStyleSheet(href) {
            if(typeof href !== 'undefined') {
                var element = document.createElement('link');
                element.type = 'text/css';
                element.rel = 'stylesheet';
                element.href = href;
            }
            else {
                var element = document.createElement('style');
                element.type = 'text/css';
            }

            document.getElementsByTagName('head')[0].appendChild(element);
            var sheet = document.styleSheets[document.styleSheets.length - 1];

            if(typeof sheet.addRule === 'undefined')
                sheet.addRule = addRule;

            if(typeof sheet.removeRule === 'undefined')
                sheet.removeRule = sheet.deleteRule;

            return sheet;
        }

        function addRule(selectorText, cssText, index) {
            if(typeof index === 'undefined')
                index = this.cssRules.length;

            this.insertRule(selectorText + ' {' + cssText + '}', index);
        }

        return createStyleSheet;
    })();
}

Możesz dodać pliki zewnętrzne za pośrednictwem

document.createStyleSheet('foo.css');

i dynamicznie twórz reguły poprzez

var sheet = document.createStyleSheet();
sheet.addRule('h1', 'background: red;');
Christoph
źródło
Pomogło mi to w załadowaniu zewnętrznego pliku CSS w dziwnym kontekście CMS. Miałem pewne problemy z częścią addRule / removeRule, więc po prostu je wyeliminowałem i wszystko działa dobrze.
Kirkman14,
33

Zakładam, że chcesz wstawić styletag w porównaniu do linktagu (odwołując się do zewnętrznego CSS), więc to właśnie robi następujący przykład:

<html>
 <head>
  <title>Example Page</title>
 </head>
 <body>
  <span>
   This is styled dynamically via JavaScript.
  </span>
 </body>
 <script type="text/javascript">
   var styleNode = document.createElement('style');
   styleNode.type = "text/css";
   // browser detection (based on prototype.js)
   if(!!(window.attachEvent && !window.opera)) {
        styleNode.styleSheet.cssText = 'span { color: rgb(255, 0, 0); }';
   } else {
        var styleText = document.createTextNode('span { color: rgb(255, 0, 0); } ');
        styleNode.appendChild(styleText);
   }
   document.getElementsByTagName('head')[0].appendChild(styleNode);
 </script>
</html>

Zauważyłem też w twoim pytaniu, że używasz innerHTML. Jest to w rzeczywistości niestandardowy sposób wstawiania danych na stronę. Najlepszą praktyką jest utworzenie węzła tekstowego i dołączenie go do innego węzła elementu.

Jeśli chodzi o twoje ostatnie pytanie, usłyszysz, jak niektórzy mówią, że twoja praca powinna działać we wszystkich przeglądarkach. Wszystko zależy od odbiorców. Jeśli nikt z Twoich odbiorców nie używa Chrome, nie przejmuj się; Jeśli jednak chcesz dotrzeć do jak największej liczby odbiorców, najlepiej jest obsługiwać wszystkie główne przeglądarki klasy A.

Tomek
źródło
1
Jest to w zasadzie to samo, co moje rozwiązanie; żadne z nich nie działa w IE!
Christoph
Dołączenie węzła tekstowego nie działa w IE. Ale umieszczenie elementu stylu w głowie sprawia, że ​​moje rozwiązanie działa w Chrome! :-)
1
dla IE użyjstyleNode.styleSheet.cssText = ...
Christoph
7
(Bardzo późny komentarz) „Wszystko zależy od odbiorców. Jeśli nikt z odbiorców nie korzysta z Chrome, nie przejmuj się” Takie podejście prowadzi do zablokowania ludzi w IE6 przez lata po udostępnieniu IE7, a nawet IE8 . „Ale aplikacja internetowa, z której muszę korzystać, działa tylko w IE6”
Stephen P
1
Tak, masz rację i niekoniecznie zalecam robienie tego (stąd całość: „jeśli chcesz dotrzeć do jak największej liczby odbiorców, najlepiej jest obsługiwać wszystkie główne przeglądarki klasy A”), ale znając publiczność na Twojej platformie jest ważna.
Tom
31

<style>tagi powinny być miejscami wewnątrz <head>elementu, a każdy dodany tag powinien być dodany na dole <head>tagu.

Używanie insertAdjacentHTML do wstrzykiwania znacznika stylu do znacznika nagłówka dokumentu :

Natywny DOM:

document.head.insertAdjacentHTML("beforeend", `<style>body{background:red}</style>`)


jQuery :

$('<style>').text("body{background:red}").appendTo(document.head)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

vsync
źródło
Zgadzam się, jest to najlepsze i proste, ale uważaj na źle wstrzyknięty css, jeśli nie masz nad nim kontroli!
Endless
24

Przykład, który działa i jest zgodny ze wszystkimi przeglądarkami:

var ss = document.createElement("link");
ss.type = "text/css";
ss.rel = "stylesheet";
ss.href = "style.css";
document.getElementsByTagName("head")[0].appendChild(ss);
Belaz
źródło
7
zły element: stylenie ma rellub ma hrefatrybut - miałeś na myśli link?
Christoph
4
co linkma wspólnego element z pytaniem? OP poprosił o styleelement. Ta odpowiedź nie ma nic wspólnego z pytaniem
vsync,
2
@vsync stylesłuży do dodawania stylów wbudowanych, linkjest poprawny dla źródeł arkuszy stylów i ma tę zaletę, że pozwala uniknąć problemów w różnych przeglądarkach.
majick 12.04.16
7

Często trzeba zastąpić istniejące reguły, więc dołączanie nowych stylów do HEAD nie zawsze działa.

Wymyśliłem tę prostą funkcję, która podsumowuje wszystkie niepoprawne podejścia „dołącz do BODY” i jest po prostu wygodniejsza w użyciu i debugowaniu (IE8 +).

window.injectCSS = (function(doc){
    // wrapper for all injected styles and temp el to create them
    var wrap = doc.createElement('div');
    var temp = doc.createElement('div');
    // rules like "a {color: red}" etc.
    return function (cssRules) {
        // append wrapper to the body on the first call
        if (!wrap.id) {
            wrap.id = 'injected-css';
            wrap.style.display = 'none';
            doc.body.appendChild(wrap);
        }
        // <br> for IE: http://goo.gl/vLY4x7
        temp.innerHTML = '<br><style>'+ cssRules +'</style>';
        wrap.appendChild( temp.children[1] );
    };
})(document);

Demo: codepen , jsfiddle

Garlaro
źródło
Doskonale działał w najnowszym Firefoksie, Chrome i ie8 (a przynajmniej tak, jak go wpisałem). Naprawdę nie wiem, dlaczego to nie ma więcej punktów.
Harry Pehkonen,
Nie ma to już więcej punktów, ponieważ nie jest poprawne, ani dobrą rzeczą do wstrzykiwania <style>tagu poza <head>tag. Tag stylu nie powinien pojawiać się nigdzie indziej niż w <head>tagu. To powszechnie przyjęty standard HTML. Istnieje atrybut stylu dla wbudowanego stylu, a atrybut stylu może być zastosowany do dowolnego znacznika w <body>znaczniku, w tym <body>znacznika.
Spooky
Ten kod nie działał dla mnie. Stworzyłem trochę krótszy kod, który działa w trzech przeglądarkach i opublikuję tutaj swoją odpowiedź.
David Spector,
Nie mogłem zrozumieć, dlaczego Chrome nie aktualizował moich stylów, gdy dynamicznie dodawałem blok stylów do głowy. Próbowałem tego i magicznie aktualizuje się. Muszę zbadać, jaka jest tutaj różnica w tym kodzie, która powoduje, że przeglądarka ponownie renderuje css. Ale wielkie dzięki!
prograhammer
5

Ta zmienna obiektowa doda tag stylu do tagu head z atrybutem type i jedną prostą regułą przejścia wewnątrz, która pasuje do każdego identyfikatora / klasy / elementu. Możesz modyfikować właściwości treści i wprowadzać tyle reguł, ile potrzebujesz. Po prostu upewnij się, że reguły css wewnątrz zawartości pozostają w jednym wierszu (lub „uciekaj” z każdego nowego wiersza, jeśli wolisz).

var script = {

  type: 'text/css', style: document.createElement('style'), 
  content: "* { transition: all 220ms cubic-bezier(0.390, 0.575, 0.565, 1.000); }",
  append: function() {

    this.style.type = this.type;
    this.style.appendChild(document.createTextNode(this.content));
    document.head.appendChild(this.style);

}}; script.append();
Straszny
źródło
1
Podobało mi się to rozwiązanie, więc sam go użyłem do zmiany rozmiarów przycisków na urządzeniach mobilnych, ale niepoprawne jest to, że właściwość content musi znajdować się w jednym wierszu: po prostu połącz wiele ciągów (w wielu wierszach) z operatorem +.
RufusVS,
Prawdziwe. Wiem i wiedziałem o tym. Ale czasami jestem zbyt leniwy, by pisać tak, jak powinienem. : D Na zdrowie.
Spooky
5

Oto wariant dynamicznego dodawania klasy

function setClassStyle(class_name, css) {
  var style_sheet = document.createElement('style');
  if (style_sheet) {
    style_sheet.setAttribute('type', 'text/css');
    var cstr = '.' + class_name + ' {' + css + '}';
    var rules = document.createTextNode(cstr);
    if(style_sheet.styleSheet){// IE
      style_sheet.styleSheet.cssText = rules.nodeValue;
    } else {
      style_sheet.appendChild(rules);
    }
    var head = document.getElementsByTagName('head')[0];
    if (head) {
      head.appendChild(style_sheet);
    }
  }
}
Michał
źródło
4

Ta funkcja wstrzykuje css za każdym razem, gdy wywołasz funkcję w appendStylenastępujący sposób:
appendStyle('css you want to inject')

Działa to poprzez wstrzyknięcie stylewęzła do nagłówka dokumentu. Jest to technika podobna do powszechnie używanej do leniwego ładowania JavaScript. Działa konsekwentnie w większości nowoczesnych przeglądarek.

appendStyle = function (content) {
  style = document.createElement('STYLE');
  style.type = 'text/css';
  style.appendChild(document.createTextNode(content));
  document.head.appendChild(style);
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
  <h1>Lorem Ipsum</h1>
  <p>dolar sit amet</p>
  <button onclick='appendStyle("body { background-color: #ff0000;}h1 { font-family: Helvetica, sans-serif; font-variant: small-caps; letter-spacing: 3px; color: #ff0000; background-color: #000000;}p { font-family: Georgia, serif; font-size: 14px; font-style: normal; font-weight: normal; color: #000000; background-color: #ffff00;}")'>Press me to inject CSS!</button>
</body>

</html>

Możesz także leniwie ładować zewnętrzne pliki CSS, używając następującego fragmentu:

appendExternalStyle = function (content) {
  link = document.createElement('LINK');
  link.rel = 'stylesheet';
  link.href = content;
  link.type = 'text/css';
  document.head.appendChild(link);
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
    html {
      font-family: sans-serif;
      font-display: swap;
    }
  </style>
</head>

<body>

  <h1>Lorem Ipsum</h1>
  <p>dolar sit amet</p>
  <button onclick='appendExternalStyle("data:text/css;base64,OjotbW96LXNlbGVjdGlvbntjb2xvcjojZmZmIWltcG9ydGFudDtiYWNrZ3JvdW5kOiMwMDB9OjpzZWxlY3Rpb257Y29sb3I6I2ZmZiFpbXBvcnRhbnQ7YmFja2dyb3VuZDojMDAwfWgxe2ZvbnQtc2l6ZToyZW19Ym9keSxodG1se2NvbG9yOnJnYmEoMCwwLDAsLjc1KTtmb250LXNpemU6MTZweDtmb250LWZhbWlseTpMYXRvLEhlbHZldGljYSBOZXVlLEhlbHZldGljYSxzYW5zLXNlcmlmO2xpbmUtaGVpZ2h0OjEuNjd9YnV0dG9uLGlucHV0e292ZXJmbG93OnZpc2libGV9YnV0dG9uLHNlbGVjdHstd2Via2l0LXRyYW5zaXRpb24tZHVyYXRpb246LjFzO3RyYW5zaXRpb24tZHVyYXRpb246LjFzfQ==")'>press me to inject css!</button>
</body>

</html>

Joel Ellis
źródło
Jest to z grubsza podejście, które opracowałem niezależnie. Krótkie i słodkie i działa w najnowszych przeglądarkach Firefox, Microsoft Edge i Chrome. Oczywiście w przeglądarce Internet Explorer jest zbyt wiele błędów JavaScript, aby martwić się o włączenie jej do zgodności z przeglądarką.
David Spector,
3

Napisałeś:

var divNode = document.createElement("div");
divNode.innerHTML = "<br><style>h1 { background: red; }</style>";
document.body.appendChild(divNode);

Dlaczego nie to

var styleNode = document.createElement("style");
document.head.appendChild(styleNode);

Odtąd możesz łatwo dołączać reguły CSS do kodu HTML:

styleNode.innerHTML = "h1 { background: red; }\n";
styleNode.innerHTML += "h2 { background: green; }\n";

... lub bezpośrednio do DOM:

styleNode.sheet.insertRule("h1 { background: red; }");
styleNode.sheet.insertRule("h2 { background: green; }");

Spodziewam się, że zadziała to wszędzie oprócz archaicznych przeglądarek.

Zdecydowanie działa w Chrome w roku 2019.

7vujy0f0hy
źródło
3

document.head.innerHTML += `
  <style>
    h1 {
      color: red; 
    }
    p {
      color: blue;
    }
  </style>`
<h1>I'm red!</h1>
<p>I'm blue!</p>

Zdecydowanie najprostsze rozwiązanie. Wszystko, co musisz zrobić, to wpisać to samo, co normalnie deklarujesz styletagi, pomiędzy backtickami

Kabirr singh sahni
źródło
1
Witam i witam na stronie. Chociaż ten kod może rozwiązać dany problem, należy również wyjaśnić, w jaki sposób i dlaczego to działa.
Radiodef,
1

Jeśli napotykasz problem polegający na wstrzykiwaniu ciągu CSS na stronę, łatwiej jest to zrobić z <link>elementem niż z <style>elementem.

Poniżej dodano p { color: green; }regułę do strony.

<link rel="stylesheet" type="text/css" href="data:text/css;charset=UTF-8,p%20%7B%20color%3A%20green%3B%20%7D" />

Możesz utworzyć to w JavaScript po prostu przez kodowanie URL-a łańcucha CSS i dodanie go do HREFatrybutu. Znacznie prostsze niż wszystkie dziwactwa <style>elementów lub bezpośredni dostęp do arkuszy stylów.

let linkElement: HTMLLinkElement = this.document.createElement('link');
linkElement.setAttribute('rel', 'stylesheet');
linkElement.setAttribute('type', 'text/css');
linkElement.setAttribute('href', 'data:text/css;charset=UTF-8,' + encodeURIComponent(myStringOfstyles));

Będzie to działać w IE 5.5 w górę

moefinley
źródło
Dynamiczne wstrzykiwanie bloku stylu w głowę nie aktualizowało stylu w niektórych przypadkach. To działa!
prograhammer
-1
this link may helpful to you: 

http://jonraasch.com/blog/javascript-style-node

Vinod Poorma
źródło
Nie używaj wstępnie sformatowanych bloków tekstu / kodu dla krótkiego akapitu. Linkowanie do odpowiedzi w ten sposób jest również bezużyteczne. Najpierw streszcz stronę internetową.
FryingggPannn