WWW

Pseudoelementy ::before i ::after w CSS – pisownia i zastosowanie

9 min. czytania

Pseudoelementy ::before i ::after to jeden z najważniejszych mechanizmów w CSS: pozwalają dodać dekoracyjną treść przed lub po zawartości elementu, bez zmiany HTML i przy zachowaniu semantyki oraz dostępności strony. Jednocześnie wokół nich narosło sporo pytań – zwłaszcza o poprawną pisownię (:before vs ::before) i bezpieczne zastosowanie z perspektywy użytkowników, w tym osób korzystających z czytników ekranu.

Czym są pseudoelementy w CSS?

Pseudoelementy to specjalne słowa kluczowe dodawane do selektorów, które pozwalają stylizować określone części elementu, do których nie da się łatwo odwołać zwykłymi selektorami albo w ogóle nie istnieją w HTML jako osobne węzły. To abstrakcyjna reprezentacja fragmentów dokumentu, tworzona i kontrolowana wyłącznie przez CSS.

Do typowych pseudoelementów należą m.in.:

  • ::before – wstawia wygenerowaną treść przed zawartością elementu;
  • ::after – wstawia wygenerowaną treść po zawartości elementu;
  • ::first-line, ::first-letter – stylizują odpowiednio pierwszą linię i pierwszą literę;
  • ::marker – stylizuje znaczniki list (np. kropki, numerację);
  • ::selection – stylizuje zaznaczony fragment tekstu.

:before vs ::before – jak to poprawnie pisać?

W praktyce spotkasz dwa zapisy: ::before / ::after (z podwójnym dwukropkiem) oraz :before / :after (z jednym dwukropkiem, starszy zapis). Specyfikacja CSS wprowadziła podwójny dwukropek dla pseudoelementów, by odróżnić je od pseudoklas (np. :hover, :focus).

Współczesne materiały i dokumentacja (np. MDN, web.dev) zalecają zapis ::before i ::after. Jednocześnie przeglądarki, z powodów historycznych, wciąż wspierają zapis z jednym dwukropkiem – to zgodność wsteczna. W nowym kodzie używaj konsekwentnie zapisu z podwójnym dwukropkiem i nie mieszaj obu form w jednym projekcie.

Przykład poprawnego selektora:

.button::before {
content: ""; /* styl pseudoelementu */
}

Jak działają ::before i ::after?

„Wirtualne” dziecko elementu

Pseudoelementy ::before i ::after tworzą wirtualnego potomka wewnątrz zaznaczonego elementu. ::before staje się jego pierwszym dzieckiem, a ::after – ostatnim. Dodana treść nadal znajduje się wewnątrz danego elementu, a nie przed lub za nim w strukturze DOM.

Przykład – HTML:

<p class="quote">To jest treść akapitu.</p>

CSS:

.quote::before { content: "„"; }
.quote::after { content: "”"; }

Wizualnie użytkownik zobaczy:

„To jest treść akapitu.”

W DOM nadal istnieje tylko jeden element <p>, a cudzysłowów nie zobaczysz w HTML.

Wymóg właściwości content

Pseudoelement ::before lub ::after powstaje tylko wtedy, gdy ustawisz mu właściwość content. Bez content pseudoelement w ogóle nie jest generowany; content może być ciągiem znaków, adresem obrazka, licznikiem, atrybutem lub pustym stringiem.

Przykład minimalny:

.title::before {
content: "";
display: block;
height: 4px;
width: 40px;
background: currentColor;
}

Tutaj content: "" nie dodaje tekstu, ale aktywuje pseudoelement, który następnie stylizujemy jak prostokątną linię dekoracyjną.

Domyślne zachowanie w modelu pudełkowym

Najważniejsze fakty o zachowaniu pseudoelementów w box modelu:

  • ::before i ::after są domyślnie elementami inline,
  • możesz im zmienić display na block, inline-block, flex i inne,
  • można je pozycjonować (position), nadawać wymiary, tło, obramowania i stosować transformacje.

To sprawia, że świetnie nadają się do tworzenia ikon, kropek, linii, znaczników, strzałek i innych efektów dekoracyjnych bez rozbudowywania HTML.

Podstawowa składnia i najczęstsze błędy

Minimalny schemat

Najprostszy schemat użycia wygląda tak:

selektor::before {
content: "treść"; /* lub "" */
/* dodatkowe style */
}

Kluczowe elementy:

  • selektor elementu – np. .button, a, h2;
  • ::before / ::after – wskazanie pseudoelementu;
  • content – zawsze wymagane dla widocznego pseudoelementu.

