Como criar uma tag <style> com Javascript?

336

Estou procurando uma maneira de inserir uma <style>tag em uma página HTML com JavaScript.

A melhor maneira que encontrei até agora:

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

Isso funciona no Firefox, Opera e Internet Explorer, mas não no Google Chrome. Também é um pouco feio com a <br>frente do IE.

Alguém sabe como criar uma <style>tag que

  1. É melhor

  2. Funciona com o Chrome?

Ou talvez

  1. Isso é algo fora do padrão que devo evitar

  2. Três navegadores de trabalho são ótimos e quem usa o Chrome?

Ameena sana
fonte

Respostas:

663

Tente adicionar o styleelemento ao headinvés do body.

Isso foi testado no IE (7-9), Firefox, Opera e 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
fonte
19
FYI, document.headé suportado em todos os principais navegadores.
Rob W
30
@ RobW - Não é suportado no IE8 e abaixo. É suportado em navegadores modernos, mas não em todos os principais.
Tim
5
por que não usar document.querySelector("head")? É evento suportado pelo IE8 pela fonte
allenhwkim
8
@ allenhwkim: a resposta é anterior à introdução de querySelector(); hoje, eu provavelmente iria document.head, disponível desde IE9 #
Christoph
2
Eu tive que acrescentar o elemento de estilo na cabeça antes de acessar style.styleSheet.cssText. Antes de ser anexado, style.styleSheetera nulo.
Will Hawker
38

Aqui está um script que adiciona métodos createStyleSheet()e estilo do IE addRule()a navegadores que não os possuem:

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

Você pode adicionar arquivos externos via

document.createStyleSheet('foo.css');

e criar regras dinamicamente via

var sheet = document.createStyleSheet();
sheet.addRule('h1', 'background: red;');
Christoph
fonte
Isso foi muito útil para mim ao tentar carregar um arquivo CSS externo em um contexto estranho do CMS. Eu tive alguns problemas com a parte addRule / removeRule, então eu apenas os eliminei e tudo funciona bem.
precisa saber é o seguinte
33

Suponho que você queira inserir uma styletag versus uma linktag (referenciando um CSS externo), e é isso que o exemplo a seguir faz:

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

Além disso, notei na sua pergunta que você está usando innerHTML. Essa é, na verdade, uma maneira não padrão de inserir dados em uma página. A melhor prática é criar um nó de texto e anexá-lo a outro nó do elemento.

Com relação à sua pergunta final, você ouvirá algumas pessoas dizerem que seu trabalho deve funcionar em todos os navegadores. Tudo depende do seu público. Se ninguém do seu público estiver usando o Chrome, não se preocupe; no entanto, se você deseja atingir o maior público possível, é melhor oferecer suporte a todos os principais navegadores de categoria A

Tom
fonte
11
Isso é basicamente o mesmo que minha solução; nenhum deles funciona no IE!
728 Christoph
Acrescentar um nó de texto não funciona no IE. Mas colocar o elemento style na cabeça faz minha solução funcionar no Chrome! :-)
11
para IE, use #styleNode.styleSheet.cssText = ...
Christoph
7
(Comentário muito tardio) "Tudo depende do seu público. Se ninguém no seu público estiver usando o Chrome, então não se preocupe" Essa atitude é o que leva as pessoas a ficarem trancadas no IE6 por anos após o IE7 e até o IE8 estarem disponíveis. . "Mas o aplicativo da web que eu tenho que usar funciona no IE6"
Stephen P
11
Sim, você está certo e também não estou defendendo isso (daí o todo: "se você deseja atingir o maior público possível, é melhor oferecer suporte a todos os principais navegadores de categoria A"), mas conhecendo o o público da sua plataforma é importante.
Tom
31

<style>as tags devem estar localizadas no <head>elemento e cada tag adicionada deve ser adicionada na parte inferior da <head>tag.

Usando insertAdjacentHTML para injetar uma marca de estilo na marca de cabeçalho do documento :

DOM nativo:

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
fonte
2
Esta é a melhor e mais simples solução, obrigado!
Ryzal Yusoff 26/09/19
Concordo, é melhor e simples, mas cuidado com o CSS injetado mal se você não estiver no controle!
Endless
24

Um exemplo que funciona e é compatível com todos os navegadores:

var ss = document.createElement("link");
ss.type = "text/css";
ss.rel = "stylesheet";
ss.href = "style.css";
document.getElementsByTagName("head")[0].appendChild(ss);
belaz
fonte
7
elemento errado: stylenão tem relou hrefatributo - que você quis dizer link?
Christoph
4
o que o linkelemento tem a ver com a pergunta? o OP pediu styleelemento. Esta resposta não tem nada a ver com a questão
vsync
2
O @vsync styleé para adicionar estilos embutidos, linké correto para fontes de folha de estilo e isso tem a vantagem de evitar problemas entre navegadores.
majick
7

