Comment créer une balise <style> avec Javascript?

336

Je cherche un moyen d'insérer une <style>balise dans une page HTML avec JavaScript.

La meilleure façon que j'ai trouvée jusqu'à présent:

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

Cela fonctionne dans Firefox, Opera et Internet Explorer, mais pas dans Google Chrome. C'est aussi un peu moche avec l' <br>avant pour IE.

Quelqu'un connaît-il un moyen de créer une <style>balise

  1. Est plus agréable

  2. Fonctionne avec Chrome?

Ou peut-être

  1. C'est une chose non standard que je devrais éviter

  2. Trois navigateurs qui fonctionnent sont excellents et qui utilise quand même Chrome?

Ameena sana
la source

Réponses:

663

Essayez d'ajouter l' styleélément au headplutôt qu'au body.

Cela a été testé dans IE (7-9), Firefox, Opera et 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
la source
19
FYI, document.headest pris en charge dans tous les principaux navigateurs.
Rob W
30
@RobW - Il n'est pas pris en charge dans IE8 et ci-dessous. Il est pris en charge dans les navigateurs modernes, mais pas dans tous les principaux.
Tim
5
pourquoi ne pas simplement utiliser document.querySelector("head")? C'est un événement pris en charge par IE8 par la source
allenhwkim
8
@allenhwkim: la réponse est antérieure à l'introduction de querySelector(); aujourd'hui, j'irais probablement avec document.head, disponible depuis IE9
Christoph
2
J'ai dû ajouter l'élément de style à la tête avant d'accéder style.styleSheet.cssText. Avant son ajout, la valeur style.styleSheetétait nulle.
Will Hawker
38

Voici un script qui ajoute un style IE createStyleSheet()et des addRule()méthodes aux navigateurs qui n'en ont pas:

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;
    })();
}

Vous pouvez ajouter des fichiers externes via

document.createStyleSheet('foo.css');

et créer dynamiquement des règles via

var sheet = document.createStyleSheet();
sheet.addRule('h1', 'background: red;');
Christoph
la source
Cela m'a été très utile pour essayer de charger un fichier CSS externe dans un étrange contexte CMS. J'ai rencontré des problèmes avec la partie addRule / removeRule, donc je les ai juste éliminées, et tout fonctionne bien.
Kirkman14
33

Je suppose que vous souhaitez insérer une stylebalise par rapport à une linkbalise (référençant un CSS externe), c'est donc ce que fait l'exemple suivant:

<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>

De plus, j'ai remarqué dans votre question que vous utilisez innerHTML. Il s'agit en fait d'une manière non standard d'insérer des données dans une page. La meilleure pratique consiste à créer un nœud de texte et à l'ajouter à un autre nœud d'élément.

En ce qui concerne votre dernière question, vous allez entendre certaines personnes dire que votre travail devrait fonctionner sur tous les navigateurs. Tout dépend de votre public. Si personne dans votre audience n'utilise Chrome, ne le transpirez pas; cependant, si vous cherchez à atteindre le plus grand public possible, il est préférable de prendre en charge tous les principaux navigateurs de niveau A

