Relační selektor :has – zdaleka ne jen selektor rodiče

Publikováno: 27.4.2022

Funkční selektor :has() můžeme použít jako selektor rodiče, tedy vybrat rodičovské prvky, obsahující potomky určitého typu. Podívejme se na něj detailně.

Celý článek

Text vyšel původně na webu autora.

:has() je funkční selektor, který můžeme mimojiné použít jako selektor rodiče, tedy vybrat rodičovské prvky, obsahující potomky určitého typu:

a:has(img) { }

Tento selektor cílí na všechny odkazy (a), které mají v DOMu jako potomka obrázek (img).

Je to selektor rodiče. Ale taky nemusí být.

Selektor :has je podporován v Safari a to od verze 15.4 z března 2022. Fanfáry prosím!

Chrome oznámil, že od verze 101, takže v nejbližším měsíci, bude selektor podporovat zkušebně s možností zapnout jej pod nastavením vlaječek (flags).

Nejen selektor rodiče

Selektor :has je součástí návrhu specifikace W3C Selectors Level 4. Vzbudil velkou pozornost, protože jednou z možností jeho použití je právě selektor rodiče, což je v CSS už asi dvacet let něco jako banány za komunistů. Lidé to strašně moc chtějí, stáli by na to fronty, ono se to občas někde objeví, ale zpravidla je to planý poplach.

Jenže :has ve skutečnosti selektor rodiče není. Doslovně, přesně podle specifikace, jde o relační pseudotřídu (Relational Pseudo-class). Relační proto, že do závorek můžete napsat jakýkoliv relativní selektor, se vztahem k selektoru před dvojtečkou:

/* Vybere <a>, jejichž přímým potomkem je <img>: */
a:has(> img) { }

/* Vybere všechny <section>, které obsahují <h1> nebo <h2>: */
section:has(h1, h2) { }

/* Vybere všechny <img>, za nimiž následují <figcaption>: */
img:has(+ figcaption)

Všimněte si posledního případu. Vybírá prvního z bezprostředně navazujících sourozenců v DOMu. Tady o selektoru rodiče nemůže být řeč. Navíc je to užitečné a skoro stejně nedostatkové jako ty banány za komunistů. Nebo jako selektor rodiče v CSS.

Ukázka se selektorem rodiče

Podívejme se na následující CodePen. Jsou v něm dva prvky .box. Jeden obsahuje obrázek a jeden pouze text:

<p class="box">
  Lorem ipsum…
</p>  

<p class="box">
  <img />
  <br>
  Quam doloremque…
</p>

Relační pseudotřídou :has se pak snažím zacílit boxík s obrázkem:

.box:has(img) {
  border: 5px #30680d dotted;
}

Výsledek uvidíte níže. Jen pozor, v dubnu 2022 to bude fungovat jen v Safari 15.4:

Ukázka se selektorem předchozího sourozence

V tomto demíčku se zaměříme na stylování prvků v textu, za nimiž následují jiné specifické prvky. Máme dva nadpisy, za jedním následuje odstavec, za druhým seznam položek:

<h2>Lorem ipsum, dolor sit amet</h2>
<p>
  Lorem…
</p>  
<h2>Quam doloremque…</h2>
<ul>
  <li>
    Lorem…
  </li>
</ul>

Pokud bychom ten druhý chtěli stylovat jinak, opět nemusíme složitě přidávat třídu, ale použít relační pseudotřídu :has:

h2:has(+ul) {
  border-bottom: 5px #30680d dotted;
  margin-bottom: 2rem;
}

Ani tuto ukázku neuvidíte plně funkční jinde než v Safari 15.4:

Další možnosti, občas dechberoucí

Když jsem procházel, co se selektorem :has vykouzlili jiní autoři, občas mě srdíčko poskočilo radostí. O jejich nápady se s vámi musím podělit, v tomto případě hlavně o nápady Matthiase Otta.

/* Vybere formulář, ve kterém je zatržené zatržítko: */
form:has(input[type="checkbox"]:checked) { }

/* Vybere formulář, kde jsou dvě zatržená zatržítka: */
form:has(input[type="checkbox"]:checked ~ input[type="checkbox"]:checked) { }

/* Vybere <img> ve <figure>, za nímž následuje <figcaption>: */
figure img:has(+ figcaption) { }

/* Vybere kontejner layoutu, v němž jsou dvě položky: */
.grid:has(:nth-child(2):last-child) { }

Všimněte si hlavně té poslední možnosti. Rozložení v CSS layoutu upravujeme počítáním prvků uvnitř. Jde o aplikaci takzvaných quantity queries, které už před lety popsal Heydon Pickering.

Podpora v prohlížečích

Stav podpory :has k dubnu 2022 je tento:

  • Safari nový selektor plně podporuje od poslední verze, tzn. 15.4.
  • Chrome si s :has pohrává a od verze 101 bude možné zkoušet za vlaječkou.
  • Firefox zatím nevysílá signály, že by měl podporu v nejbližší době v plánu. To nás mrzí, že… ?

V tuto chvíli by, kvůli zdaleka ne plné podpoře, asi nebylo vhodné selektor :has začít používat na veřejných webech.

Pokud byste to přes to chtěli zkusit, zmiňuji zde nápad testování podpory selektoru s možností vytvoření alternativního řešení pro přohlížeče, které :has neumí. Prostě využijeme dotaz na podporu @supports:

@supports selector(:has(*)) {
  /* Kód pro prohlížeče, které podporují :has */
}

Existují samozřejmě také javascriptové polyfilly, které funkci :has nahrazují, ale neodkážu na ně, protože z pohledu výkonu považuji nahrazování takto nízkoúrovňové funkce prohlížeče za nepěknou prasárnu.

Nevím jak vy, ale já se na podporu :has v prohlížečích docela těším.

ebook-vdcss3-prebal-final

Kniha „Vzhůru do (responzivního) designu“

Kompletní průvodce návrhem a implementací responzivních uživatelských rozhraní v e-booku a knize. Více informací.

Nahoru
Tento web používá k poskytování služeb a analýze návštěvnosti soubory cookie. Používáním tohoto webu s tímto souhlasíte. Další informace