Uso de Shadow DOM para Encapsular Estilos en Componentes Web
Resumen
¿Qué es el Shadow DOM y cómo resuelve problemas de reescritura de estilos?
El Shadow DOM es una tecnología que permite a los desarrolladores web definir componentes de interfaz encapsulados, protegiendo su estructura y estilos en el navegador. A menudo, los desarrolladores enfrentan problemas cuando los estilos de sus proyectos se reescriben al agregar bibliotecas de CSS, como Bootstrap. Esto puede llevar a la mala práctica de usar !important para mantener estilos deseados. Sin embargo, el Shadow DOM ofrece una solución a esta problemática al crear un entorno aislado dentro del DOM global, de manera que los estilos externos no afecten a los internos del componente.
¿Cómo se integra el Shadow DOM en un componente?
Integrar el Shadow DOM en tus componentes resulta ser un proceso sencillo y extremadamente útil para mantener la integridad de los estilos CSS. A continuación, se detallan los pasos básicos:
Crear la instancia del Shadow DOM: Dentro del constructor de tu componente, utiliza el método attachShadow.
this.attachShadow({mode:'open'});
Transferir el contenido al Shadow DOM: Al crear un componente web, el contenido del mismo se debe adjuntar específicamente al Shadow DOM.
Manipulación del Shadow DOM: En vez de utilizar document, se debe operar directamente con shadowRoot para cambiar o consultar los elementos dentro del Shadow DOM.
¿Qué modo seleccionar para el Shadow DOM: abierto o cerrado?
El modo del Shadow DOM puede ser abierto o cerrado. Por buenas prácticas, se suele elegir el modo "open" para permitir que elementos internos del Shadow DOM sean accesibles desde fuera del componente, promoviendo una mayor reutilización y flexibilidad. Esta elección posibilita ver el contenido y realizar interacciones con los componentes, como por ejemplo en etiquetas estándar de HTML5 (<input>, <video>, etc.).
¿Cómo afecta el Shadow DOM a la reescritura de estilos?
Con el Shadow DOM, los estilos CSS internos se encapsulan, evitando que los estilos externos impacten su diseño. Esto se demuestra fácilmente cuando dos h2 con estilos conflictivos no son reescritos, uno enfocándose en azul y otro en rojo, diferenciados por su ámbito de aplicación dentro o fuera del componente encapsulado.
¿Cómo se visualiza el Shadow DOM en el inspector del navegador?
Para inspeccionar el Shadow DOM, es vital activar la visualización en las herramientas de desarrollo del navegador. Sigue estos pasos para habilitarlo:
Abre el inspector de elementos en las herramientas de desarrollo.
Dirígete a Settings -> Elements.
Activa la opción que permite mostrar el Shadow DOM.
Una vez activada, podrás evaluar los elementos dentro del Shadow DOM de cualquier página, permitiéndote entender mejor su estructura y funcionamiento.
Esta guía debería haberte dado una comprensión clara de las funciones del Shadow DOM y sus aplicaciones. ¡Anímate a implementarlo en tus futuros proyectos para maximizar la eficiencia y mantenimiento de tus estilos CSS!
una pregunta:
no se ve penalizado el SEO cuando se usa shadowDOM? si bien el navegador puede saber cual es el contenido del elemento, lo sabe el indexador de google?
sabe lo que es un h1 si está dentro de un shadowDOM?
Si bien al final el navegador te muestra todo lo que renderizo dándole ver código fuente de la pagina que es lo que va a ver el Bot de Google no se si al programarlo lea los propios componentes.
Uno de los bots de google analiza las webs despues de ejecutarse los javascripts, sino habría muchas páginas que no se indexarian correctamente (sobre todo las páginas web cargadas con ajax).
Un saludo.
Si desean visualizar el código html que se encuentra en los archivos .JS instalen la extensión
**es6-string-html **
para visual studio code y coloque el comentario antes de codear en etiquetas como muestro en la imagen a continuación:
!Imagen
https://i.imgur.com/wbL6voa.png
¿Esto es para que Visual studio Code entienda que es html y te ayude con el auto-complete? 🤔
Gracias por el aporte, ahora es menos tedioso jaja
Shadow DOM
Con esta implementación podremos solucionar los problemas con los estilos css que se rescriben por temas de especificidad.
Generando como un encapsulado, un dom independiente dentro de nuestro dom global, esto que quiere decir que todo lo que coexista en nuestro dom independiente no va existir dentro de nuestro dom global.
classmyElementextendsHTMLElement{constructor(){super();//Venimos al constructor que es donde generamos la instancia de esta api//Agregamos shadow down (API) y lo ponemos en modo openthis.attachShadow({mode:"open"})}getTemplate(){const template =document.createElement('template'); template.innerHTML=`<section><h3>Hola mundo!</h3><div><p> Soy text ejemplo<p></div></section> ${this.getStyles()}
`;return template
}getStyles(){return` <style>
h2{
color:red;
}
</style>
`}render(){//Ahora poder renderizar nuestros templates tenemos que cambiar el contexto//Donde agregamos nuestro template ya que lo estabamos agregando al dom global//Ahora debemos agregarlo en nuestro shadow dom que es otro contexto diferenethis.shadowRoot.appendChild(this.getTemplate().content.cloneNode(true))}connectedCallback(){this.render();}}customElements.define('my-element', myElement);
Es importante activar el shadow dom para poderlo visualmente en nuestro inspector de elementos
.
Gracias por explicar el código.
Gracias, tendré que repasar esta clase para asimilarlo
Shadow DOM
El API de DOM Shadow es un parte clave para esto, proporcionando una forma de enlazar un DOM oculto y separado a un elemento. Este artículo cubre los aspectos básicos para utilizar Shadow DOM.
ㅤ
El Shadow DOM permite adjuntar arboles DOM ocultos a elementos en el árbol DOM regular, este árbol Shadow DOM comienza con un elemento Shadow Root, debajo del cual se puede adjuntar cualquier elemento que desee, de la misma manera que el DOM normal.
ㅤ
Hay algunos conceptos de Shadow DOM que deben ser tomados en cuenta:
Shadow host: El nodo regular del DOM al que es atado el shadow DOM.
Shadow tree: El árbol DOM dentro del shadow DOM.
Shadow boundary: El punto en el que el shadow DOM termina y el DOM regular comienza.
Shadow root: El nodo raíz del árbol Shadow.
ㅤ
Puede adjuntar un shadow root a cualquier elemento utilizamos el método Element.attachShadow (). Éste toma como parámetro un objeto que contiene una propiedad mode con dos posibles valores: open o closed.
ㅤ
open: Significa que puede acceder al shadow DOM usando JavaScript en el contexto principal de la página. Por ejemplo, usando la propiedad
closed: Significa que no se puede acceder al shadow Dom desde afuera, como con la etiqueta video.
Ohhh vale, ya ví en donde se usa el template, ese template que está ahi en el HTML no sirve para nada, el que sí sirve es el que creamos con el createElement jaja.
.
Aun así me sigue causando conflicto que tenemos que usar innerHTML para poder meter el contenido del template xc
No hay problema porque el innerHtml no proviene de un input del usuario y en caso de que viniera de un usuario lo tendrías que limpiar en el backend hay varias funciones para php, JS o phython que sanitizan el código
Hay una forma distinta donde la etiqueta <template> se utiliza, solo que el profesor saltó a otro método y nos dejó así ¯_(ツ)_/¯ Te dejo unos enlaces al respecto
Se puede agregar css desde fuera del componente? Al shadow dom
Hay dos opciones para adicionar CSS desde afuera del componente, una es pasar algunas variables a través de la etiqueta en HTML, así como lo haces con cualquier etiqueta HTML. Obviamente esta opción es muy limitada.
La otra opción es pasar CSS desde JavaScript.
Shadow DOM
Shadow DOM se puede entender como un DOM independiente de el Documento principal, ya que los estilos que escribamos acá no afectan los elementos externos del DOM principal.
.
Esto nos ayuda a tener mejores prácticas con CSS ya que no tendremos un colapso de estilos y evitaremos usar cosas como el !important.
.
Veamos con nuestro ejemplo anterior como implementarlo:
classMyElementextendsHTMLElement{constructor(){super();this.attachShadow({/* Permite interactuar con el componente viendo lo que tenemos
dentro del mismo en una #shadow-root */mode:'open'})}...}
Si vemos ahora nuestro navegador, no veremos el componente, esto debido a que ya esta creado este DOM paralelo, pero en la estructura de HTML en el inspector nos muestra que hay un Shadow root
Entonces ¿Como lo renderizamos? Sencillo, simplemente en el método render debemos cambiar la manera como lo renderizamos en HTML. Esto lo haremos con la propiedad shadowRoot.
classMyElementextendsHTMLElement{constructor(){...})}...render(){/* Le decimos que acceda a la propiedad **shadowRoot** para que
pueda renderizar el contenido del componente */this.shadowRoot.append(this.getTemplate().content.cloneNode(true));}...}
Y si vemos ahora nuestro navegador, nuestro componente estará renderizado 😁.
Tremendo los webComponent, que tipo de usos se te ocurren en un proyecto? Saludos..
Juegos, gracias a webComponents se pueden tener bibliotecas de assets, si sumamos electron y otros proyectos estos juegos no se limitan a el navegador.
Ventas, literalmente cada accion que se relacione con ventas puede ser un webComponent,
Software de Oficina, mediante pequeños componentes y su conexion cada paso de la administración puede ser mas fácil, al ser una webAPP es mas fácil de implementar en una empresa como plataforma como servicio, ademas la conexión entre niveles de administración es mas fácil, y en tiempo real.
Redes sociales, al ver como funcionan los webComponents no paro de pensar el como muchas de estas redes nos estafan, se podría hacer todo tipo de cosas pero las actuales redes sociales te meten en una casa súper limitada.
Los webComponents literalmente son como una caja de herramientas, la información es la materia prima y la comunicación el fin. El resto depende de nuestra experiencia e imaginación.
muy interesante la clase
Apuntes de esta clase:
Shadow DOM
Esto nos ayudará evitar problemas de estilos reescribiendose. Esto se logrará por el encapsulado.
Pensemos en ShadowDOM como un DOM independiente adentro del DOM global, es por esto que los estilos estilos serán independientes en cada uno.
this.attachShadow({mode:'open'});//*Casi siempre todos los componentes tiene que venir en modo abierto.
this.shadowRoot.append(this.getTemplate().content.cloneNode(true));//* Aquí tenemos que especificar `shadowRoot` para que se agregue al DOM y se vea reflejado en el navegador
El tema de especifidad es un tema importante durante la declaracion de estilos y comprenderlo nos ayuda eliminarnos la pregunta de por que se rompio algo
Quiero crear un componente con el tipico menu de hamburguesa.
Creo dos div y una función para el evento onclick.
Funciona sin problemas.
Pero a la que quiero añadir el shadowDoom para no tener problemas con los stilos de css no funciona correctamente:
Si tenéis alguna sugerencia de hacer un componente del típico menú de hamburguesa mejor que mi idea...será bienvenida.
Un saludo a todos y gracias por vuestro tiempo y ayuda.
En este caso no está penalizado el SEO ?, si se indexea correctamente?
Encontré esto ... si averiguas algo más específico... cuéntanos
miren que intente meter otro body dentro del componente para probar el aislamiento del que nos provee template.... i no funciono =( es decir, el codigo corre pero no hay 2 etiquetas body en el dom, realmente lo intente en mi codigo pero en el doom que muestra el inspector de elementos la que estaba dentro del component desaparecio =(
Personalmente no me gusta usar el innerHTML (al inicio me gustaba porque era mas facil), ahora prefiero usar las herramientas del DOM asi que usandolas el codigo quedaria algo asi:
Para crear un componente personalizado en JavaScript, primero debes definir una clase que extienda la clase HTMLElement. Esta clase representa el nuevo elemento HTML personalizado.
classMyElementextendsHTMLElement{// ...}
Constructor
El constructor se llama cuando se crea una instancia del elemento personalizado. Puedes utilizarlo para realizar cualquier configuración necesaria, como adjuntar un shadow DOM.
constructor(){super();// Llamada al constructor de la clase basethis.attachShadow({mode:"open"});// Adjuntar shadow DOM}
Shadow DOM
El Shadow DOM es una característica de HTML que permite adjuntar un DOM separado y encapsulado a un elemento personalizado. Para crear un Shadow DOM, se utiliza el método attachShadow(), que permite encapsular la estructura del DOM y los estilos CSS, previniendo conflictos y manteniendo mayor claridad en el código.
this.attachShadow({mode:"open"});
Generación de contenido
Para generar el contenido de un elemento personalizado, puedes crear una plantilla de HTML y utilizarla para generar el shadow DOM.
getTemplate(){const template =document.createElement('template'); template.innerHTML=`<section><h2class="title">Soy un título</h3><div><p>Soy un párrafo</p></div></section> ${this.getStyles()}
`;return template;}
En este ejemplo, la función getTemplate() genera una plantilla que incluye un título h2 y un párrafo p. La función getStyles() se llama para incluir estilos personalizados.
.
Estilos personalizados
Puedes incluir estilos personalizados en un elemento personalizado utilizando el método getStyles(). Este método retorna un string con un bloque de estilos CSS que se incluirá en la plantilla de HTML.
La función render() llama al método append() en el shadow root del elemento personalizado para agregar el contenido generado por getTemplate() al árbol DOM.
.
Conexión al DOM
La función connectedCallback() se llama cuando el elemento personalizado se agrega al árbol DOM. Puedes utilizar esta función para realizar cualquier configuración adicional, como renderizar el contenido.
connectedCallback(){this.render();}
En este ejemplo, la función connectedCallback() llama a la función render() para renderizar el contenido del elemento personalizado.
.
Definición del elemento personalizado
Finalmente, debes definir el nuevo elemento personalizado utilizando el método customElements.define(). Esto te permite utilizar el elemento en tu página web.
customElements.define('my-element',MyElement);
En este ejemplo, el nombre del elemento personalizado es my-element y la clase que lo define es MyElement.
.
Uso del elemento personalizado
Una vez que has definido tu elemento personalizado, puedes utilizarlo en cualquier página web. Para hacerlo, simplemente agrega el nuevo elemento personalizado a tu HTML como cualquier otro elemento HTML.