Usando tags <style> no <body> com outro HTML

195
<html>
  <body>
    <style type="text/css">
      p.first {color:blue}
      p.second {color:green}
    </style>

    <p class="first">Hello World</p>
    <p class="second">Hello World</p>

    <style type="text/css">
      p.first {color:green}
      p.second {color:blue}
    </style>

    <p class="first">Hello World</p>
    <p class="second">Hello World</p>
  </body>
</html>

Como um navegador deve renderizar css que não é contíguo? É suposto gerar alguma estrutura de dados usando todos os estilos css em uma página e usá-la para renderizar?

Ou ele renderiza usando informações de estilo na ordem em que vê?

Gagan
fonte
2
Eu diria que é um comportamento indefinido, pois não é HTML válido. Para obter mais informações, quais elementos são válidos e quais não são: en.wikipedia.org/wiki/HTML_element
Felix Kling
2
Deixando de lado esse problema, é uma prática ruim misturar CSSe HTML.
0x2D9A3
1
@ 0x2D9A3 Não é necessariamente verdade. Leva mais tempo para solicitar uma página CSS externa do que o CSS definido na <head>tag
Kolob Canyon 8/08
@KolobCanyon Concordo, mas como regra geral, o CSS deve estar em um arquivo separado. Se você possui toneladas de CSS, é mais fácil gerenciar (manter, (pós-) processamento, minificação, agrupamento) e servir como um arquivo separado, e seu conteúdo (HTML) também pode carregar mais rapidamente, levando a uma melhor UX. No entanto, como sempre, com o desenvolvimento, tudo é específico do contexto, então YMMW :)
0x2D9A3
3
@KolobCanyon, isso não é uma questão de se o CSS deve estar em um arquivo separado. Nesse caso, a questão é sobre CSS no <body>e não no <head>.
Ray Butterworth

Respostas:

312

Como outros já mencionaram, o HTML 4 exige que a <style>tag seja colocada na <head>seção (mesmo que a maioria dos navegadores permita <style>tags dentro da body).

No entanto, o HTML 5 inclui o scopedatributo (consulte a atualização abaixo), que permite criar folhas de estilo com escopo definido no elemento pai da <style>tag. Isso também permite que você coloque <style>tags dentro do <body>elemento:

<!DOCTYPE html>
<html>
<head></head>
<body>

<div id="scoped-content">
    <style type="text/css" scoped>
        h1 { color: red; } 
    </style>

    <h1>Hello</h1>
</div>

    <h1>
      World
    </h1>

</body>
</html>

Se você renderizar o código acima em um navegador compatível com HTML-5 compatível scoped, verá o escopo limitado da folha de estilos.

Há apenas uma grande ressalva ...

No momento em que escrevo esta resposta (maio de 2013), quase nenhum navegador mainstream atualmente suporta o scopedatributo. (Embora aparentemente as versões do desenvolvedor do Chromium sejam compatíveis).

No entanto, há uma implicação interessante do scopedatributo que pertence a esta pergunta. Isso significa que os navegadores futuros são obrigatórios via padrão para permitir <style>elementos dentro do <body>(desde que os <style>elementos tenham escopo definido).

Então, dado que:

  • Quase todos os navegadores existentes atualmente ignoram o scopedatributo
  • Quase todos os navegadores existentes atualmente permitem <style>tags dentro do<body>
  • Implementações futuras serão necessárias para permitir <style>tags (com escopo) dentro do<body>

... então, literalmente, não há mal nenhum em colocar <style>tags dentro do corpo, desde que você as proteja com um scopedatributo no futuro . O único problema é que os navegadores atuais não limitarão o escopo da folha de estilo - eles a aplicarão a todo o documento. Mas o ponto é que, para todos os fins práticos, você pode incluir <style>tags dentro do valor <body>que você:

  • Prepare seu HTML para o futuro incluindo o scopedatributo
  • Entenda que, a partir de agora, a folha de estilo dentro do <body>escopo não terá realmente um escopo (porque ainda não existe suporte ao navegador principal)