Typowe błędy

  1. Brak content – pseudoelement nie zostanie wygenerowany:

    Kod problematyczny:

    .button::before {
    width: 10px;
    height: 10px;
    background: red;
    }

  2. Traktowanie pseudoelementu jak fizycznego węzła w HTML – DevTools pokazują je obok elementu, ale w HTML nie ma rzeczywistego znacznika.
  3. Dodawanie treści istotnej dla użytkownika do pseudoelementów – to poważny błąd z punktu widzenia dostępności (szczegóły w kolejnej sekcji).

Różnica między ::before a ::after

Oba pseudoelementy działają podobnie: dodają wirtualnego potomka wewnątrz elementu i można je stylizować tymi samymi właściwościami CSS. Kluczowa różnica polega na miejscu wstawienia: ::before pojawia się przed „główną” treścią (pierwsze dziecko), a ::after po zawartości (ostatnie dziecko).

Przykład – dodanie ikonki przed linkiem i strzałki po nim:

a.external::before { content: "🌐 "; }
a.external::after { content: " ↗"; }

Wizualnie:

🌐 Nazwa linku ↗

Typowe zastosowania ::before i ::after

Cudzysłowy, ozdobniki typograficzne

Pseudoelementy są idealne do dodawania cudzysłowów i innych znaków typograficznych wokół cytatów.

blockquote::before {
content: "“";
font-size: 3rem;
line-height: 1;
margin-right: 0.25em;
}
blockquote::after {
content: "”";
}

Dekoracyjne linie, „badge”, tła

Ponieważ pseudoelementy można traktować jak wirtualne bloki, często stosuje się je do:

  • poziomych linii pod nagłówkiem,
  • dekoracyjnych ramek,
  • etykiet typu „NEW”, „SALE” (jako dekoracja, nie kluczowa informacja),
  • tła przesuniętego względem elementu.

Przykład linii pod nagłówkiem:

h2.section-title {
position: relative;
padding-bottom: 0.75rem;
}
h2.section-title::after {
content: "";
position: absolute;
left: 0;
bottom: 0;
width: 3rem;
height: 3px;
background-color: currentColor;
}

Własne znaki interpunkcyjne, ikonki, strzałki

::before i ::after świetnie nadają się do dodawania ikonek lub symboli przed/po tekście.

.nav-link--has-children::after {
content: "▾";
margin-left: 0.25em;
font-size: 0.8em;
}

Liczniki i atrybuty

Właściwość content wspiera również wartości counter() (np. do numerowania kroków) oraz attr() (wstawienie wartości atrybutu, np. href czy data-*).

Przykład z atrybutem:

a::after {
content: " (" attr(href) ")";
font-size: 0.8em;
}

Taki pattern bywa używany np. w wersjach „drukowalnych” lub w trybach debugowania, ale uważaj, by nie dublować zbędnie treści dla czytników ekranu.

Clearfix i hacki layoutowe

Klasyczny wzorzec clearfix wykorzystywał ::before i ::after, aby wymusić poprawne „czyszczenie” floatów. Choć dziś częściej stosuje się Flexbox i Grid, w starszych kodach nadal zobaczysz np.:

.clearfix::after {
content: "";
display: block;
clear: both;
}

Takie użycie jest prezentacyjne (techniczne) i nie wpływa na treść semantyczną dokumentu.

::before i ::after a dostępność (WCAG, czytniki ekranu)

Dekoracja, nie treść – dlaczego to ważne?

Pseudoelementy powinny służyć głównie dekoracji, a nie przekazywaniu istotnych informacji. Wygenerowana treść ma charakter prezentacyjny i część niewizualnych user‑agentów (czytniki ekranu) może ją zignorować.

W praktyce oznacza to:

Nie umieszczaj w ::before i ::after treści, bez której użytkownik nie zrozumie funkcji elementu (np. części etykiety przycisku, ostrzeżeń, kluczowych etykiet formularza).

Jak czytniki ekranu traktują wygenerowaną treść?

Zachowanie czytników (NVDA, JAWS, VoiceOver itd.) wobec content nie jest całkowicie jednolite i zależy od przeglądarki oraz trybu pracy. Najczęściej obserwuje się, że:

  • w wielu kombinacjach czytnik + przeglądarka wygenerowana treść jest czytana jak część tekstu,
  • w innych bywa ignorowana lub odtwarzana w nieoczekiwany sposób,
  • przyszłe zmiany w przeglądarkach/czytnikach mogą to zachowanie zmienić.

Pseudoelementy traktuj jako niewiarygodne medium do przekazywania treści.

Bezpieczne zastosowania z perspektywy dostępności

Za bezpieczne uznaje się takie użycia, w których pseudoelement:

  • nie dodaje nowej, kluczowej informacji, a jedynie wzmacnia wizualnie coś, co już jest w tekście,
  • nie zastępuje tekstu, który powinien być dostępny w HTML,
  • nie jest jedynym nośnikiem informacji (np. jedyny sposób odróżnienia „stanu błędu”).

