Lekcja 33

Pseudoklasy i pseudoelementy w praktyce

Pseudoklasy pozwalają stylować elementy zależnie od stanu, relacji albo pozycji w strukturze. Pseudoelementy pozwalają stylować fragmenty elementu albo dodać dekorację bez dokładania kolejnego znacznika HTML.

Cele lekcji

Po ukończeniu tej lekcji będziesz umieć:

  • stosować pseudoklasy stanów, takie jak :hover, :focus-visible i :disabled,
  • używać pseudoklas strukturalnych do stylowania list i powtarzalnych elementów,
  • grupować selektory przez :is() i obniżać specyficzność przez :where(),
  • wykluczać elementy przez :not(),
  • stylować stany formularzy przez :required, :valid i :invalid,
  • używać ::before i ::after do dekoracji bez utraty semantyki.

Kontekst praktyczny

W realnym interfejsie wiele decyzji zależy od stanu: link jest odwiedzony, przycisk ma fokus, pole formularza jest niepoprawne, a ostatni element listy nie powinien mieć separatora. Pseudoklasy i pseudoelementy pozwalają opisać te sytuacje bez dokładania klas do każdego przypadku.

W praktyce: pseudoselektory są świetne wtedy, gdy wynikają ze stanu lub struktury dokumentu. Jeśli opisujesz decyzję biznesową, wariant komponentu nadal lepiej nazwać klasą.

Stany UI

Pseudoklasy stanów opisują interakcję użytkownika z elementem. Najczęściej używasz ich przy linkach, przyciskach, kartach i polach formularza.

.button:hover {
  background: #1d4ed8;
}

.button:focus-visible {
  outline: 3px solid #93c5fd;
  outline-offset: 3px;
}

.button:disabled {
  opacity: .55;
  cursor: not-allowed;
}

:focus-visible jest lepsze od prostego :focus dla wielu komponentów, bo pokazuje fokus głównie wtedy, gdy jest potrzebny użytkownikowi klawiatury.

Pseudoklasy strukturalne

Pseudoklasy strukturalne wybierają elementy na podstawie ich miejsca w dokumencie. Są przydatne przy listach, tabelach, kartach i separatorach.

.list-item:first-child {
  border-top: 0;
}

.list-item:last-child {
  border-bottom: 0;
}

.table-row:nth-child(even) {
  background: #f8fafc;
}

Używaj ich do wzorców wynikających ze struktury. Jeżeli konkretny element ma znaczenie produktowe, nazwij go klasą zamiast liczyć jego pozycję.

:is() i :where()

:is() upraszcza grupowanie selektorów. :where() robi podobną rzecz, ale ma zerową specyficzność, co pomaga pisać style bazowe łatwe do nadpisania.

.card :is(h2, h3, p) {
  margin: 0;
}

:where(.content) :where(ul, ol) {
  padding-left: 1.25rem;
}

W praktyce :where() dobrze pasuje do warstwy base i layout, a :is() do czytelnego skracania selektorów komponentów.

:not()

:not() wybiera elementy, które nie pasują do podanego selektora. Przydaje się do wyjątków strukturalnych, ale łatwo go nadużyć.

.nav-link:not([aria-current="page"]) {
  color: #475569;
}

.stack > *:not(:last-child) {
  margin-bottom: 1rem;
}

Jeśli :not() robi się długie albo opisuje wiele warunków naraz, prawdopodobnie potrzebujesz klasy wariantu albo prostszej struktury HTML.

Pseudoklasy formularzy

Formularze mają własne pseudoklasy stanów. Możesz reagować na wymagane pola, poprawne wartości, błędy, disabled i checked bez ręcznego dokładania klas do każdego pola.

.field input:required {
  border-color: #93c5fd;
}

.field input:invalid {
  border-color: #f87171;
}

.field input:valid {
  border-color: #86efac;
}

Pamiętaj, że walidacja CSS nie zastępuje komunikatów błędu i logiki formularza. To tylko warstwa wizualnego feedbacku.

Pseudoelementy

Pseudoelementy pozwalają stylować część elementu albo dodać dekoracyjny fragment. Najczęściej spotkasz ::before, ::after, ::marker, ::selection i ::first-letter.

.badge::before {
  content: "";
  width: .5rem;
  height: .5rem;
  border-radius: 999px;
  background: #22c55e;
}

::selection {
  background: #bfdbfe;
}

Treść dodawana przez content powinna być dekoracyjna. Ważnych informacji nie ukrywaj wyłącznie w ::before albo ::after.

Demo selektorów

Demo pokazuje pseudoklasy i pseudoelementy w małym komponencie zadania. Są tu stany przycisków, marker statusu bez dodatkowego elementu oraz strukturalne separatory listy.

Aktywne zadanie

Przegląd komponentu

Najedź na akcję albo przejdź klawiaturą, aby zobaczyć stan interakcji.

Struktura

Lista kontrolna

  1. :first-childusuwa zbędny separator startowy
  2. :not()pomija element aktywny albo ostatni
  3. ::beforedodaje dekoracyjny status
  4. ::markerstyluje numer listy

Najczęstsze błędy początkujących

  • Usuwanie stylu fokusu bez zapewnienia dostępnej alternatywy.
  • Używanie :hover jako jedynego feedbacku interakcji.
  • Opieranie logiki komponentu na :nth-child(), gdy potrzebna jest klasa wariantu.
  • Tworzenie bardzo długich selektorów z :not().
  • Dodawanie ważnej treści przez ::before albo ::after.
  • Zapominanie, że :where() ma zerową specyficzność i łatwo je nadpisać.

Mini zadanie

Zbuduj mały komponent listy zadań z pseudoklasami i pseudoelementami.

  • Dodaj link lub przycisk ze stanami :hover, :focus-visible i :disabled.
  • Użyj :not(:last-child) do separatorów między zadaniami.
  • Użyj :is(), aby skrócić selektor nagłówków i akapitów wewnątrz karty.
  • Dodaj dekoracyjny status przez ::before.
  • W formularzu testowym ostyluj :required, :valid i :invalid.
  • Sprawdź, czy ważna informacja jest nadal dostępna w HTML, a nie tylko w pseudoelementach.

Checklista

  • Rozumiem różnicę między pseudoklasą i pseudoelementem.
  • Potrafię zaprojektować widoczny stan :focus-visible.
  • Używam pseudoklas strukturalnych tylko wtedy, gdy wynikają ze struktury.
  • Wiem, kiedy użyć :is(), a kiedy :where().
  • Nie wkładam kluczowej treści do ::before ani ::after.
  • Potrafię ostylować podstawowe stany formularza bez dodatkowych klas.

Podsumowanie lekcji

Pseudoklasy i pseudoelementy pozwalają pisać mniej klas, ale wymagają dobrego wyczucia. Stany interakcji, pozycja w strukturze i dekoracyjne elementy CSS powinny wspierać semantyczny HTML, a nie go zastępować.

Kolejny krok roadmapy to container queries.

Przejdź do Lekcji 34