* exceto, é claro, por irritar os validadores HTML ...


Finalmente, com relação à alegação comum (mas subjetiva) de que a incorporação de CSS no HTML é uma prática inadequada, deve-se observar que todo o objetivo do scopedatributo é acomodar estruturas de desenvolvimento modernas típicas que permitem que os desenvolvedores importem partes do HTML como módulos ou conteúdo sindicado . É muito conveniente ter CSS incorporado que se aplica apenas a um pedaço específico de HTML, a fim de desenvolver componentes modulares encapsulados com estilos específicos.


Atualize a partir de fevereiro de 2019, de acordo com a documentação da Mozilla , o scopedatributo está obsoleto. O Chrome parou de suportá-lo na versão 36 (2014) e o Firefox na versão 62 (2018). Nos dois casos, o recurso teve que ser explicitamente ativado pelo usuário nas configurações dos navegadores. Nenhum outro navegador importante jamais o suportou.

Charles Salvia
fonte
3
@RobertMcKee: você realmente testou isso? Eu esperaria que geralmente toda a página html (incluindo todo o estilo embutido) seja analisada antes da renderização, pois geralmente não é enorme e os navegadores esperam um pouco (muito curto) enquanto antes da renderização precisamente para evitar o conteúdo sem flash que pode ocorrer devido ao css vinculado no head. Se esse for seu único CSS, e se a página for grande e se a conexão de rede não for muito rápida, talvez você veja um flash de conteúdo sem estilo, mas isso me surpreenderia nas situações mais práticas.
Eamon Nerbonne
4
Atualmente, apenas o Firefox suporta o elemento de estilo com escopo (de acordo com caniuse.com/#feat=style-scoped ). E como os navegadores comuns apenas suportam o elemento STYLE dentro do BODY, eu o usaria, se necessário. Se o CSS deve ser aplicado em um escopo, é possível prefixar cada seletor na fonte CSS com o ID / classe de um wrapper. Na verdade, eu fiz isso em um aplicativo Web que carregava relatórios HTML no lado do servidor e os renderizava via AJAX. O CSS pode ser prefixado com regex simples em JavaScript: cssString.replace (/ (^ | \}) ([^ {] +) (\ {) / g, '$ 1' + prefixo + '$ 2 $ 3')
Adam Ho
5
Suporte para @scoped, ou scopedparece estar morrendo: aqui e aqui
Kiran Subbaraman
51
Apoiando @KiranSubbaraman: Acabei de ler (julho de 2016) no mozilla dev: "O atributo escopo foi removido da especificação após apenas uma adoção limitada e experimental pelo Chrome e Firefox. Você deve evitar usá-lo , pois quase certamente será removidos desses navegadores em breve ". >> developer.mozilla.org/pt-BR/docs/Web/HTML/Element/…
jave.web
9
O scopedatributo foi removido das especificações atuais do HTML5.
Albert Wiersch 27/09/16
61

Notícias ruins para "estilo no corpo" amantes: W3C recentemente perdeu a guerra HTML contra WHATWG, cujo versionless HTML "padrão de vida" agora se tornou a oficial, que, infelizmente, não não permitir STYLE no BODY. Os dias felizes de curta duração terminaram. ;) O validador W3C também funciona com as especificações do WHATWG agora. (Obrigado @FrankConijn pelo aviso!)

(Nota: esse é o caso "a partir de hoje", mas como não há controle de versão, os links podem se tornar inválidos a qualquer momento sem aviso ou controle. A menos que você queira vincular sua fonte individual ao GitHub, você basicamente não pode faça referências estáveis ​​ao novo padrão oficial de HTML , AFAIK. Corrija-me se houver uma maneira canônica de fazer isso corretamente.)

BOAS NOTÍCIAS OBSILHADAS:

Yay, STYLEfinalmente é válido BODY, a partir do HTML5.2! (E scopedse foi também.)

Das especificações do W3C ( aprecie a última linha! ):

4.2.6 O elemento de estilo

...

Contextos em que este elemento pode ser usado:

