Casos de éxito de :has()

Swetha Gopalakrishnan
Swetha Gopalakrishnan
Saurabh Rajpal
Saurabh Rajpal

CSS no tiene una forma de seleccionar directamente un elemento superior según sus elementos secundarios. Esta ha sido una de las principales solicitudes de los desarrolladores durante muchos años. El selector :has(), que ahora es compatible con todos los navegadores principales, resuelve este problema. Antes de :has(), a menudo, se encadenaban selectores largos o se agregaban clases para hooks de diseño. Ahora puedes aplicar diseño según la relación de un elemento con sus descendientes. Obtén más información sobre el selector :has() en CSS Wrapped 2023 y 5 fragmentos de CSS que todo desarrollador de frontend debe conocer.

Aunque este selector parece pequeño, puede habilitar una gran cantidad de casos de uso. En este artículo, se muestran algunos casos de uso que las empresas de comercio electrónico desbloquearon con el selector :has().

:has() forma parte de Baseline Newly Available.

Navegadores compatibles

  • Chrome: 105.
  • Edge: 105.
  • Firefox: 121
  • Safari: 15.4.

Origen

Consulta la serie completa de la que forma parte este artículo, en la que se analiza cómo las empresas de comercio electrónico mejoraron sus sitios web con nuevas funciones de CSS y IU.

Policybazaar

Con el selector :has(), pudimos eliminar la validación basada en JavaScript de la selección del usuario y reemplazarla por una solución de CSS que funciona sin problemas con la misma experiencia que antes. Aman Soni, líder técnico, Policybazaar

El equipo de inversiones de Policybazaar aplicó de forma inteligente el selector :has() para proporcionar una indicación visual clara a los usuarios que comparan planes. En la siguiente imagen, se muestran dos tipos de planes dentro de la IU de comparación (amarillo y azul). Cada plan solo se puede comparar con su propio tipo. Cuando se usa :has(), cuando un usuario selecciona un tipo de plan, no se puede seleccionar el otro.

Implementa :has() para aplicar diseño al elemento superior y a sus elementos secundarios para crear una funcionalidad de selección vinculada a categorías.

Código

:has() te permite acceder a elementos superiores de diseño y sus elementos secundarios. El siguiente código verifica si un contenedor superior tiene configurada una clase .disabled-group. Si es así, la tarjeta se inhabilita y se impide que el botón "Agregar" reaccione a los clics si se establece pointer-events en none.

.plan-group-container:has(.disabled-group) {
  opacity: 0.5;
  filter: grayscale(100%);
}

.plan-group-container:has(.disabled-section) .button {
  pointer-events: none;
  border-color: #B5B5B5;
  color: var(--text-primary-38-color);
  background: var(--input-border-color);
}

El equipo de salud de Policybazaar implementó un caso de uso ligeramente diferente. Tiene un cuestionario intercalado para el usuario y usa :has() para verificar el estado de la casilla de verificación de la pregunta y ver si se respondió. Si es así, se aplica una animación para pasar a la siguiente pregunta.

health.policybazaar.com/

Código

En el ejemplo de comparación de planes, se usó :has() para verificar la presencia de una clase. También puedes verificar el estado de un elemento de entrada, como una casilla de verificación, con :has(input:checked). En la imagen que muestra el cuestionario, cada pregunta del banner púrpura es una casilla de verificación. Policybazaar verifica si se respondió la pregunta con :has(input:checked) y, de ser así, activa una animación con animation: quesSlideOut 0.3s 0.3s linear forwards para deslizarte a la siguiente pregunta. Consulta cómo funciona en el siguiente código.

.segment_banner__wrap__questions {
 position: relative;
 animation: quesSlideIn 0.3s linear forwards;
}

.segment_banner__wrap__questions:has(input:checked) {
 animation: quesSlideOut 0.3s 0.3s linear forwards;
}


@keyframes quesSlideIn {
 from {
   transform: translateX(50px);
   opacity: 0;
 }
 to {
   transform: translateX(0px);
   opacity: 1;
 }
}

@keyframes quesSlideOut {
 from {
   transform: translateX(0px);
   opacity: 1;
 }
 to {
   transform: translateX(-50px);
   opacity: 0;
 }
}

Tokopedia

Tokopedia usó :has() para crear una imagen superpuesta si la miniatura del producto contiene un video. Si la miniatura del producto contiene una clase .playIcon, se agrega una superposición de CSS. Aquí, el selector :has() se usa junto con el selector de anidación & dentro de la clase .thumbnailWrapper general que se aplica a todas las miniaturas. Esto crea un CSS más modular y legible.

Captura de pantalla de la página de Tokopedia antes y después de usar el selector has.
Antes y después de usar :has().

Código

En el siguiente código, se usan los selectores y combinaciones de CSS (& y >) y se anidan con :has() para definir el estilo de la miniatura. Para los navegadores que no son compatibles, se usa la regla de clase CSS adicional normal como resguardo. La regla @supports selector(:has(*)) también se usa para verificar la compatibilidad con el navegador. Por lo tanto, la experiencia general es la misma en todas las versiones del navegador.

export const thumbnailWrapper = css`
  padding: 0;
  margin-right: 7px;
  border: none;
  outline: none;
  background: transparent;

  > div {
    width: 64px;
    height: 64px;
    overflow: hidden;
    cursor: pointer;
    border-color: ;
    position: relative;
    border: 2px solid ${NN0};
    border-radius: 8px;
    transition: border-color 0.25s;

    &.active {
      border-color: ${GN500};
    }

    @supports selector(:has(*)) {
      &:has(.playIcon) {
        &::after {
          content: '';
          display: block;
          background: rgba(0, 0, 0, 0.2);
          position: absolute;
          top: 0;
          left: 0;
          right: 0;
          bottom: 0;
        }
      }
    }

    & > .playIcon {
      position: absolute;
      top: 25%;
      left: 25%;
      width: 50%;
      height: 50%;
      text-align: center;
      z-index: 1;
    }
  }
`;

Aspectos que debes tener en cuenta cuando usas :has()

Combina :has() con otros selectores para crear una condición más compleja. Consulta algunos ejemplos en tiene() el selector de familia.

Recursos:

Explora los otros artículos de esta serie en los que se explica cómo las empresas de comercio electrónico se beneficiaron del uso de nuevas funciones de CSS y IU, como animaciones impulsadas por el desplazamiento, transiciones de vista, consultas de popover y contenedor.