Aguarde...

14 de julho de 2022

As possibilidades desbloqueadas do seletor :has()

As possibilidades desbloqueadas do seletor :has()

Eu estava ouvindo, onde Eric Meyer fala sobre todas as novas possibilidades (muitas ainda não descobertas) que o :has()seletor desbloqueia, incluindo o que ele chama de “marcação sem classes”. Aqui é Eric:

Sempre que você estiver em uma situação em que você estiver tipo, “Ah droga, eu tenho que classificar o pai dois ou três níveis acima… para que eu possa estilizá-lo diferente”, [com :has()] isso desaparece.

Isso é incrível quanto mais você pensa sobre isso. Vamos pensar um pouco mais.

Tradicionalmente, eu dependia do JavaScript para adicionar e remover classes por questões de estilo. Algo aconteceu no DOM? Adicione uma classe aqui e ali para que eu possa estilizar diferentes elementos em toda a árvore. Mas com :has()isso vai embora. Não há mais dependência de JavaScript (ou duplicação de estado na forma de uma classe, mais sobre isso em um momento).

Uma ótima ilustração dessa ideia é o uso da :checkedpseudo-classe . Hoje, você pode estilizar algo diferente na interface do usuário, dependendo de uma caixa de seleção estar marcada. Para fazer isso com CSS puro, você precisa estruturar sua marcação de forma que possa direcionar elementos com CSS com base nesse estado. Por exemplo, alavancando o seletor de irmãos adjacentes.

<form>
  <input type="checkbox">
  <label>Make this red when checked</label>
</form>

<style>
  [type="checkbox"]:checked + label { color: red }
</style>

Você praticamente tem que escrever sua marcação dessa maneira. Se, por exemplo, você aninhar o <input>rótulo dentro do rótulo, não há como direcionar <label>uma vez que a caixa de seleção esteja marcada, a não ser usar JavaScript para adicionar/remover uma classe mais acima na árvore.

<form>
  <label>
    <input type="checkbox">
    Make this red when checked
  </label>
</form>

<style>
  /* `[type="checkbox"]:checked` can only target siblings
     and sibiling children. Otherwise you’ll have to
     add/remove a class with JS */
  label.checked { color: red }
</style>

<script>
  document.querySelector("[type=checkbox]")
    .addEventListener("change", () => {
      /* code that handles adding/removing `.checked` class */
    })
</sript>

Com :has(), direcionar um elemento em qualquer nível da árvore DOM com base no estado em qualquer outro lugar na árvore DOM se torna incrivelmente fácil. Isso libera você para estruturar seu HTML na forma mais semântica possível, não devido a alguma restrição de seletores CSS disponíveis.

<form>
  <label>
    <input type="checkbox">
    Make this red when checked
  </label>
</form>
<button>Make this red too!</button>

<style>
  body:has([type="checkbox"]:checked) label,
  body:has([type="checkbox"]:checked) button {
    color: red;
  }
</style>

O que é intrigante sobre isso é como ele começa a se parecer com o React em termos de “re-renderização”. No React, você tem um lugar canônico para o estado e tudo deriva disso. Se o estado mudar, tudo será renderizado novamente — UI=fn(s). Com :has()uma ideia semelhante vem o CSS! Como?

Imagine uma árvore DOM.

No DOM de hoje, se você tem um pedaço de estado em algum lugar da árvore que pode ser controlado pelo usuário, você precisa de JavaScript para escutar as mudanças nesse estado e duplicá-lo na forma de classes em outros lugares da árvore.

Com :has(), você não precisa duplicar esse pedaço de estado na forma de nomes de classe em outro lugar no DOM para obter controle de estilo. Em vez disso, você pode escrever um :has()seletor que o procure em qualquer lugar da árvore.

Como outro exemplo, imagine um controle de preferência de esquema de cores. Você pode colocá-lo em qualquer lugar no DOM e obter controle de estilo em qualquer outro nível do DOM que desejar – sem JavaScript ou classes CSS extras necessárias. Confira este codepen como um exemplo . (É verdade que isso não resolve o estado persistente nas solicitações e tudo mais, mas ilustra essa ideia de marcação sem classe.)

Esta é apenas uma das possibilidades que o :has()seletor desbloqueia. Um seletor irmão anterior é outro. Que outras possibilidades existem? Estou animado!

Postado em Blog
Escreva um comentário