Onde o conteúdo de metadados é esperado.

Em um elemento noscript que é filho de um elemento principal.

No corpo, onde o conteúdo do fluxo é esperado.


NOTA LATERAL DO META:

O mero fato de que, apesar dos danos da "guerra dos navegadores", ainda tínhamos que continuar desenvolvendo contra dois padrões "oficiais" HTML " ridiculamente concorrentes " (aspas para 1 standard + 1 standard < 1 standard) significa que a abordagem de "retorno ao senso comum nas trincheiras" o desenvolvimento web nunca realmente deixou de se aplicar.

Isso pode finalmente mudar agora, mas citando a sabedoria convencional: autores / desenvolvedores da Web e, portanto, por sua vez, os navegadores devem decidir o que deve (e não deve) estar nas especificações, quando não há uma boa razão contra o que já foi feito em realidade. E a maioria dos navegadores têm apoiado STYLEem BODY(de uma forma ou outra; ver, por exemplo o scoped. Attr) (que, apesar de seu desempenho inerente (e possivelmente outros) Pênaltis nós . Deve decidir pagar ou não, não as especificações). Então, por um lado, continuarei apostando neles e não vou perder a esperança. ;) Se o WHATWG tiver o mesmo respeito à realidade / autores que afirmam, eles podem acabar fazendo aqui o que o W3C fez.

Sz.
fonte
3
Eu li as especificações, mas não entendo. Você pode dar um exemplo de código de um stylebloco no bodyque valida?
31819 Frank Conijn
3
@FrankConijn: Bom ponto, as coisas mudaram, atualizei a resposta! É realmente confuso. As especificações 5.2 e 5.3 do W3C tratam STYLEcomo metadados e conteúdo de fluxo, mas as últimas especificações "vivas" do WHATWG contam a velha e chata história "apenas metadados" (permitindo apenas no HEAD). E, para adicionar insulto à lesão, o validador do W3C parece seguir o sabor WHATWG. Ainda não decidi rir ou chorar, mas com certeza decidi "errar" com o caso "browsers + W3C - validator" e permitir STYLE no BODY. (Aliás, não se esqueça: na verdade, devemos ser a melhor fonte do padrão .)
Sz.
Eu realmente acho que eles pularam o tubarão com essa porcaria, eles basicamente não deixam outra opção a não ser usar estilos de linha, se você deseja definir uma propriedade de imagem de fundo dinamicamente em um sistema de modelo. Era muito menos invasivo descartar um bloco de estilo gerado programaticamente logo acima da saída html.
GovCoder 22/02
32

Quando vejo que os sistemas de gerenciamento de conteúdo de sites grandes rotineiramente colocam alguns elementos <style> (alguns, não todos) próximos ao conteúdo que depende dessas classes, concluo que o cavalo está fora do estábulo.

Consulte as fontes da página do cnn.com, nytimes.com, huffingtonpost.com, o jornal da cidade grande mais próximo etc. etc. Todos eles fazem isso.

Se houver um bom motivo para colocar uma seção <style> extra em algum lugar do corpo - por exemplo, se você incluir () elementos de página diversos e independentes em tempo real e cada um tiver um estilo próprio incorporado, e a organização será mais limpa, mais modular, mais compreensível e mais sustentável - eu digo apenas morda a bala. Claro que seria melhor se pudéssemos ter um estilo "local" com escopo restrito, como variáveis ​​locais, mas você trabalha com o HTML que possui, não com o HTML que deseja ou deseja ter posteriormente.

É claro que existem desvantagens em potencial e boas (se não sempre obrigatórias) razões para seguir a ortodoxia, como outras pessoas elaboraram. Mas, para mim, parece cada vez mais com o uso ponderado de <style> em <body> já se tornou popular.

Timberline
fonte
1
Pragmatismo FTW!
Waruyama 26/09
1
Sim, você está certo. Como exemplo, eu uso a tag <style> em <body> dentro do meu plugin. Por que, porque é a maneira mais fácil de criar conteúdo elegante para plug-ins. Mas um momento, todas as classes css são únicas para os meus dados de plug-in.
Avirtum
7

