Rodzaje selektorów CSS — klasy, identyfikatory i pseudo-klasy w praktyce | WebMajka

Rodzaje selektorów CSS — klasy, identyfikatory i pseudo-klasy w praktyce | WebMajka

Selektory CSS — dlaczego to fundament stylowania

Kiedy zaczynamy naukę CSS, pierwszą rzeczą, z którą musimy się zmierzyć, są selektory CSS. To mechanizm, który pozwala wskazać przeglądarce, który element HTML chcemy ostylować. Bez dobrze dobranego selektora nawet najbardziej pomysłowe reguły stylów nie zadziałają — albo zadziałają nie tam, gdzie chcieliśmy. W dzisiejszym CSS mamy do dyspozycji kilkanaście rodzajów selektorów — od najprostszych (selektor elementu) po zaawansowane pseudo-klasy i pseudo-elementy, które otwierają możliwości trudne do osiągnięcia innymi metodami. W tym poradniku zobaczmy wszystkie typy, poznajmy zasady ich łączenia oraz mechanizm specyficzności, który decyduje o tym, która reguła "wygrywa", gdy kilka konkuruje o ten sam element. Całość z praktycznymi przykładami, bo najlepszym nauczycielem CSS jest kod.

Selektor elementu — najprostszy typ

Selektor elementu (nazywany też selektorem typu) wskazuje na konkretny tag HTML. Używamy po prostu nazwy znacznika bez żadnego prefiksu — p, h1, a, div, section. Przykład: p { color: #333; } zmieni kolor wszystkich akapitów na stronie. To najszerszy selektor — dotyczy wszystkich instancji danego elementu w dokumencie. W praktyce używamy go do ustalania globalnych stylów podstawowych — reset CSS, typografia bazowa, domyślne marginesy. Gdy potrzebujemy bardziej granularnej kontroli, kombinujemy selektor elementu z innymi: article p wskaże akapity tylko wewnątrz artykułów. Zaletą selektora elementu jest prostota i niska specyficzność, co ułatwia późniejsze nadpisywanie. Wadą — jego szeroki zasięg: jeśli nieostrożnie ustawimy div { margin: 20px; }, wpłyniemy na dziesiątki elementów w całej aplikacji.

CSS klasy i identyfikatory — precyzyjne celowanie

Klasy i identyfikatory to dwa najczęściej używane selektory w nowoczesnym CSS. Klasa oznaczana jest kropką: .przycisk { background: blue; }. W HTML element dostaje atrybut class="przycisk". Identyfikator oznaczany jest hashem: #header { height: 80px; }. W HTML element dostaje id="header". Zasadnicza różnica? Klasa może być użyta wielokrotnie na stronie — ten sam .przycisk pojawi się przy 20 przyciskach w formularzach, menu, stopce. Identyfikator musi być unikalny — tylko jeden element na stronie może mieć id="header". W praktyce nowoczesny CSS praktycznie nie używa #id do stylowania — zostają one dla JavaScriptu i kotwic linków (<a href="#sekcja">). Klasy dominują, bo są elastyczne i mają niższą specyficzność — łatwiej je nadpisać. Dobre nazewnictwo klas to kluczowa umiejętność frontendowca, o której napiszemy jeszcze w sekcji o BEM.

Selektor atrybutu — moc pomijana przez początkujących

Mało kto początkujący wie, że w CSS możemy pisać reguły bazujące na atrybutach HTML. Składnia używa nawiasów kwadratowych: [type="text"] wskaże wszystkie elementy z atrybutem type="text" (najczęściej inputy). Jest to szczególnie użyteczne dla formularzy: input[type="email"] { border-color: green; }, input[type="password"] { letter-spacing: 2px; }. Selektor atrybutu ma też warianty z wzorcami: [href^="https"] — zaczyna się od, [href$=".pdf"] — kończy się na, [class*="btn"] — zawiera, [alt~="logo"] — zawiera słowo. Możemy więc np. ostylować wszystkie linki PDF z ikoną: a[href$=".pdf"]::after { content: " (PDF)"; }. Selektor atrybutu działa świetnie również z data-attributes — [data-role="admin"] pozwala stylować elementy bez dodawania klas. To niedoceniana technika, szczególnie przydatna przy integracji z aplikacjami JavaScript.

Pseudo-klasy — stany elementów

Pseudo-klasy to specjalne słowa kluczowe dodawane po selektorze z dwukropkiem: a:hover, input:focus, li:first-child. Reprezentują one stan elementu, którego nie da się wyrazić zwykłym selektorem. Klasyczne pseudo-klasy interakcji to :hover (najechanie kursorem), :focus (element ma fokus, np. klikniety input), :active (element jest aktywnie klikany). Strukturalne: :first-child (pierwsze dziecko rodzica), :last-child, :nth-child(2n) (co drugi element), :only-child (jedyne dziecko). Formularzowe: :checked (checkbox/radio zaznaczony), :disabled, :required, :valid, :invalid. Nowsze: :is(), :where(), :has() — ta ostatnia zrewolucjonizowała CSS, pozwalając stylować rodziców na podstawie dzieci (article:has(img) — artykuł zawierający obrazek). Pseudo-klasy pozwalają pisać interaktywne style bez JavaScriptu — menu rozwijane przez :hover, walidacja formularzy przez :invalid — to oszczędność kodu.

Diagram pokazujący różne rodzaje selektorów CSS i ich specyficzność
Diagram pokazujący różne rodzaje selektorów CSS i ich specyficzność

Pseudo-elementy — stylowanie fragmentów

O ile pseudo-klasy reprezentują stany, pseudo-elementy pozwalają stylować części elementu, które nie istnieją jako osobny tag HTML. Oznaczamy je podwójnym dwukropkiem: ::before, ::after, ::first-line, ::first-letter, ::selection, ::placeholder, ::marker. Najczęściej używane ::before i ::after pozwalają wstawić dodatkową treść przed/po elemencie: .przycisk::after { content: " →"; } doda strzałkę. To technika używana do ikon, ozdobników, tooltipów, clear-fixów. ::selection pozwala ostylować zaznaczony tekst. ::placeholder kontroluje wygląd placeholdera w inputach. ::first-letter pozwala zrobić inicjał (duża pierwsza litera akapitu). Pseudo-elementy są renderowane jako wizualne elementy, ale nie istnieją w DOM-ie — czytniki ekranowe ich nie widzą, JavaScript też nie może ich modyfikować standardowo. Dlatego krytyczna treść nigdy nie powinna być dodawana przez content, tylko być w HTML.

Kombinatory — łączenie selektorów

Poszczególne selektory możemy łączyć w wyrażenia, które opisują relacje między elementami. Potomek (spacja): article p — akapity wewnątrz artykułów, na dowolnym poziomie zagnieżdżenia. Bezpośrednie dziecko (>): ul > li — elementy li, które są bezpośrednim dzieckiem ul (pomija zagnieżdżone). Sąsiad bezpośredni (+): h2 + p — akapit zaraz po nagłówku h2. Sąsiad ogólny (~): h2 ~ p — wszystkie akapity po h2 na tym samym poziomie. Lista selektorów (przecinek): h1, h2, h3 { font-family: Arial; } — wspólne reguły dla wielu selektorów. Kombinatory pozwalają pisać precyzyjne reguły bez nadmiaru klas: zamiast dodawać .nav-item do każdego li, wystarczy nav > ul > li. Warto jednak zachować umiar — zbyt głęboko zagnieżdżone selektory (np. div div ul li a span) są trudne do utrzymania i zwiększają specyficzność ponad rozsądek.

Specyficzność CSS — kto wygrywa konflikt

Jedna z najczęstszych frustracji początkujących brzmi: napisałem regułę, a ona nie działa. W 95% przypadków powód to specyficzność. Gdy kilka reguł dotyczy tego samego elementu, przeglądarka wybiera tę o wyższej specyficzności. Obliczamy ją jako (a,b,c,d):

Typ selektoraWagaPrzykład
Inline style1,0,0,0style="..."
ID0,1,0,0#header
Klasa, atrybut, pseudo-klasa0,0,1,0.btn, [type="text"], :hover
Element, pseudo-element0,0,0,1p, ::before
!importantnadrzędnewszystko nadpisuje

Porównujemy od lewej: (0,1,0,0) > (0,0,10,0) — jeden ID wygrywa z dziesięcioma klasami. Dlatego unikamy ID w stylowaniu — gdy raz użyjesz #naglowek { color: red }, żadna klasa go nie nadpisze bez !important. Nowe pseudo-klasy :where() mają specyficzność zerową — idealne do reset CSS.

Przykłady CSS — selektory w akcji

Kiedy zrozumiemy składnię, warto zobaczyć przykłady CSS w realnych scenariuszach. Stylowanie pierwszego akapitu z inicjałem: article p:first-of-type::first-letter { font-size: 3em; float: left; }. Alternatywne tła wierszy tabeli: tbody tr:nth-child(even) { background: #f9f9f9; }. Link z ikoną PDF: a[href$=".pdf"]::after { content: " 📄"; }. Podświetlenie wymaganych pól: input:required:invalid { border-color: red; }. Menu bez JavaScript (dropdown na hover): nav li:hover > ul { display: block; }. Stylowanie tylko elementów, które mają obrazek w środku: .card:has(img) { padding: 0; }. Każdy z tych przykładów pokazuje, jak selektory pozwalają osiągać efekty, które jeszcze kilka lat temu wymagały JavaScriptu. Przy budowie responsywnych stron często łączymy je z media queries.

Metodologia BEM — uporządkowane klasy

BEM to skrót od Block, Element, Modifier — popularna metodologia nazewnictwa klas CSS. Składa się z trzech części oddzielonych specjalnymi znakami:

  • .block — samodzielny, niezależny komponent (.card, .menu, .form)
  • .block__element — część bloku, która nie ma sensu poza nim (.card__title, .menu__item)
  • .block--modifier — wariant bloku (.card--featured, .button--primary)

Przykład: <div class="card card--featured"><h2 class="card__title">...</h2></div>. Zaletą BEM jest płaska struktura selektorów — zamiast .card .title .text, mamy po prostu .card__title__text. To obniża specyficzność, eliminuje konflikty i czyni kod czytelniejszym. BEM wymaga nieco dyscypliny i może wydawać się rozwlekły, ale skaluje się fantastycznie w dużych projektach. Alternatywy to SMACSS, OOCSS i podejścia utility-first (Tailwind CSS). Każde ma zalety — BEM pozostaje jednak najbardziej uniwersalnym punktem wyjścia dla zespołów tworzących strony WWW klasycznym podejściem komponentowym.

Dobre praktyki stosowania selektorów

Podsumujmy najważniejsze zasady, które pozwolą pisać lepszy CSS. Unikaj ID w stylowaniu — używaj klas, które mają niższą specyficzność i są elastyczne. Minimalizuj zagnieżdżenie — maksymalnie 3-4 poziomy w złożonych preprocesorach. Unikaj !important — traktuj jako ostateczność, nie codzienny reset. Używaj semantycznych nazw klas.karta-produktu jest lepsza niż .blue-box. Selektory atrybutów to świetna alternatywa dla dodatkowych klas przy formularzach. Pseudo-klasy :is() i :where() pozwalają pisać bardziej zwięzły kod — :is(h1, h2, h3) { margin: 0; }. Nie używaj * (selektora uniwersalnego) w produkcji — w reset CSS tak, w codziennych regułach nie, bo mocno obciąża przeglądarkę. Przestrzegaj konwencji zespołu — nawet najlepsza metodologia nie działa, gdy połowa zespołu jej nie używa. Wprowadzenie linterów (stylelint) pomaga egzekwować reguły automatycznie.

Podsumowanie — selektory to narzędzia

Rodzaje selektorów CSS są niczym zestaw narzędzi stolarza — każdy ma konkretne zastosowanie, a mistrzostwo polega na dobraniu właściwego do zadania. Selektor elementu daje globalne style, klasy są uniwersalnym koniem roboczym, selektor atrybutu bywa zaskakująco potężny, pseudo-klasy i pseudo-elementy otwierają drzwi do interaktywności bez JS, a kombinatory pozwalają precyzyjnie opisać strukturę. Pamiętanie o specyficzności oszczędza godziny debugowania, a stosowanie metodologii jak BEM sprawia, że kod pozostaje zrozumiały nawet po latach. Najlepszą nauką jest praktyka — zbuduj prostą stronę, zastosuj każdy z omawianych selektorów, sprawdź co działa i co nie. Z czasem dobór selektora stanie się naturalny, a refleks — szybszy. Jeśli potrzebujesz profesjonalnego stworzenia strony firmowej z czystym, utrzymywalnym kodem CSS, to jedna z naszych specjalności w WebMajka.

Najczęściej zadawane pytania (FAQ)

Jaka jest różnica między klasą a identyfikatorem w CSS?
Klasa (.klasa) może być użyta wielokrotnie na stronie — ten sam przycisk może pojawić się 50 razy. Identyfikator (#id) musi być unikalny — tylko jeden element na stronie. Klasy mają niższą specyfikę, są elastyczne i preferowane w stylowaniu. ID zostawiamy dla JavaScriptu i kotwic linków. Dobra zasada: klasy do CSS, ID do JS.
Co to jest specyficzność CSS i jak ją obliczyć?
Specyficzność to waga selektora, decydująca, która reguła wygra przy konflikcie. Obliczamy w formacie (inline, ID, klasa/atrybut/pseudo-klasa, element): #main .btn:hover ma wartość (0,1,2,0), h1 p to (0,0,0,2). Porównujemy od lewej. ID wygrywa z klasami, klasa z elementem. !important nadpisuje wszystko, ale używaj go ostrożnie.
Kiedy używać pseudo-klas, a kiedy pseudo-elementów?
Pseudo-klasy (:hover, :focus, :nth-child) reprezentują stany lub pozycje elementów w drzewie HTML. Pseudo-elementy (::before, ::after, ::first-letter) pozwalają stylować fragmenty elementu, które nie istnieją w HTML. Oznaczamy je różnie: pseudo-klasy jednym dwukropkiem, pseudo-elementy podwójnym (choć oba jeszcze działają z pojedynczym ze względu na kompatybilność).
Co to jest metodologia BEM?
BEM (Block, Element, Modifier) to konwencja nazewnictwa klas: .block, .block__element, .block--modifier. Przykład: .card, .card__title, .card--featured. Zaleta — płaska struktura, niska specyficzność, brak konfliktów. Alternatywy: SMACSS, OOCSS, utility-first (Tailwind). BEM świetnie skaluje się w dużych projektach i jest łatwy do nauki.
Dlaczego mój selektor CSS nie działa?
Najczęstszy powód to specyficzność — inna reguła o wyższej wadze nadpisuje twoją. Sprawdź w DevTools (F12) zakładkę Computed, żeby zobaczyć wygrywającą regułę. Inne przyczyny: literówka w nazwie klasy, błędna kolejność w pliku (późniejsze reguły wygrywają przy równej specyfice), brak deklaracji media query, cache przeglądarki. Pseudo-klasy jak :hover wymagają interakcji użytkownika.
Czy warto używać ID do stylowania w CSS?
W nowoczesnym CSS — nie. ID mają bardzo wysoką specyfikę, co utrudnia nadpisywanie stylów. Lepiej używać klas, nawet tych reprezentujących unikalne sekcje (.main-header zamiast #header). ID zostawiamy dla JavaScriptu (łatwe getElementById), kotwic (<a href="#sekcja">) i formularzy (połączenie <label> z <input>). W CSS ID to ostateczność.
Co to jest selektor :has() i kiedy go używać?
:has() to pseudo-klasa pozwalająca stylować rodzica na podstawie dzieci — czego CSS nie potrafił przez lata. Przykład: article:has(img) { padding: 0; } — artykuł zawierający obrazek. Obsługiwana od 2023 roku we wszystkich głównych przeglądarkach. Rewolucja w CSS — wcześniej takie zależności wymagały JavaScriptu. Używaj śmiało, ale sprawdź kompatybilność dla starszych Safari.

Przeczytaj również