À M
la source
1
C'est fondamentalement la même que ma solution; aucun d'eux ne fonctionne dans IE!
Christoph
L'ajout d'un nœud de texte ne fonctionne pas dans IE. Mais mettre l'élément de style dans la tête fait fonctionner ma solution dans Chrome! :-)
1
pour IE, utilisezstyleNode.styleSheet.cssText = ...
Christoph
7
(Commentaire très tardif) "Tout dépend de votre public. Si personne dans votre public n'utilise Chrome, alors ne vous inquiétez pas" Cette attitude est la raison pour laquelle les gens sont enfermés dans IE6 pendant des années après qu'IE7 et même IE8 soient disponibles . "Mais l'application web que je dois utiliser ne fonctionne que dans IE6"
Stephen P
1
Oui, vous avez raison et je ne préconise pas nécessairement de le faire non plus (d'où le tout: "si vous cherchez à atteindre le plus grand public possible, alors il est préférable de prendre en charge tous les principaux navigateurs de niveau A"), mais sachant l'audience de votre plateforme est importante.
Tom
31

<style>les balises doivent être placées dans l' <head>élément et chaque balise ajoutée doit être ajoutée au bas de la <head>balise.

Utilisation de insertAdjacentHTML pour injecter une balise de style dans la balise d'en- tête du document :

DOM natif:

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
la source
D'accord, c'est mieux et simple mais attention aux CSS mal injectés si vous n'êtes pas en contrôle!
sans fin
24

Un exemple qui fonctionne et est compatible avec tous les navigateurs:

var ss = document.createElement("link");
ss.type = "text/css";
ss.rel = "stylesheet";
ss.href = "style.css";
document.getElementsByTagName("head")[0].appendChild(ss);
belaz
la source
7
mauvais élément: stylen'a pas relou hrefattribut - vouliez-vous dire link?
Christoph
4
qu'est-ce que l' linkélément a à voir avec la question? le PO a demandé un styleélément. Cette réponse n'a rien à voir avec la question
vsync
2
@vsync styleest destiné à ajouter des styles en ligne, linkest correct pour les sources de feuilles de style et cela a l'avantage d'éviter les problèmes inter-navigateurs.
majick
7

Souvent, il est nécessaire de remplacer les règles existantes, donc l'ajout de nouveaux styles à HEAD ne fonctionne pas dans tous les cas.

Je suis venu avec cette fonction simple qui résume toutes les approches "ajouter au corps" non valides et est juste plus pratique à utiliser et à déboguer (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);

Démo: codepen , jsfiddle

Garlaro
la source
Fonctionne parfaitement dans les derniers Firefox, Chrome et ie8 (ou du moins comme je l'ai tapé). Je ne sais vraiment pas pourquoi cela n'a pas plus de points.
Harry Pehkonen
Cela n'a plus de points, car ce n'est pas valide, ni une bonne chose à injecter une <style>balise en dehors de la <head>balise. La balise de style ne doit apparaître nulle part ailleurs que dans la <head>balise. C'est la norme html largement adoptée. Il existe un attribut de style pour le style en ligne et un attribut de style peut être appliqué à n'importe quelle balise dans la <body>balise, y compris la <body>balise elle-même.
Spooky
Ce code n'a pas fonctionné pour moi. J'ai conçu un code beaucoup plus court qui fonctionne dans trois navigateurs et publierai ma réponse ici.
David Spector
Je n'ai pas pu comprendre pourquoi Chrome ne mettait pas à jour mes styles lorsque j'ai ajouté un bloc de style à la tête de manière dynamique. J'ai essayé cela et comme par magie, il se met à jour. J'ai besoin d'examiner quelle est la différence ici dans ce code qui déclenche le navigateur pour restituer le CSS. Mais, merci beaucoup!
prograhammer
5

Cette variable d'objet ajoutera une balise de style à la balise head avec l'attribut type et une règle de transition simple à l'intérieur qui correspond à chaque id / classe / élément. N'hésitez pas à modifier la propriété du contenu et à injecter autant de règles que nécessaire. Assurez-vous simplement que les règles CSS à l'intérieur du contenu restent sur une seule ligne (ou «échappez» chaque nouvelle ligne, si vous préférez).

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();
Effrayant
la source
1
J'ai aimé cette solution, je l'ai donc utilisée moi-même pour modifier la taille des boutons sur les appareils mobiles, mais il est incorrect que la propriété de contenu doive être sur une seule ligne: concaténez simplement plusieurs chaînes (sur plusieurs lignes) avec l'opérateur +.
RufusVS
Vrai. Je le sais et je le savais. Mais, parfois, je suis juste trop paresseux pour écrire comme je suis censé le faire. : D Cheers.
Spooky
5

Voici une variante pour ajouter dynamiquement une classe

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);
    }
  }
}
Michael
la source
4

Cette fonction injectera css chaque fois que vous appelez la fonction appendStylecomme ceci:
appendStyle('css you want to inject')

Cela fonctionne en injectant un stylenœud dans la tête du document. Il s'agit d'une technique similaire à celle couramment utilisée pour le chargement paresseux de JavaScript. Il fonctionne de manière cohérente dans la plupart des navigateurs modernes.

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>

Vous pouvez également charger des fichiers CSS externes paresseux à l'aide de l'extrait de code suivant:

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
la source
C'est à peu près l'approche que j'ai développée indépendamment. Court et doux et fonctionne dans les derniers navigateurs Firefox, Microsoft Edge et Chrome. Bien sûr, il y a trop d'erreurs JavaScript dans Internet Explorer pour se soucier de l'inclure dans la compatibilité du navigateur.
David Spector
3

Tu as écrit:

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

Pourquoi pas ça?

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

Désormais, vous pouvez facilement ajouter des règles CSS au code HTML:

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

... ou directement au DOM:

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

Je m'attends à ce que cela fonctionne partout sauf dans les navigateurs archaïques.

Fonctionne certainement dans Chrome en 2019.

7vujy0f0hy
la source
3

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

De loin la solution la plus simple. Tout ce que vous avez à faire est de taper la même chose que la façon dont vous déclareriez normalement les stylebalises, entre les backticks

Kabirr singh sahni
la source
1
Bonjour et bienvenue sur le site. Bien que ce code puisse résoudre le problème donné, vous devez également inclure une explication de comment et pourquoi cela fonctionne.
Radiodef
1

Si le problème auquel vous êtes confronté consiste à injecter une chaîne de CSS dans une page, il est plus facile de le faire avec l' <link>élément qu'avec le<style> élément.

Ce qui suit ajoute une p { color: green; }règle à la page.

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

Vous pouvez créer cela en JavaScript simplement en codant l'URL de votre chaîne de CSS et en lui ajoutant l' HREFattribut. Beaucoup plus simple que toutes les bizarreries des <style>éléments ou l'accès direct aux feuilles de style.

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));

Cela fonctionnera dans IE 5.5 vers le haut

moefinley
la source
L'injection dynamique du bloc de style dans la tête n'a pas mis à jour le style dans certains cas. Cela fonctionne bien!
prograhammer
-1
this link may helpful to you: 

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

Vinod Poorma
la source
Veuillez ne pas utiliser de blocs de texte / code préformatés pour un court paragraphe. Lier une réponse de cette manière est également inutile. Veuillez d'abord résumer le site Web.
FryingggPannn