HTML inválido; de qualquer maneira, praticamente todos os navegadores parecem considerar apenas a segunda instância.

Testado nas últimas versões do FF e Google Chrome no Fedora, e FF, Opera, IE e Chrome no XP.

nico
fonte
6

Acho que isso varia de navegador para navegador: as regras de exibição global provavelmente serão atualizadas à medida que o navegador avança no código.

Às vezes, você pode ver essas alterações nas regras de exibição global quando uma folha de estilo externa é carregada com um atraso. Algo semelhante pode acontecer aqui, mas em uma sucessão tão curta que na verdade não é renderizada.

De qualquer forma, não é HTML válido, então eu diria que é uma coisa fútil para se pensar. <style>tags pertencem à headseção da página.

Pekka
fonte
5

Como já foi dito, esse HTML inválido não é válido, pois as tags de estilo pertencem à cabeça.

No entanto, a maioria dos navegadores realmente não impõe essa validação. Em vez disso, depois que o documento é carregado, os estilos são mesclados e aplicados. Nesse caso, o segundo conjunto de estilos sempre substituirá o primeiro porque foram as últimas definições encontradas.

Eu não
fonte
5

A <style>tag pertence à <head>seção, separada de todo o conteúdo.

Referências: Especificações do W3C e W3Schools

Josh Stodola
fonte
52
Não aborda a questão. E essas diretrizes rígidas são invadidas pela realidade. Existem MUITOS casos em que não é possível que os autores definam / incluam seu estilo no cabeçalho html.
Javier
3
Isso pode ter sido verdade em 2010, mas está longe de ser uma resposta aceitável hoje.
Isaac Lubow
3

No seu exemplo, um navegador não deve "fazer nada". O HTML é inválido. A recuperação de erros é acionada ou o analisador faz o que quiser.

Em uma instância válida, várias folhas de estilo são tratadas como aparecendo uma após a outra, a cascata é calculada normalmente.

Quentin
fonte
2

Eu acho que isso pode ser uma questão sobre contextos limitados, por exemplo, editores WYIWYG em um sistema web usado por usuários não programadores , que limita as possibilidades de seguir os padrões. Às vezes (como o TinyMCE), é uma biblioteca que coloca seu conteúdo / código dentro de uma textareatag, renderizada pelo editor como uma divtag grande . E, às vezes, pode ser uma versão antiga desses editores.

Suponho que:

  1. esses usuários não programadores não têm um canal aberto com os administradores do sistema (ou webdevs da instituição), para solicitar a inclusão de algumas regras CSS nasstylesheets . Na verdade, seria impraticável para os administradores (ou webdevs), considerando o número de solicitações nesse sentido que elas teriam.
  2. esse sistema é legado e ainda não suporta versões mais recentes de HTML.

Em alguns casos, sem styleregras de uso , pode ser uma experiência de design muito ruim. Então, sim, esses usuários precisam de personalização. Ok, mas quais seriam as soluções nesse cenário? Considerando as diferentes maneiras de inserir CSS em uma htmlpágina, suponho que estas soluções:


1ª opção: pergunte ao seu sysadm

Peça ao administrador do sistema para incluir algumas regras CSS no sistema stylesheets. Essa será uma solução CSS externa ou interna . Como já foi dito, pode não ser possível.


2ª opção: <link>ativada<body>

Use uma folha de estilo externa na bodytag, ou seja, o uso da linktag dentro da área que você tem acesso (que será, no site, dentro da bodytag e não na headtag). Algumas fontes dizem que está tudo bem, mas "não é uma boa prática", como o MDN :

Um <link>elemento pode ocorrer no elemento <head>ou <body>, dependendo se ele possui um tipo de link que está correto para o corpo . Por exemplo, o stylesheettipo de link é body-ok e, portanto, <link rel="stylesheet">é permitido no corpo. No entanto, essa não é uma boa prática a seguir; faz mais sentido separar seus <link>elementos do conteúdo do corpo, colocando-os no <head>.

