Usar etiquetas <style> en <body> con otro 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>

¿Cómo se supone que un navegador representa css que no es contiguo? ¿Se supone que genera alguna estructura de datos usando todos los estilos CSS en una página y la usa para renderizar?

¿O se procesa utilizando información de estilo en el orden que ve?

Gagan
fuente
2
Yo diría que es un comportamiento indefinido ya que no es HTML válido. Para obtener más información sobre qué elementos son válidos y cuáles no: en.wikipedia.org/wiki/HTML_element
Felix Kling
2
Dejando a un lado este problema, es una mala práctica confundirse CSSy HTML.
0x2D9A3
1
@ 0x2D9A3 No necesariamente es cierto. Se requiere más tiempo para solicitar una página CSS externa que la CSS definida en la <head>etiqueta
Kolob Canyon,
@KolobCanyon De acuerdo, pero como regla general, CSS debe estar en un archivo separado. Si tiene toneladas de CSS, es más fácil de administrar (mantener, (post) procesar, minificar, agrupar) y servir como un archivo separado, y su contenido (HTML) también puede cargar más rápido, lo que lleva a una mejor experiencia de usuario . Sin embargo, como siempre con el desarrollo, todo es específico del contexto, por lo que YMMW :)
0x2D9A3
3
@KolobCanyon, no se trata de si CSS debe estar en un archivo separado. En este caso, la pregunta es sobre CSS en <body>lugar de en <head>.
Ray Butterworth

Respuestas:

312

Como otros ya han mencionado, HTML 4 requiere que la <style>etiqueta se coloque en la <head>sección (aunque la mayoría de los navegadores permiten <style>etiquetas dentro de body).

Sin embargo, HTML 5 incluye el scopedatributo (consulte la actualización a continuación), que le permite crear hojas de estilo dentro del elemento principal de la <style>etiqueta. Esto también le permite colocar <style>etiquetas dentro del <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>

Si representa el código anterior en un navegador habilitado para HTML-5 que admita scoped, verá el alcance limitado de la hoja de estilo.

Solo hay una advertencia importante ...

En el momento en que escribo esta respuesta (mayo de 2013), casi ningún navegador convencional actualmente admite el scopedatributo. (Aunque aparentemente las construcciones de desarrollador de Chromium admiten).

SIN EMBARGO, hay una implicación interesante del scopedatributo que pertenece a esta pregunta. Significa que los futuros navegadores están obligados a través del estándar para permitir <style>elementos dentro del <body>(siempre y cuando los <style>elementos tengan un alcance).

Entonces, dado que:

  • Casi todos los navegadores existentes actualmente ignoran el scopedatributo
  • Casi todos los navegadores existentes actualmente permiten <style>etiquetas dentro de<body>
  • Se requerirán implementaciones futuras para permitir <style>etiquetas (de ámbito) dentro del<body>

... entonces, literalmente, no hay daño * al colocar <style>etiquetas dentro del cuerpo, siempre que las pruebe en el futuro con un scopedatributo. El único problema es que los navegadores actuales en realidad no limitarán el alcance de la hoja de estilo, sino que lo aplicarán a todo el documento. Pero el punto es que, a todos los efectos prácticos, puede incluir <style>etiquetas dentro de las <body>que siempre que:

  • Prepara tu HTML para el futuro incluyendo el scoped atributo
  • Comprenda que a partir de ahora, la hoja de estilo dentro de la <body>realidad no tendrá alcance (porque todavía no existe soporte para el navegador principal)


* excepto, por supuesto, para cabrear los validadores HTML ...


Finalmente, con respecto a la afirmación común (pero subjetiva) de que incrustar CSS en HTML es una mala práctica, debe tenerse en cuenta que el objetivo principal del scopedatributo es acomodar los marcos de desarrollo modernos típicos que permiten a los desarrolladores importar fragmentos de HTML como módulos o contenido sindicado . Es muy conveniente tener CSS incrustado que solo se aplica a un fragmento particular de HTML, para desarrollar componentes modulares encapsulados con estilos específicos.


Actualización a partir de febrero de 2019, de acuerdo con la documentación de Mozilla , el scopedatributo está en desuso. Chrome dejó de admitirlo en la versión 36 (2014) y Firefox en la versión 62 (2018). En ambos casos, el usuario tenía que habilitar explícitamente la función en la configuración de los navegadores. Ningún otro navegador importante lo soportó.

