10.2. Selektory rodzeństwa: sąsiadującego (+) i ogólnego (~)
Wprowadzenie: Wybieranie elementów obok siebie
Oprócz relacji rodzic-dziecko/potomek, CSS pozwala również wybierać elementy na podstawie ich relacji z **rodzeństwem** (siblings) - elementami, które mają tego samego rodzica i znajdują się na tym samym poziomie w drzewie DOM.
Istnieją dwa główne selektory rodzeństwa: selektor sąsiadującego rodzeństwa (+
) i selektor ogólnego rodzeństwa (~
).
Selektor sąsiadującego rodzeństwa (+)
Selektor sąsiadującego rodzeństwa, zapisywany jako znak plusa (+
) między dwoma selektorami (np. h2 + p
), wybiera element pasujący do drugiego selektora (p
), który znajduje się **bezpośrednio po** elemencie pasującym do pierwszego selektora (h2
) i **mają tego samego rodzica**.
Innymi słowy, wybiera tylko **pierwszego** brata/siostrę danego typu, który następuje bezpośrednio po określonym elemencie.
<div class="article">
<h2>Nagłówek 1</h2>
<p>Paragraf 1 (bezpośrednio po h2)</p>
<p>Paragraf 2 (nie bezpośrednio po h2)</p>
<h2>Nagłówek 2</h2>
<div>Inny element</div>
<p>Paragraf 3 (nie bezpośrednio po h2)</p>
</div>
/* Wybierz paragraf (p), który znajduje się BEZPOŚREDNIO po nagłówku h2 */
h2 + p {
color: green;
font-style: italic;
}
W powyższym przykładzie, tylko **Paragraf 1** zostanie wybrany przez selektor h2 + p
, ponieważ jest to pierwszy paragraf znajdujący się bezpośrednio po pierwszym h2
. Paragraf 2 nie jest bezpośrednio po h2
, a Paragraf 3 jest oddzielony od drugiego h2
przez element div
.
Selektor +
jest przydatny do stylizowania elementów w specyficzny sposób tylko wtedy, gdy poprzedza je określony element, np. dodanie marginesu górnego do paragrafu, który następuje po nagłówku.
Selektor ogólnego rodzeństwa (~)
Selektor ogólnego rodzeństwa, zapisywany jako tylda (~
) między dwoma selektorami (np. h2 ~ p
), wybiera **wszystkie** elementy pasujące do drugiego selektora (p
), które znajdują się **po** elemencie pasującym do pierwszego selektora (h2
) i **mają tego samego rodzica**.
W przeciwieństwie do +
, selektor ~
wybiera wszystkich braci/siostry danego typu, którzy występują później, a nie tylko tego bezpośrednio następującego.
<!-- Użyjemy tego samego HTML co poprzednio -->
<div class="article">
<h2>Nagłówek 1</h2>
<p>Paragraf 1 (po h2)</p>
<p>Paragraf 2 (po h2)</p>
<h2>Nagłówek 2</h2>
<div>Inny element</div>
<p>Paragraf 3 (po h2)</p>
</div>
/* Wybierz WSZYSTKIE paragrafy (p), które znajdują się PO nagłówku h2 */
/* i mają tego samego rodzica */
h2 ~ p {
text-decoration: underline;
color: purple;
}
W powyższym przykładzie, selektor h2 ~ p
wybierze **Paragrafy 1, 2 i 3**. Dlaczego?
- Paragraf 1 i 2 znajdują się po pierwszym
h2
i mają tego samego rodzica (div.article
). - Paragraf 3 znajduje się po drugim
h2
i ma tego samego rodzica (div.article
).
Selektor ~
jest mniej restrykcyjny niż +
i pozwala stylizować wszystkie elementy rodzeństwa występujące po określonym elemencie.
Ważne uwagi
- Oba selektory (
+
i~
) biorą pod uwagę tylko rodzeństwo, które występuje **po** pierwszym elemencie w kodzie HTML. Nie wybierają rodzeństwa, które znajduje się wcześniej. - Elementy muszą mieć **tego samego bezpośredniego rodzica**, aby były uważane za rodzeństwo.
Zadania praktyczne
Zadanie 1 (z rozwiązaniem)
Stwórz strukturę HTML z kilkoma paragrafami p
i obrazkiem img
między nimi. Użyj selektora +
, aby nadać specjalny styl (np. większy margines górny) tylko paragrafowi, który znajduje się bezpośrednio po obrazku.
Rozwiązanie:
HTML:
<div>
<p>Paragraf przed obrazkiem.</p>
<img src="obrazek.jpg" alt="Przykładowy obrazek">
<p>Ten paragraf jest bezpośrednio po obrazku.</p>
<p>Kolejny paragraf.</p>
</div>
CSS:
img + p { /* Wybiera paragraf bezpośrednio po img */
margin-top: 30px; /* Dodaj większy odstęp górny */
font-weight: bold;
}
Efekt: Tylko paragraf "Ten paragraf jest bezpośrednio po obrazku." będzie miał większy margines górny i pogrubioną czcionkę.
Zadanie 2 (do samodzielnego wykonania)
Stwórz listę definicji (dl
, dt
, dd
). Użyj selektora +
, aby nadać wcięcie (margin-left
) tylko elementom dd
, które znajdują się bezpośrednio po dt
.
Zadanie 3 (do samodzielnego wykonania)
Stwórz formularz z etykietami (label
) i polami tekstowymi (input type="text"
). Użyj selektora ~
, aby ukryć (display: none;
) wszystkie etykiety, które znajdują się po polu input z klasą .hide-following-labels
.
FAQ - Najczęściej zadawane pytania
Czy selektory rodzeństwa działają wstecz?
Nie, zarówno selektor sąsiadujący (+
), jak i ogólny (~
) działają tylko "w przód" w drzewie DOM. Wybierają rodzeństwo, które pojawia się **po** elemencie odniesienia w kodzie HTML. Nie ma w CSS selektora, który wybierałby poprzedzające rodzeństwo.
Co jeśli między elementami jest biały znak (np. nowa linia)?
Białe znaki (spacje, tabulatory, nowe linie) w kodzie HTML między elementami rodzeństwa nie mają wpływu na działanie selektorów +
i ~
. Liczy się tylko kolejność i relacja elementów w drzewie DOM.
Czy mogę łączyć selektory rodzeństwa z innymi?
Tak. Można je łączyć z selektorami typu, klas, ID, atrybutów, pseudoklas itp. Na przykład: h2.section-title + p.intro
wybierze paragraf z klasą .intro
, który jest bezpośrednio po nagłówku h2
z klasą .section-title
.
Do czego praktycznie przydaje się selektor ~
?
Selektor ogólnego rodzeństwa (~
) jest przydatny, gdy chcemy zastosować styl do grupy elementów następujących po pewnym elemencie, ale niekoniecznie bezpośrednio. Przykładem może być zmiana wyglądu wszystkich elementów formularza po zaznaczeniu checkboxa (tzw. "checkbox hack") lub stylizowanie wszystkich paragrafów po nagłówku sekcji.