Alguns outros o restringem à <head>seção, como w3schools :

Nota: Este elemento vai apenas na seção principal, mas pode aparecer várias vezes.

Teste

Eu testei aqui (ambiente de desktop, em um navegador) e funciona para mim. Crie um arquivo foo.html:

<!DOCTYPE html>
<html>
<head></head>
<body>
    <link href="bar.css" type="text/css" rel="stylesheet">
    <h1 class="test1">Hello</h1>
    <h1 class="test2">World</h1>
</body>
</html>

E, em seguida, um arquivo CSS, no mesmo diretório, chamado bar.css:

.test1 { 
    color: green;
};

Bem, isso só parece possível se você tiver como fazer upload de um arquivo CSS em algum lugar do sistema da instituição. Talvez este fosse o caso.


3ª opção: <style>ativada<body>

Use a folha de estilo da Internet na bodyetiqueta, ou seja, o uso da styleetiqueta dentro da área a que você tem acesso (que será, no site, dentro da bodytag e não na headtag). É disso que trata as respostas de Charles Salvia e Sz aqui. Escolhendo esta opção, considere suas preocupações.


4ª, 5ª e 6ª opções: maneiras JS

Alerta Esses estão relacionados à modificação do <head>elemento da página. Talvez isso não seja permitido pelos administradores de sistema da instituição. Portanto, é recomendável pedir permissão a eles primeiro.

Ok, supondo a permissão concedida, a estratégia é acessar o <head> . Quão? Métodos JavaScript.

4ª opção: novo <link>em<head>

Esta é outra versão da 2ª opção. Use uma folha de estilo externa na <head>tag, ou seja, uso do <link>elemento fora da área que você tem acesso (que será, no site, não dentro da bodytag e sim dentro da headtag). Esta solução está em conformidade com as recomendações da MDN e da w3schools , conforme citado acima, na segunda opção de solução. Um novo Linkobjeto será criado.

Para resolver o problema por meio do JS, existem várias maneiras, mas nas seguintes linhas de código eu demonstro uma simples.

Teste

Eu testei aqui (ambiente de desktop, em um navegador) e funciona para mim. Crie um arquivo f.html:

<!DOCTYPE html>
<html>
<head></head>
<body>
    <h1 class="test1">Hello</h1>
    <h1 class="test2">World</h1>
    <script>
        // JS code here
    </script>
</body>
</html>

Dentro da scripttag:

var newLink = document.createElement("link");
newLink.href = "bar.css";
newLink.rel = "stylesheet";
newLink.type = "text/css";
document.getElementsByTagName("head")[0].appendChild(newLink);

E então, no arquivo CSS, no mesmo diretório, chamado bar.css(como na segunda opção):

.test1 { 
    color: green;
};

Como eu já disse: isso só parece possível se você tiver como fazer upload de um arquivo CSS em algum lugar do sistema da instituição.

5ª opção: novo <style>em<head>

Use uma nova folha de estilo interna na <head>tag, ou seja, use um novo <style>elemento fora da área que você tem acesso (que será, no site, não dentro da bodytag e sim dentro da headtag). Um novo Styleobjeto será criado.

Isso é resolvido através do JS. Uma maneira simples é demonstrada a seguir.

Teste

Eu testei aqui (ambiente de desktop, em um navegador) e funciona para mim. Crie um arquivo foobar.html:

<!DOCTYPE html>
<html>
<head></head>
<body>
    <h1 class="test1">Hello</h1>
    <h1 class="test2">World</h1>
    <script>
        // JS code here
    </script>
</body>
</html>

Dentro da scripttag:

var newStyle = document.createElement("style");
newStyle.innerHTML = 
    "h1.test1 {"+
        "color: green;"+
    "}";
document.getElementsByTagName("head")[0].appendChild(newStyle);

6ª opção: usar um já existente <style>em<head>

Use uma folha de estilo interna existente na <head>tag, ou seja, uso de um <style>elemento fora da área que você tem acesso (que será, no site, não dentro da bodytag e sim dentro da headtag), se houver algum. Um novo Styleobjeto será criado ou um CSSStyleSheetobjeto será usado (no código da solução adotada aqui).

