Estudos de caso de :has()

Swetha Gopalakrishnan
Swetha Gopalakrishnan
Saurabh Rajpal
Saurabh Rajpal

O CSS não tinha uma maneira de selecionar diretamente um elemento pai com base nos filhos. Esse é um dos principais pedidos dos desenvolvedores há muitos anos. O seletor :has(), que agora tem suporte de todos os principais navegadores, resolve esse problema. Antes :has(), você normalmente encadenava seletores longos ou adicionava classes para ganchos de estilo. Agora é possível definir estilos com base na relação de um elemento com os descendentes dele. Leia mais sobre o seletor :has() em CSS Wrapped 2023 e 5 snippets de CSS que todo desenvolvedor de front-end precisa conhecer.

Embora esse seletor pareça pequeno, ele pode permitir um grande número de casos de uso. Este artigo mostra alguns casos de uso que as empresas de e-commerce desbloquearam com o seletor :has().

:has() faz parte da Linha de base recém-disponível.

Browser Support

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

Source

Confira a série completa (em inglês) da qual este artigo faz parte, que discute como as empresas de e-commerce melhoraram os sites usando novos recursos de CSS e interface.

Policybazaar

Com o seletor :has(), foi possível eliminar a validação baseada em JavaScript da seleção do usuário e substituí-la por uma solução CSS que funciona perfeitamente para nós com a mesma experiência de antes.—Aman Soni, líder de tecnologia, Policybazaar

A equipe de investimentos da Policybazaar aplicou habilmente o seletor :has() para fornecer uma indicação visual clara aos usuários que estão comparando planos. A imagem a seguir mostra dois tipos de planos na interface de comparação (amarelo e azul). Cada plano só pode ser comparado com o próprio tipo. Ao usar :has(), quando um usuário seleciona um tipo de plano, o outro tipo não pode ser selecionado.

Implementação de :has() para estilizar o elemento pai e os filhos dele para criar uma funcionalidade de seleção vinculada a uma categoria.

Código

O :has() dá acesso aos elementos pai de estilo e aos filhos deles. O código abaixo verifica se um contêiner pai tem uma classe .disabled-group definida. Se isso acontecer, o card ficará esmaecido, e o botão "Adicionar" não reagirá a cliques ao definir pointer-events como 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); } 

A equipe de saúde da Policybazaar implementou um caso de uso um pouco diferente. Eles têm um teste inline para o usuário e usam :has() para verificar o status da caixa de seleção da pergunta e saber se ela foi respondida. Se for, uma animação será aplicada para fazer a transição para a próxima pergunta.

health.policybazaar.com/

Código

No exemplo de comparação de planos, :has() foi usado para verificar a presença de uma classe. Também é possível verificar o estado de um elemento de entrada, como uma caixa de seleção, usando :has(input:checked). No recurso visual que mostra o teste, cada pergunta no banner roxo é uma caixa de seleção. O Policybazaar verifica se a pergunta foi respondida usando :has(input:checked) e, se sim, aciona uma animação usando animation: quesSlideOut 0.3s 0.3s linear forwards para deslizar até a próxima pergunta. Confira como isso funciona no código a seguir.

.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

A Tokopedia usou :has() para criar uma imagem de sobreposição se a miniatura do produto contiver um vídeo. Se a miniatura do produto contiver uma classe .playIcon, uma sobreposição CSS será adicionada. Aqui, o seletor :has() é usado com o seletor de aninhamento & na classe .thumbnailWrapper principal, que se aplica a todas as miniaturas. Isso cria um CSS mais modular e legível.

Captura de tela da página Tokopedia antes e depois do uso do seletor "has".
Antes e depois de usar o :has().

Código

O código a seguir usa os seletores e combinatores de CSS (& e >) e aninhamento com :has() para definir o estilo da miniatura. Para navegadores que não oferecem suporte, a regra de classe CSS adicional regular é usada como substituto. A regra @supports selector(:has(*)) também é usada para verificar o suporte do navegador. Portanto, a experiência geral é a mesma em todas as versões do 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;     }   } `; 

Considerações ao usar :has()

Combine :has() com outros seletores para criar uma condição mais complexa. Confira alguns exemplos em has() o seletor de família.

Recursos:

Confira os outros artigos desta série que falam sobre como as empresas de e-commerce se beneficiaram com o uso de novos recursos de CSS e interface, como animações com base no rolagem, transições de visualização, popovers e consultas de contêiner.