Tilbage til Fundamentals

3. semester / Tema 13C: Frontend Design

:has() i praksis

Relationelle selectors og quantity queries med :has().

Se undervisningsslides

Relevante links

Hvad er :has()

:has() kaldes ofte en relationel pseudo-klasse: du kan style et element ud fra hvad det indeholder eller hvad der ligger ved siden af det.

Det gør det muligt at flytte logik op på parent-niveau i stedet for at style kun det inderste element.

Det åbner op for helt nye måder at tænke på i forhold til styling baseret på indhold og struktur.

Undersøg relationerne

Gæt hvilke bokse der rammes, og afprøv derefter div:has(h2), div:has(h2, h3) og div:has(h2):has(h3). Brug fx outline-color: deeppink til at vise resultatet.

Komma betyder her enten/eller, mens to :has() efter hinanden kræver begge betingelser. Det er stadig div, der vælges; overskrifterne bruges som betingelse.

Sammenlign også p + figure med p:has(+ figure): den første vælger figuren, den anden afsnittet umiddelbart før figuren. De skal være søskende.

Patterns og øvelser

Der er mange patterns du kan bygge med :has(). Her er nogle eksempler:

.card:has(img)

Vælger .card, hvis der findes et img indeni.

.card:not(:has(img))

Vælger .card, hvis den ikke har et billede.

.form:has(:focus)

Vælger .form, hvis et felt indeni har fokus.

.option:has(input:checked)

Vælger .option, hvis den indeholder et input der er :checked.

.list:has(> :nth-child(4))

Vælger .list, hvis der er mindst 4 direkte element-børn.

.item:has(+ .item)

Vælger .item, hvis der findes en søskende-.item lige efter.

.item:has(~ .item)

Vælger .item, hvis der findes en søskende-.item senere i DOM'en.

.card:has(img, video)

Vælger .card, hvis den har enten img eller video indeni.

.card:has(img):has(video)

Vælger .card, hvis den har både img og video indeni.

:has() er altså særligt nyttig, når du har brug for at style baseret på indholdets tilstedeværelse, tilstand eller mængde. Det kan være:

Test dig selv

  1. Knappen med et ikon skal have helt runde hjørner og have reduceret padding på højre side til 0.675rem.
  1. Giv kun det udsolgte produkt en outline ved hjælp af CSS :has().
  1. .container skal have et grid med to kolonner, hvis der er et <figure>-element. Hvis der ikke er et <figure>-element, skal .container have en max-width40ch og være centreret.
  1. Giv p en grøn farve, hvis den kommer før figure, og rød farve, hvis den kommer efter figure.

Bonus: display: contents

display: contents fjerner elementets egen boks fra layoutet, men fjerner ikke elementet fra DOM’en. Dets børn kan derfor deltage i det omgivende layout, mens selectors stadig følger den oprindelige HTML-struktur.

p:has(img) {
display: contents;
}

Mønstret fra slides kan være nyttigt for wrappers omkring billeder. Undersøg forskellen mellem DOM-træet og de bokse, browseren tegner. Det er bonusstof; et godt første mål er at forstå de almindelige relationer med :has().

Bonus: Quantity queries

.list:has(> :nth-child(4)) {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
}

Her er betingelsen mindst fire direkte element-børn. Uden > kunne fjerde barn i en nested struktur også udløse reglen. Test ved at tilføje indhold inde i det første kort uden at øge antallet af kort.

En mere sammensat selector er .gallery:not(:has(:not(img))). Den matcher, når galleriet ikke har efterkommerelementer, der er andet end img. Den undersøger ikke tekstnoder og matcher også et tomt galleri. Den betyder derfor ikke i almindelighed “indeholder kun billeder og intet andet”. Brug den kun, når du kan forklare de konkrete matches i din HTML.