Charles Salvia
fuente
3
@RobertMcKee: ¿realmente has probado eso? Esperaría que generalmente toda la página html (incluido todo el estilo en línea) se analice antes de renderizar, ya que generalmente no es enorme y los navegadores esperan un (muy corto) tiempo antes de renderizar con precisión para evitar el destello de contenido sin estilo que pueda ocurrir debido a css vinculado en el head. Si esta es su única css, y si la página es grande y si la conexión de red no es muy rápido, entonces tal vez usted va a ver un destello de contenido sin estilo, pero me había sorpresa en la mayoría de las situaciones prácticas.
Eamon Nerbonne
44
A partir de hoy, solo Firefox admite elementos de estilo con ámbito (de acuerdo con caniuse.com/#feat=style-scoped ). Y dado que los navegadores comunes solo admiten el elemento STYLE dentro de BODY, lo usaría si fuera necesario. Si el CSS se debe aplicar en un ámbito, puede simplemente prefijar cada selector en la fuente CSS con ID / clase de un contenedor. Realmente hice esto en una aplicación web que cargó informes HTML del lado del servidor y los procesó a través de AJAX. El CSS se puede prefijar con una expresión regular simple en JavaScript: cssString.replace (/ (^ | \}) ([^ {] +) (\ {) / g, '$ 1' + prefijo + '$ 2 $ 3')
Adam Hošek
55
Apoyo @scopedo scopedparece estar desapareciendo: aquí y aquí
Kiran Subbaraman
51
Apoyo a @KiranSubbaraman: Acabo de leer (julio de 2016) en mozilla dev: "El atributo de ámbito se ha eliminado de la especificación después de una adopción limitada y experimental por parte de Chrome y Firefox. Deberías evitar usarlo , ya que seguramente será eliminado de estos navegadores pronto ". >> developer.mozilla.org/en-US/docs/Web/HTML/Element/…
jave.web
9
El scopedatributo se ha eliminado de las especificaciones HTML5 actuales.
Albert Wiersch
61

BREAKING BAD NEWS para amantes del "estilo en el cuerpo": W3C ha perdido recientemente la guerra de HTML contra WHATWG, cuyo HTML "Living Standard" sin versión se ha convertido en el oficial, que, por desgracia, no está permitido STYLE en el BODY. Los días felices de corta duración han terminado. ;) El validador W3C también funciona con las especificaciones WHATWG ahora. (¡Gracias @FrankConijn por el aviso!)

(Nota: este es el caso "a partir de hoy", pero dado que no hay versiones, los enlaces pueden volverse inválidos en cualquier momento sin previo aviso o control. A menos que esté dispuesto a vincular a sus confirmaciones de fuente individuales en GitHub, básicamente no puede ya no haga referencias estables al nuevo estándar HTML oficial , AFAIK. Corríjame si hay una forma canónica de hacerlo correctamente).

BUENAS NOTICIAS OBSOLETADAS:

¡Yay, STYLEfinalmente es válido en BODY, a partir de HTML5.2! (Y también scopedse fue).

De las especificaciones del W3Cdisfruta la última línea! ):

4.2.6. El elemento de estilo

...

Contextos en los que se puede usar este elemento:

Donde se espera contenido de metadatos.

En un elemento noscript que es hijo de un elemento head.

En el cuerpo, donde se espera el contenido de flujo.


NOTA LATERAL DEL META:

El mero hecho de que a pesar de los daños de la "guerra de los navegadores" todavía teníamos que seguir desarrollándonos contra dos competidores ridículamente estándares "HTML" " " (cita para 1 standard + 1 standard < 1 standard) significa que el enfoque de "respaldo al sentido común" El desarrollo web nunca ha dejado de aplicarse.

Esto finalmente puede cambiar ahora, pero citando la sabiduría convencional: los autores / desarrolladores web y, por lo tanto, los navegadores deberían decidir qué debería (y no debería) estar en las especificaciones, cuando no hay una buena razón contra lo que ya se ha hecho en realidad. Y la mayoría de los navegadores han apoyado durante mucho tiempo STYLEen BODY(de una forma u otra; véase, por ejemplo el scoped. Attr) (que, a pesar de su rendimiento inherente (y posiblemente otros) las sanciones que . Deberíamos decidir pagar o no, no las especificaciones). Entonces, por mi parte, seguiré apostando por ellos y no perderé la esperanza. ;) Si WHATWG tiene el mismo respeto por la realidad / autores que afirman, pueden terminar haciendo lo que hizo el W3C.