Muitas vezes, é necessário substituir as regras existentes, portanto, anexar novos estilos ao HEAD não funciona em todos os casos.

Eu vim com essa função simples que resume tudo as abordagens não válidas de "anexar ao corpo" e é apenas mais conveniente de usar e depurar (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);

Demonstração: codepen , jsfiddle

Garlaro
fonte
Funcionou perfeitamente no mais recente Firefox, Chrome e no ie8 (ou pelo menos do jeito que eu o digitei). Realmente não sei por que isso não tem mais pontos.
Harry Pehkonen
Isso não tem mais pontos, porque não é válido, nem é bom injetar uma <style>etiqueta externa <head>. A tag de estilo não deve aparecer em nenhum outro lugar, mas dentro da <head>tag. Esse é o padrão html amplamente adotado. Há um atributo de estilo para o estilo embutido e o atributo de estilo pode ser aplicado a qualquer marca dentro da <body>marca, incluindo a <body>marca própria.
Spooky
Este código não funcionou para mim. Criei um código muito mais curto que funciona em três navegadores e publicarei minha resposta aqui.
David Spector
Não consegui descobrir por que o Chrome não estava atualizando meus estilos quando adicionei um bloco de estilo à cabeça dinamicamente. Eu tentei isso e magicamente ele atualiza. Preciso investigar qual é realmente a diferença aqui neste código que aciona o navegador para renderizar novamente o css. Mas, muito obrigado!
prograhammer
5

Essa variável de objeto acrescentará uma tag de estilo à tag head com o atributo type e uma regra de transição simples dentro que corresponda a cada id / classe / elemento. Sinta-se à vontade para modificar a propriedade do conteúdo e injetar quantas regras você precisar. Apenas certifique-se de que as regras CSS dentro do conteúdo permaneçam em uma linha (ou 'escape' a cada nova linha, se você preferir).

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();
Assustador
fonte
11
Gostei dessa solução, então eu a usei para alterar o tamanho dos botões em dispositivos móveis, mas é incorreto que a propriedade content precise estar em uma linha: concatene simplesmente várias seqüências de caracteres (em várias linhas) com o operador +.
RufusVS 27/02
Verdade. Eu sei e sabia disso. Mas, às vezes, sou muito preguiçoso para escrever como devo. : D Saúde.
Spooky # 16
5

Aqui está uma variante para adicionar dinamicamente uma 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
fonte
4

Esta função irá injetar css sempre que você chamar a função appendStyleassim:
appendStyle('css you want to inject')

Isso funciona injetando um stylenó na cabeça do documento. Essa é uma técnica semelhante à que é comumente usada para carregar lentamente o JavaScript. Funciona de forma consistente na maioria dos navegadores modernos.

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>

Você também pode carregar preguiçosamente arquivos CSS externos usando o seguinte snippet:

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
fonte
Essa é aproximadamente a abordagem que desenvolvi independentemente. Curto e agradável e funciona nos mais recentes navegadores Firefox, Microsoft Edge e Chrome. Obviamente, existem muitos erros de JavaScript no Internet Explorer para se preocupar em incluí-lo mais na compatibilidade do navegador.
David Spector
3

Você escreveu:

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

Por que não isso?

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

A partir de agora, você pode anexar regras CSS facilmente ao código HTML:

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

... ou diretamente para o DOM:

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

Espero que isso funcione em qualquer lugar, exceto nos navegadores arcaicos.

Definitivamente funciona no Chrome no ano de 2019.

7vujy0f0hy
fonte
3

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

De longe, a solução mais direta. Tudo o que você precisa fazer é digitar o mesmo que normalmente declararia styletags, entre os backticks

Kabirr singh sahni
fonte
11
Olá e bem-vindo ao site! Embora esse código possa resolver o problema fornecido, você também deve incluir uma explicação de como e por que ele funciona.
Radiodef 16/07
1

Se o problema que você está enfrentando é injetar uma string de CSS em uma página, é mais fácil fazer isso com o <link>elemento do que com o <style>elemento.

O seguinte adiciona p { color: green; }regra à página.

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

Você pode criar isso em JavaScript simplesmente codificando URL sua sequência de CSS e adicionando a ela o HREFatributo Muito mais simples do que todas as peculiaridades dos <style>elementos ou acessar diretamente as folhas de estilo.

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

Isso funcionará no IE 5.5 para cima

moefinley
fonte
A injeção dinâmica do bloco de estilos na cabeça não atualizou o estilo em alguns casos. Isso funciona!
prograhammer
-1
this link may helpful to you: 

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

Vinod Poorma
fonte
Por favor, não use blocos de texto / código pré-formatados para um parágrafo curto. Vincular uma resposta dessa maneira também é inútil. Resuma primeiro o site.
FryingggPannn