Si las estrategias que hemos visto hasta ahora no te convencen para crear «código CSS local» (que afecte sólo a una pequeña región del HTML), entonces te puede interesar el denominado Shadow DOM declarativo.
Al igual que cuando hablamos de DOM estamos hablando de la estructura HTML de nuestra página, cuando hablamos de Shadow DOM estamos hablando de una encapsulación HTML, es decir, de una pequeña sección en la página, a la que no le va a afectar cosas del exterior (y viceversa).
¿Cuál es el problema?
El problema que tenemos ahora mismo es que queremos crear una pequeña zona de la página, donde queremos que el CSS global no le afecte, y el CSS de esa zona, no afecte al resto de la página. Observa este código donde, aunque añadimos un bloque <style>
después del primer <h2>
, sigue afectando a ambos en todo el documento:
<h2>Titular superior</h2>
<style>
h2 {
background: green;
color: white;
padding: 1rem;
}
</style>
<h2>Titular inferior</h2>
Esto se puede solucionar facilmente añadiendo clases contenedoras para delimitarlo, pero se trata de una solución global que no es escalable, ya que posteriormente deberás tener en cuenta los nombres utilizados, o tener cuidado de que no colisione con otro desarrollador que trabaje en el proyecto.
Nos interesa una solución más «autónoma».
Shadow DOM declarativo
El Shadow DOM declarativo es una solución donde sólo con HTML podemos hacer justo lo que buscamos. Observa que simplemente, en el interior de un elemento HTML colocamos una etiqueta <template>
. Esta etiqueta se utiliza para crear plantillas, pero con el atributo shadowrootmode
le podemos indicar que el contenido de dicha etiqueta es HTML encapsulado, y que debe estar aislado del documento principal:
<h2>Títular exterior</h2>
<div class="container">
<template shadowrootmode="open">
<h2>Titular interior</h2>
<style>
h2 {
background: indigo;
color: white;
padding: 1rem;
}
</style>
</template>
</div>
Debido a esto, el código CSS del interior de la etiqueta <template>
no afectará al resto del documento. De la misma forma, si creamos estilos CSS en el exterior del <template>
, de forma global, dichos estilos tampoco afectarán al interior del <template>
:
<h2>Títular exterior</h2>
<style>
h2 {
background: indigo;
color: white;
padding: 1rem;
}
</style>
<div class="container">
<template shadowrootmode="open">
<h2>Titular interior</h2>
</template>
</div>
Esto lo convierte en una genial forma de crear estilos encapsulados sólo con HTML, sin necesidad de utilizar herramientas externas.
Shadow DOM con Javascript
En el caso de necesitarlo, esta encapsulación se puede hacer también mediante Javascript. Para ello, se realiza algo parecido a lo que hemos visto antes. En el HTML tenemos:
- 1️⃣ Un titular
<h2>
a nivel global (exterior). - 2️⃣ Un elemento
.container
donde vamos a añadir contenido HTML. - 3️⃣ Un fragmento de código HTML inactivo y oculto, que vamos a copiar para clonar.
<h2>Títular exterior</h2>
<div class="container"></div>
<template>
<h2>Titular interior</h2>
<style>
h2 {
background: indigo;
color: white;
padding: 1rem;
}
</style>
</template>
const container = document.querySelector(".container");
const template = document.querySelector("template");
container.attachShadow({ mode: "open" });
container.shadowRoot.append(template.content.cloneNode(true));
Como ves, si miras la demo, verás que el resultado es equivalente al del ejemplo del apartado anterior, sólo que lo hemos hecho desde Javascript. La explicación de las líneas realizadas son las siguientes:
- 1️⃣ Buscamos un elemento donde crear el Shadow DOM (
.container
). - 2️⃣ Buscamos el fragmento de código HTML que queremos clonar (interior de
<template>
). - 3️⃣ Creamos un Shadow DOM en el elemento
.container
. - 4️⃣ Añadimos el contenido clonado del template en el
shadowRoot
del elemento.
La última parte de este ejemplo Javascript puede ser difícil de entender. Si te interesa profundizar más en esto, te aconsejo echar un vistazo a ¿Qué es el Shadow DOM?.