Sz.
fuente
3
Leí las especificaciones, pero no entiendo. ¿Puedes dar un código de ejemplo de un stylebloque en el bodyque valide?
Frank Conijn
3
@FrankConijn: ¡Buen punto, las cosas cambiaron, actualicé la respuesta! Es realmente confuso Tanto las especificaciones 5.2 y 5.3 del W3C se tratan STYLEcomo metadatos y contenido de flujo, pero la última especificación "viva" de WHATWG cuenta la vieja y aburrida historia "solo metadatos" (permitiéndola solo en HEAD). Y, para agregar insulto a la lesión, el validador W3C parece seguir el sabor WHATWG. Todavía no he decidido si reír o llorar, pero seguro decidí, personalmente, "errar" con el caso "navegadores + W3C - validador", y permitir ESTILO en el CUERPO. (Por cierto, no lo olvides: deberíamos ser la última fuente del estándar , en realidad.)
Sz.
Realmente creo que saltaron al tiburón con esta basura, básicamente no dejan más remedio que usar en estilos de línea si desea establecer una propiedad de imagen de fondo dinámicamente en un sistema con plantilla. Fue mucho menos invasivo soltar un bloque de estilo generado mediante programación justo por encima de su salida html.
GovCoder
32

Cuando veo que los sistemas de gestión de contenido de sitios grandes ponen rutinariamente algunos elementos <style> (algunos, no todos) cerca del contenido que se basa en esas clases, concluyo que el caballo está fuera del establo.

Mire las fuentes de la página de cnn.com, nytimes.com, huffingtonpost.com, su periódico de la gran ciudad más cercano, etc. Todos ellos hacen esto.

Si hay una buena razón para poner una sección <style> adicional en algún lugar del cuerpo, por ejemplo, si incluye () elementos de página diversos e independientes en tiempo real y cada uno tiene un <style> incrustado, y la organización será más limpia, más modular, más comprensible y más fácil de mantener. Solo digo que muerda la bala. Claro, sería mejor si pudiéramos tener un estilo "local" con un alcance restringido, como las variables locales, pero si trabajas con el HTML que tienes, no con el HTML que quieras o quieras tener más adelante.

Por supuesto, hay posibles inconvenientes y buenas (si no siempre convincentes) razones para seguir la ortodoxia, como han explicado otros. Pero para mí parece cada vez más que el uso reflexivo de <style> en <body> ya se ha generalizado.

Timberline
fuente
1
Pragmatismo FTW!
Waruyama
1
Sí tienes razón. Como ejemplo, uso la etiqueta <style> en <body> dentro de mi plugin. ¿Por qué? Porque es la forma más fácil de crear contenido de complementos con estilo. Pero en un momento, todas las clases de CSS son únicas para mis datos de complemento.
Avirtum
7

HTML no válido, de todos modos, casi todos los navegadores parecen considerar solo la segunda instancia.

Probado en las últimas versiones de FF y Google Chrome en Fedora, y FF, Opera, IE y Chrome en XP.

nico
fuente
6

Supongo que esto variará de un navegador a otro: las reglas de visualización global probablemente se actualizarán a medida que el navegador siga el código.

Puede ver dichos cambios en las reglas de visualización global a veces cuando una hoja de estilo externa se carga con retraso. Algo similar podría ocurrir aquí, pero en una sucesión tan corta que en realidad no se procesa.

De todos modos, no es HTML válido, así que diría que es inútil pensar en eso. <style>Las etiquetas pertenecen a la headsección de la página.

Pekka
fuente
5

Como han dicho otros, esto no es html válido ya que las etiquetas de estilo pertenecen a la cabeza.

Sin embargo, la mayoría de los navegadores realmente no aplican esa validación. En cambio, una vez que se carga el documento, los estilos se fusionan y se aplican. En este caso, el segundo conjunto de estilos siempre anulará el primero porque fueron las últimas definiciones encontradas.

Yo no
fuente
5

La <style>etiqueta pertenece en el<head> sección, separada de todo el contenido.

Referencias: W3C Specs y W3Schools

