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.
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.
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.
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.
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:
- CSS Wrapped 2023
- :has(): El selector de familia
- Demostraciones :has()
- ¿Quieres informar un error o solicitar una función nueva? Queremos conocer tu opinión.
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.