Przykłady:

  • dekoracyjna linia pod nagłówkiem,
  • ozdobna ikonka strzałki przy przycisku „Dalej” – o ile tekst „Dalej” jest normalnie widoczny w HTML,
  • cudzysłowy wokół cytatu, gdy i tak wiadomo z kontekstu, że to cytat.

Przykłady niebezpiecznych wzorców

  1. „Ucinanie” tekstu w HTML i dopełnianie go w pseudoelementach.

Kod HTML:

<button class="cta">Pobierz</button>

Kod CSS:

.cta::after { content: " raport PDF"; }

Użytkownik widzi „Pobierz raport PDF”, ale czytnik ekranu może przeczytać tylko „Pobierz”, przez co znaczenie staje się niepełne.

  1. Opisy obrazków wyłącznie w ::before / ::after.

Opis obrazka powinien znaleźć się w alt lub w tekście powiązanym semantycznie, a nie w CSS.

  1. Komunikaty błędów, informacje o stanie, ostrzeżenia tylko w wygenerowanej treści.

Jeśli np. komunikat „Pole wymagane” istnieje wyłącznie w ::after, część użytkowników może go nie otrzymać.

Wspomagające techniki: aria-hidden i testy

Jeśli pseudoelement jest czysto dekoracyjny, warto ograniczyć jego wpływ na prezentację w czytnikach ekranu. Pomagają w tym m.in.:

  • dodanie dekoracji do osobnego elementu i oznaczenie go aria-hidden="true",
  • używanie pustej treści content: "" dla dekoracyjnych form (linii, tła, kształtów),
  • unikanie zbędnego „szumu” tekstowego (np. "***" jako dekoracja).

Kluczowe są testy w różnych środowiskach:

  • sprawdź komponent z użyciem NVDA / VoiceOver / Narratora,
  • przetestuj na kilku przeglądarkach,
  • upewnij się, że informacje pozostają dostępne także przy wyłączonych stylach CSS.

Pseudoelementy w projekcie – dobre praktyki

Oddziel strukturę od prezentacji

Struktura i treść należą do HTML, a dekoracje i efekty – do CSS. Dzięki ::before i ::after utrzymasz przejrzysty, semantyczny kod i jednocześnie bogatą warstwę wizualną.

Traktuj pseudoelementy jak „normalne” elementy… ale w CSS

Możesz stosować większość typowych właściwości (color, background, border, position, display, transform, animation itd.), a w DevTools zobaczysz je jako dodatkowe węzły – ułatwia to debugowanie i projektowanie.

Konsekwencja w pisowni

W nowych projektach używaj wyłącznie ::before i ::after. W starszych, gdzie wszędzie jest :before / :after, możesz ten zapis pozostawić, ale rozważ ujednolicenie w nowym kodzie.

Stosuj sensowne nazwy klas

Doprecyzuj przeznaczenie pseudoelementu nazwą klasy komponentu. Na przykład:

.card__title::after { /* dekoracyjna linia tytułu karty */ }
.button--icon-left::before { /* ikonka po lewej stronie przycisku */ }

Pamiętaj o responsywności i trybie „bez CSS”

Dostępność to nie tylko czytniki ekranu. Warto uwzględnić także:

  • użytkowników z wyłączonymi stylami,
  • urządzenia o nietypowych rozdzielczościach,
  • tryby „reader mode” w przeglądarkach.

Zadbaj, by kluczowe informacje były widoczne i zrozumiałe także wtedy, gdy pseudoelementy nie są renderowane.

To naturalnie wynika z zasady: pseudoelementy są dodatkiem dekoracyjnym, nie nośnikiem treści krytycznej.

Podsumowanie praktyczne – jak używać ::before i ::after w projektach

  1. Zawsze ustawiaj content – bez tego pseudoelement nie powstanie.
  2. Stosuj zapis z podwójnym dwukropkiem::before, ::after – zgodny ze współczesną specyfikacją.
  3. Traktuj je jako narzędzie dekoracyjne – linie, ikonki, cudzysłowy, badge, tła.
  4. Nie umieszczaj tam treści kluczowej dla zrozumienia interfejsu – czytniki ekranu mogą ją pominąć lub odczytać w nieprzewidywalny sposób.
  5. Testuj komponenty z wyłączonym CSS i z czytnikami ekranu – upewnij się, że strona pozostaje zrozumiała i funkcjonalna.
  6. Dbaj o spójność kodu – jedna stylistyka zapisu, sensowne nazwy klas, przejrzyste reguły CSS.