Josh Stodola
fuente
52
No aborda la pregunta. Y esas pautas rígidas están invadidas por la realidad. Hay MUCHOS casos en los que no es posible para los autores definir / incluir su estilo en el encabezado html.
Javier
3
Esto puede haber sido cierto en 2010, pero está lejos de ser una respuesta aceptable hoy.
Isaac Lubow
3

En su ejemplo, no se "supone" que un navegador haga nada. El HTML no es válido. O se activa la recuperación de error, o el analizador lo hace como lo hará.

En una instancia válida, varias hojas de estilo simplemente se tratan como apareciendo una tras otra, la cascada se calcula como normal.

Quentin
fuente
2

Supongo que esto puede ser un problema sobre contextos limitados, por ejemplo, editores WYIWYG en un sistema web utilizado por usuarios que no son programadores , que limita las posibilidades de seguir los estándares. A veces (como TinyMCE), es una biblioteca que pone su contenido / código dentro de una textareaetiqueta, que el editor representa como una divetiqueta grande . Y a veces, puede ser una versión antigua de estos editores.

Supongo que:

  1. estos usuarios que no son programadores no tienen un canal abierto con los administradores del sistema (o los webdevs de la institución), para solicitar la inclusión de algunas reglas CSS en el sistemastylesheets . En realidad, no sería práctico para los administradores (o webdevs), considerando la cantidad de solicitudes en ese sentido que tendrían.
  2. Este sistema es heredado y aún no admite versiones más recientes de HTML.

En algunos casos, sin stylereglas de uso , puede ser una experiencia de diseño muy pobre. Entonces, sí, estos usuarios necesitan personalización. Bien, pero ¿cuáles serían las soluciones en este escenario? Considerando las diferentes formas de insertar CSS en una htmlpágina, supongo que estas soluciones:


Primera opción: pregunta a tu administrador de sistemas

Solicite a su adm sistema que incluya algunas reglas CSS en el sistema stylesheets. Esta será una solución CSS externa o interna . Como ya se dijo, podría no ser posible.


2da opción: <link>en<body>

Use una hoja de estilo externa en la bodyetiqueta, es decir, use la linketiqueta dentro del área a la que tiene acceso (es decir, en el sitio, dentro de la bodyetiqueta y no en la headetiqueta). Algunas fuentes dicen que está bien, pero "no es una buena práctica", como MDN :

Un <link>elemento puede aparecer en el elemento <head>o <body>, dependiendo de si tiene un tipo de enlace que sea body-ok . Por ejemplo, el stylesheettipo de enlace es body-ok y, por <link rel="stylesheet">lo tanto, está permitido en el cuerpo. Sin embargo, esta no es una buena práctica a seguir; tiene más sentido separar sus <link>elementos del contenido de su cuerpo, colocándolos en el <head>.

Algunos otros lo restringen a la <head>sección, como w3schools :

Nota: Este elemento va solo en la sección de encabezado, pero puede aparecer cualquier número de veces.

Pruebas

Lo probé aquí (entorno de escritorio, en un navegador) y funciona para mí. Crea un archivo 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>

Y luego un archivo CSS, en el mismo directorio, llamado bar.css:

.test1 { 
    color: green;
};

Bueno, esto solo parece posible si tiene cómo cargar un archivo CSS en algún lugar del sistema de la institución. Quizás este sea el caso.


3a opción: <style>en<body>

Use la hoja de estilo de Internet en la bodyetiqueta, es decir, use la styleetiqueta dentro del área a la que tiene acceso (es decir, en el sitio, dentro de la bodyetiqueta y no en la headetiqueta). De esto se tratan las respuestas de Charles Salvia y Sz . Al elegir esta opción, considere sus preocupaciones.


4ta, 5ta y 6ta opciones: formas JS

Alerta Estos están relacionados con la modificación del <head>elemento de la página. Quizás esto no sea ​​permitido por los administradores del sistema de la institución. Por lo tanto, se recomienda pedirles permiso primero.

Bien, suponiendo que se otorgue el permiso, la estrategia es acceder al <head> . ¿Cómo? Métodos JavaScript

4a opción: nuevo <link>en<head>

Esta es otra versión de la segunda opción. Use una hoja de estilo externa en la <head>etiqueta, es decir, use el <link>elemento fuera del área a la que tiene acceso (es decir, en el sitio, no dentro de la bodyetiqueta y sí dentro de la headetiqueta). Esta solución cumple con las recomendaciones de MDN y w3schools , como se mencionó anteriormente, en la solución de segunda opción. Se creará un nuevo Linkobjeto .

