> Manuales > Manual de Web Components

El selector :host. está incorporado en el estándar Web Components para aplicar estilos a la etiqueta host de un custom element, cuando el CSS lo definimos desde el Shadow DOM del componente.

Selector :host de CSS

En este artículo explicaremos el selector :host de CSS, un selector que quizás no conozcas pero que está disponible desde hace tiempo para aplicar estilos a las etiquetas host, también llamadas etiquetas raíz del componente.

Qué es :host

El selector :host en CSS es utilizado en el contexto de los Web Components, y específicamente en relación con los Custom Elements y el Shadow DOM. Este selector permite aplicar estilos CSS directamente al elemento host (la instancia del custom element en sí) desde dentro de su propio Shadow DOM.

Por si no conoces estos términos, Web Components es un estándar Javascript que permite la creación de componentes reutilizables y encapsulados para la web. Para ello usa varias especificaciones de la W3C como Custom Elements y Shadow DOM. Para conocer todos estos conceptos te recomendamos leer el Manual de Web Components.

Dicho de otro modo, si estás aplicando CSS en el Shadow DOM de un componente, usarás :host para referirte al elemento que engloba todo el componente en sí.

Por qué es importante el Selector :host

Cuando estás definiendo un componente es muy sencillo aplicar estilos CSS a los elementos que están dentro de la vista del componente. Nos explicamos, imaginemos que es un componente que muestra la hora y queremos definir estilos a las horas o los minutos.

Ese componente se podría llamar:

<dw-clock></dw-clock>

Cuando se muestre ese componente se vería algo como 22:55:36, es decir, las horas, los minutos y los segundos. Seguramente tendremos un template para implementar el reloj y cada uno de los bloques (horas, minutos, segundos) estarán dentro de un <span> o quizás un <div>. No existe problema al definir el estilo para esos bloques en particular porque está dentro del template del componente.

Particularmente, con Shadow DOM, solamente puedes aplicar estilos a los elementos del template del componente desde dentro del propio componente así que esos estilos CSS definidos en el Shadow DOM tenemos la garantía de que no se mezclarán con los estilos globales de la página web, ni desde dentro hacia afuera no desde afuera hacia adentro. Por supuesto, a no ser que queramos, porque existen mecanismos para conseguir penetrar con el CSS en el Shadow DOM, como las custom properties o las CSS Parts.

Pero, ¿qué pasaría si se quiere aplicar estilos a la etiqueta del componente?, es decir, a la etiqueta host <dw-clock>. Desde dentro del componente puedes aplicar estilos al template del componente pero no a la etiqueta que engloba ese componente. Para solucionar esta situación es para lo que usamos el selector :host.

Ejemplo básico de uso de :host

Veamos el siguiente código de ejemplo.

/* Estilos CSS colocados dentro del template del componente que se insertaría en el Shadow DOM */
:host {
  display: block;
  background-color: orange;
  color: #fff;
}

Si quieres saber cómo se insertaría el template en el componente, puedes leer el artículo del Shadow DOM.

En este caso, cualquier instancia del componente web que use este Shadow DOM tendrá un fondo de color orange, texto blanco y será un elemento de bloque. Es como si dentro del componente estuviéramos aplicando estilos a ``, ya que los estilos definidos con :host se aplican al propio tag que escribimos para usar el componente.

Combinar :host con otros selectores

El selector :host también puede ser usado de manera conjunta con otros selectores, como los de pseudo-clase y pseudo-elemento, selectores de atributo, etc. De esta forma conseguimos una selección más específica en la que el CSS declarado afectará al elemento host pero solamente en algunas circunstancias.

Por ejemplo veamos esta declaración de estilos:

:host(:hover) {
  background-color: brown;
}

Con este estilo, el fondo del componente se cambiará a brown cuando el usuario pase el cursor sobre la etiqueta host.

Ahora veamos otro ejemplo de combinación de selectores.

:host([active]) {
  color: yellow;
}