Isso é arriscado em algum ponto de vista. Primeiro , porque talvez não exista algum <style> objeto. Dependendo da maneira como você implementa esta solução, você pode obter undefinedretorno (o sistema pode usar folhas de estilo externas ). Segundo , porque você estará editando o trabalho do autor do design do sistema (problemas de autoria). Terceiro , porque pode não ser permitido nas políticas de segurança de TI da sua instituição. Portanto, peça permissão para fazer isso (como em outras soluções JS) .

Supondo, novamente, a permissão foi concedida:

Você terá de considerar algumas restrições do método disponível para desta forma: insertRule(). A solução proposta usa o cenário padrão e uma operação no primeirostylesheet , se houver algum.

Teste

Eu testei aqui (ambiente de desktop, em um navegador) e funciona para mim. Crie um arquivo foo_bar.html:

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <h1 class="test1">Hello</h1>
    <h1 class="test2">World</h1>
    <script>
      // JS code here
    </script>
  </body>
</html>

Dentro da scripttag:

function demoLoop(){ // remove this line
    var elmnt = document.getElementsByTagName("style");
    if (elmnt.length === 0) {
        // there isn't style objects, so it's more interesting create one
        var newStyle = document.createElement("style");
        newStyle.innerHTML =
            "h1.test1 {" +
                "color: green;" +
            "}";
        document.getElementsByTagName("head")[0].appendChild(newStyle);
    } else {
        // Using CSSStyleSheet interface
        var firstCSS = document.styleSheets[0];
        firstCSS.insertRule("h1.test2{color:blue;}"); // at this way (without index specified), will be like an Array unshift() method
    }
} // remove this too
demoLoop(); // remove this too
demoLoop(); // remove this too

Outra abordagem para esta solução é usar CSSStyleDeclarationobjeto (documentos em w3schools e MDN ). Mas pode não ser interessante, considerando o risco de substituir as regras existentes no CSS do sistema.


7ª opção: CSS embutido

Use CSS embutido . Isso resolve o problema, embora, dependendo do tamanho da página (em linhas de código), a manutenção (pelo próprio autor ou outra pessoa designada) do código possa ser muito difícil.

Mas, dependendo do contexto de sua função na instituição ou de suas políticas de segurança do sistema da web, essa pode ser a solução disponível exclusiva para você.

Teste

Crie um arquivo _foobar.html:

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <h1 style="color: green;">Hello</h1>
    <h1 style="color: blue;">World</h1>    
  </body>
</html>

Respondendo estritamente à pergunta de Gagan

Como um navegador deve renderizar css que não é contíguo?

  1. É suposto gerar alguma estrutura de dados usando todos os estilos css em uma página e usá-la para renderizar?
  2. Ou ele renderiza usando informações de estilo na ordem em que vê?

(citação adaptada)

Para uma resposta mais precisa, sugiro ao Google os seguintes artigos:

  • Como os navegadores funcionam: nos bastidores dos navegadores modernos
  • Construção, layout e pintura da árvore de renderização
  • O que significa "renderizar" uma página da Web?
  • Como a renderização do navegador funciona - nos bastidores
  • Renderização - Padrão HTML
  • 10 Renderização - HTML5
Igor Santos
fonte
+1 Boa ideia incluindo marcas de script e usar JavaScript para adicionar CSS, HTML perfeitamente legal para mudos editores WYSIWYG CMS
djolf
1

Como este HTML não é válido, não afeta o resultado ... significa apenas que o HTML segue o padrão (apenas para fins organizacionais). Por uma questão de validade, poderia ter sido escrito desta maneira:

<html>
<head>
<style type="text/css">
  p.first {color:blue}
  p.second {color:green}
</style>
</head>
<body>
<p class="first" style="color:green;">Hello World</p>
<p class="second" style="color:blue;">Hello World</p>

Meu palpite é que o navegador aplica o último estilo que aparece.

G. Bickham
fonte