Para resolver el problema a través de JS, hay muchas formas, pero en las siguientes líneas de código demuestro una simple.

Pruebas

Lo probé aquí (entorno de escritorio, en un navegador) y funciona para mí. Crea un archivo 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 de la scriptetiqueta:

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

Y luego en el archivo CSS, en el mismo directorio, llamado bar.css(como en la segunda opción):

.test1 { 
    color: green;
};

Como ya dije: esto solo parece posible si tiene cómo cargar un archivo CSS en algún lugar del sistema de la institución.

5ta opción: nuevo <style>en<head>

Use una nueva hoja de estilo interna en la <head>etiqueta, es decir, use un nuevo <style>elemento fuera del área a la que tenga acceso (es decir, en el sitio, no dentro de la bodyetiqueta y sí dentro de la headetiqueta). Se creará un nuevo Styleobjeto .

Esto se resuelve a través de JS. Una manera simple se demuestra a continuación.

Pruebas

Lo probé aquí (entorno de escritorio, en un navegador) y funciona para mí. Crea un archivo 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 de la scriptetiqueta:

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

6ta opción: usar un existente <style>en<head>

Use una hoja de estilo interna existente en la <head>etiqueta, es decir, use un <style>elemento fuera del área a la que tenga acceso (es decir, en el sitio, no dentro de la bodyetiqueta y sí dentro de la headetiqueta), si existe. Se Stylecreará un nuevo objeto o se usará un CSSStyleSheetobjeto (en el código de la solución adoptada aquí).

Esto es, en algún punto de vista, arriesgado. Primero , porque puede que no exista algún <style> objeto. Dependiendo de la forma en que implemente esta solución, puede obtener un undefinedretorno (el sistema puede usar una hoja de estilo externa ). En segundo lugar , porque editará el trabajo del autor del diseño del sistema (problemas de autoría). Tercero , porque puede no estar permitido en las políticas de seguridad de TI de su institución. Entonces, solicite permiso para hacer esto (como en otras soluciones JS) .

Suponiendo, nuevamente, que se concedió el permiso:

Tendrá que tener en cuenta algunas limitaciones del método disponible para de esta manera: insertRule(). La solución propuesta utiliza el escenario predeterminado y una operación en la primerastylesheet , si existe alguna.

Pruebas

Lo probé aquí (entorno de escritorio, en un navegador) y funciona para mí. Crea un archivo 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 de la scriptetiqueta:

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

Otro enfoque para esta solución es usar CSSStyleDeclarationobject (documentos en w3schools y MDN ). Pero puede no ser interesante, teniendo en cuenta el riesgo de anular las reglas existentes en el CSS del sistema.


Séptima opción: CSS en línea

Usa CSS en línea . Esto resuelve el problema, aunque dependiendo del tamaño de la página (en líneas de código), el mantenimiento (por el propio autor u otra persona asignada) del código puede ser muy difícil.

Pero dependiendo del contexto de su rol en la institución, o sus políticas de seguridad del sistema web, esta podría ser la solución única disponible para usted.

Pruebas

Crea un archivo _foobar.html:

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

Respondiendo estrictamente la pregunta hecha por Gagan

¿Cómo se supone que un navegador representa css que no es contiguo?

  1. ¿Se supone que genera alguna estructura de datos usando todos los estilos CSS en una página y la usa para renderizar?
  2. ¿O se procesa utilizando información de estilo en el orden que ve?

(cita adaptada)

Para una respuesta más precisa, le sugiero a Google estos artículos:

  • Cómo funcionan los navegadores: detrás de escena de los navegadores web modernos
  • Construcción, diseño y pintura del árbol de renderizado
  • ¿Qué significa "renderizar" una página web?
  • Cómo funciona la representación del navegador: detrás de escena
  • Renderizado - Estándar HTML
  • 10 Renderizado - HTML5
Igor Santos
fuente
+1 Buena idea incluyendo etiquetas de script y usar javascript para agregar CSS, HTML perfectamente legal para editores CMS WYSIWYG tontos
djolf
1

Debido a que este HTML no es válido, no tiene ningún efecto en el resultado ... solo significa que el HTML se adhiere al estándar (simplemente con fines organizativos). En aras de ser válido, podría haberse escrito de esta manera:

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

Supongo que el navegador aplica el último estilo con el que se encuentra.

G. Bickham
fuente