De esta manera le estamos aplicando un estilo CSS al componente cuando éste tiene el atributo "active".

<dw-clock active></dw-clock>

Esta es una estupenda manera de permitir que las personas que van a usar tu componente puedan personalizar desde fuera los custom elements. Por ejemplo podríamos tener un botón que tenga varios estilos para distintos estados y los podríamos usar así <dw-button danger>Borrar</dw-button>, <dw-button small>Refrescar</dw-button>.

Podemos llegar un poco más lejos y conseguir aplicar estilos a los elementos del Shadow DOM del componente cuando se cumpla cierta condición en la etiqueta Host.

:host([format24h]) #am-pm {
  display: none;
}

Por ejemplo, con el estilo anterior si el custom element tiene un atributo que se llama "format24", sea el valor que sea, se aplicará un estilo display: none al elemento con identificador "am-pm".

:host en los frameworks

Como has visto, el selector :host forma parte del estándar de Web Components y por lo tanto está disponible en los navegadores sin necesidad de usar ninguna librería. En otras palabras, es algo que nos aporta el propio CSS y no tiene que ver con los frameworks con los que estamos trabajando. Sin embargo, no todos los frameworks sacan partido de esta funcionalidad, por lo que no siempre lo vamos a poder usar si estamos programando en alguna abstracción de componentes que no sea compatible con Web Components.

:host en Angular

Angular es uno de los frameworks que sacan partido al estándar de los Web Components y mediante los cuales es posible usar también :host.

Al generar un componente con Angular, en las declaraciones de estilos CSS podemos usar :host como hemos descrito anteriormente.

:host {
  display: block;
  border: 1px solid red;
  padding: 1rem;
}

Eso hará que el componente actual completo, es decir, la propia etiqueta que engloba a todo el componente, tenga un borde rojo, un display de bloque y un espaciado interno.

Solo hay un detalle importante y es que este selector solo lo podemos usar si un componente está declarado con un valor "encapsulation" igual a ViewEncapsulation.Emulated o ViewEncapsulation.ShadowDom. Si tenemos un ViewEncapsulation.None no funcionará porque no estará aplicando ningún tipo de encapsulación de los estilos del componente.

Cuando definimos un componente en Angular tenemos una propiedad llamada "encapsulation" que se puede especificar de manera opcional en el decorador del componente. La opción predeterminada de este atributo es "ViewEncapsulation.Emulated", que indica que va a hacer una encapsulación del CSS emulada, de modo que se limitan las interferencias no deseadas entre el CSS definido para un componente en particular con el CSS global. Si usamos la configuración ViewEncapsulation.ShadowDom estaremos consiguiendo que Angular use Shadow DOM para el contenido de los componentes. Ambas alternativas evitan interferencias de los estilos locales del componente, pero el Shadow DOM lo hace de manera nativa y es todavía un poco más restrictivo que la encapsulación emulada.

Para que quede más claro, aquí hay un ejemplo de modificación de la propiedad encapsulation en el decorador del componente.

import { Component, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'app-foo',
  templateUrl: './foo.component.html',
  styleUrls: ['./foo.component.css'],
  //encapsulation: ViewEncapsulation.None,
  //encapsulation: ViewEncapsulation.Emulated,
  encapsulation: ViewEncapsulation.ShadowDom,
})
export class FooComponent {

}

:host en Vue o React

Estos dos frameworks no se apoyan en el estándar de Web components por lo que no podemos usar :host.

De todos modos, es posible "emular" el selector :host usando un poco de HTML y CSS. Simplemente tendríamos que crear un contenedor global para todo el template del componente y luego aplicar el estilo a ese contenedor.

Es decir, en principio no podemos alcanzar el elemento host pero sí somos capaces de colocar un contenedor dentro del componente y estilizarlo con estilos comunes en el template del componente. No es la mejor alternativa porque estamos generando HTML innecesario pero es perfectamente viable.

Miguel Angel Alvarez

Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...

Manual