Darmowe

Zrozumieć pseudo-elementy :before i :after

Chyba każda osoba tworząca strony internetowe z użyciem kaskadowych arkuszy stylów zna pojęcie pseudoklasy i w każdym projekcie używa przynajmniej jednej z nich, mianowicie…

Chyba każda osoba tworząca strony internetowe z użyciem kaskadowych arkuszy stylów zna pojęcie pseudoklasy i w każdym projekcie używa przynajmniej jednej z nich, mianowicie :hover, dzięki której między innymi nadamy odpowiednie style dla linku, który jest aktualnie wskazywany kursorem myszy. Pseudoklas jest oczywiście więcej i odpowiednio użyte, stanowią ogromny arsenał dodatkowych możliwości CSS. No właśnie… znamy pseudoklasy! I z tego powodu, artykuł, który masz przed sobą nie będzie o nich traktował. Zamiast tego skupimy się natomiast na technice bardzo zbliżonej do standardowych pseudoklas, a także bardzo podobnie brzmiącej – na pseudo-elementach.

Jeśli notacja :before i :after coś Ci mówi, to dobry znak. Jeśli nie – również powinieneś dotrwać do końca tej lektury. To właśnie na tych dwóch pseudo-elementach (które będę naprzemiennie nazywał również elementami) skupimy się w tym artykule.

UWAGA! Opisywane tutaj pseudo-elementy nie są żadną nowością dostępną dzięki modułom CSS3. Elementy te są dostępne w przeglądarkach już od bardzo dawna, zatem jeśli jeszcze ich nie znasz, to najlepszy czas by nadrobić zaległości i zyskać wiedzę na temat nowych technik.

Jak działają :before i :after?

Opisywane pseudo-elementy, w przeciwieństwie do bardziej popularnych (pseudo-klas) jak np. :hover, pozwalają na wstrzyknięcie w dynamiczny sposób dodatkowej treści do elementów naszej strony. Nie musimy zatem ingerować w kod HTML, by dodać dodatkowy tekst, obrazek lub element oraz nadać mu stosowne style według naszych upodobań. Wszystko co musimy zrobić, to zrozumieć w jaki sposób wybrana treść jest dodawana do elementu, któremu przypisaliśmy dany pseudo-element oraz jak można prawie dowolnie manipulować ową treścią, by uzyskać świetne rezultaty.

Podstawowe użycie elementu :before lub :after wygląda następująco:

p:before {
    content: "";
}

W ten sposób dodajemy do elementu p pseudo-element :before, który aktualnie jest pusty i został dodany na początku naszego elementu. Użycie :after dodałoby treść na końcu elementu. Spójrzmy na nieco bardziej rzeczywisty przykład wraz z podglądem, jak to wszystko wygląda w przeglądarce internetowej:

To jest treść paragrafu, zapisana w kodzie HTML

oraz kod CSS:

p:after {
    content: ", a to jest treść dodana dynamicznie.";
}

Wynik w przeglądarce jest następujący:
after_paragraph
Co ciekawe, tekst taki nie zachowuje się w 100% tak, jak tekst wpisany bezpośrednio w kodzie HTML. Spójrz, jak wygląda po zaznaczeniu wszystkiego (CTRL+A):
after_paragraph_selected
Widzimy tutaj, że tekst dodany dzięki :after nie jest „zaznaczalny” i nie można go również skopiować.

Jeszcze jedną ważną kwestią jest fakt, iż tekst ten również nie pojawia się w elemencie jako tekst dodany dynamicznie (co ma miejsce np. przy dodaniu tekstu za pomocą JavaScriptu):
after_chromedevtools

Jak mogliśmy zauważyć wyżej przy okazji podstawowego zapisu pseudo-elementów, jedyną rzeczą potrzebną do ich poprawnej definicji jest właściwość content, która w cudzysłowie lub apostrofach może przyjąć między innymi tekst, co nie zawsze jest szczególnie przydatne, lecz np. w przypadku użycia popularnych ostatnio czcionek obrazkowych (zamiast liter wyświetlają się ikony) okazuje się bardzo przydatne. Sprawdzając tabelę znaków danej czcionki, widzimy pod jaką literą kryje się interesująca nas ikona, a następnie podajemy tą literę we właściwości content, wstawiając przed lub za elementem ciekawą ikonę. Nasuwa się tutaj jednak pytanie, w jaki sposób przypisać daną czcionkę do pseudo-elementu?

:before i :after jak span

Kluczową rzeczą w zrozumieniu działania omawianych elementów jest sposób ich generowania przez przeglądarkę. Aby używać ich poprawnie, wyobraź sobie, że pisząc p:after wstawiasz element span na koniec elementu p. W taki właśnie sposób zachowują się nasze pseudo-elementy. Co zatem otrzymujemy? Dodatkowy element liniowy, który możemy dowolnie ostylować! Skoro możemy nadać mu dowolny styl, nic nie stoi na przeszkodzie, aby czcionkę elementu ustawić na wyżej wspomnianą czcionkę obrazkową, a następnie podać w content stosowną literę. Otrzymamy wówczas ikonę wstawioną do elementu-rodzica.

My jednak nie będziemy zajmować się dodawaniem ikon, bo nie jest to zadanie szczególnie trudne. Wspomniałem o tym dlatego, abyś pamiętał, że w kolejnym projekcie możesz zrezygnować z części obrazków, na rzecz czcionki dodanej poprzez @font-face, dzięki której uzyskasz pożądane efekty.

To, na czym się skupimy, to przykłady z życia wzięte, a dokładniej 2 przykłady użycia :before i :after z moich niedawnych realizacji. To właśnie one zainspirowały mnie do podzielenia się tymi niezwykle użytecznymi technikami, które mogą zaoszczędzić nam sporo czasu i wysiłku. Znając już podstawy, możemy przejść do konkretów i na nich wytłumaczyć jak wprowadzić je w życie.

Drewniany przycisk

Pierwszą z realizacji, której się przyjrzymy, jest drewniany przycisk, który dzięki pseudo-elementom dopasowuje się do każdej szerokości. Efekt końcowy naszej pracy wygląda następująco:
drewniany_przyklad
Po napisaniu potrzebnych stylów, wystarczy nadać stosowną klasę dla elementu a i wszystko w magiczny sposób będzie działać. Właściwie niewiele tu magii, spójrzmy zatem z jakiego obrazka został stworzony owy przycisk:
drewniany_sprite
Jak widzisz, trzy obrazki zostały tutaj połączone w jeden, z użyciem techniki CSS Sprites, o której możesz dowiedzieć się więcej z jednego z moich poprzednich wpisów. W górnej części obrazka widzimy lewą oraz prawą część przycisku, natomiast dolna część posłuży jako powtarzalne poziomo tło. Dzięki temu niezależnie od szerokości przycisku (czyli ilości tekstu, który się w nim znajduje) wszystko będzie wyglądało poprawnie. Podstawienie całego obrazka przycisku nie byłoby tutaj idealnym rozwiązaniem, gdyż narzucałoby jego szerokość i w przypadku kilku elementów konieczne byłoby stworzenie kilku przycisków o różnych szerokościach, a jak wspomniałem na początku, zależy nam na czasie i włożonym w pracę wysiłku, ale przede wszystkim na możliwie najlepszym rozwiązaniu danego problemu.

Aby lepiej zrozumieć całość, przyjrzyjmy się podstawowym stylom, jakie zostały nadane dla naszego przycisku:

a.readMore {
   display: inline-block;
   *display: inline;
   padding: 0 7px;
   height: 31px;
   text-align: center;
   background: url(../images/readmore.png) 0 -31px repeat-x;
   zoom: 1;
}

Celowo pominąłem tutaj style odnoszące się do czcionki i koloru, bo to jest sprawa raczej prosta i nie związana z naszym głównym tematem. Element a ma nadane wyświetlanie liniowo-blokowe, dzięki któremu możemy nadawać mu rozmiary. *display: inline; oraz zoom: 1; to trick dla Internet Explorera starszego niż wersja 8, by poprawnie zasymulować działanie display: inline-block; Następnie widzimy padding z lewej oraz prawej strony, który w tym konkretnym przypadku nie ma większego znaczenia. Wysokość 31px, to wysokość naszego tła z obrazka, a zatem i wysokość przycisku. Jak widzisz we właściwości tła, zostało ono przesunięte o 31px w dół (raz jeszcze – technika CSS Sprites) oraz jest powielane poziomo. Dzięki temu nasz przycisk uzyskał jednolite tło drewnianej tekstury i aktualnie wygląda tak:
drewniany_1
Kiedy już wszystko zaczyna wyglądać poprawnie, nadszedł czas na pomoc ze strony opisywanych pseudo-elementów. Naszym celem będzie wstawienie jednego przed głównym przyciskiem, a drugiego za nim oraz nadanie im odpowiednich stylów, tak aby stworzyły brzegi drewnianego przycisku. Prześledźmy zatem kod CSS dla elementu :after

a.readMore:after {
   content: "";
   display: block;
   width: 12px;
   height: 31px;
   margin: 0 -12px 0 0;
   float: right;
   background: url(../images/readmore.png) -68px 0 no-repeat;
}

Jak już wspomniałem na początku, obowiązkowa właściwość content, która w naszym przypadku jest zwyczajnie pusta. A to co widzisz dalej, to najnormalniejsze style, które możemy nadawać dla każdego elementu. To właśnie dlatego zaznaczyłem wcześniej, że pseudo-elementy :before i :after należy traktować jak np. element span. Dzięki temu możemy przekształcić takie elementy w blokowe, nadawać im rozmiary itd. W tym przypadku prawa część przycisku otrzymała wyświetlanie blokowe, dzięki któremu również nadaliśmy jej szerokość oraz wysokość, które pokrywają się z rozmiarem owej części z obrazka powyżej. Kluczowa jest tutaj jednak właściwość float: right, która sprawiła, że dodany dynamicznie element nie znalazł się pod spodem, lecz przykleił się do prawej strony głównego przycisku (trzeba pamiętać, że właściwość display: block; „wyrzuca” element do nowej linii, stąd użycie float). Jeśli jednak byłeś wystarczająco uważny, to wiesz, że elementy dodane z użyciem :after znajdują się wewnątrz elementu-rodzica, co w tym przypadku nie jest pożądanym rezultatem, gdyż prawy bok przycisku nakładałby się po prostu na tło głównego przycisku. My chcemy jednak, by element ten znalazł się „na zewnątrz” swojego rodzica i stąd właśnie pojawia się ujemny prawy margines, który wyciągnie nasz element poza prawą krawędź przycisku dokładnie o 12px, czyli o wartość równą z jego szerokością.

Wiedząc już w jaki sposób stworzona została prawa część przycisku, możemy analogicznie stworzyć lewą, używając pseudo-elementu :before

a.readMore:before {
   content: "";
   display: block;
   width: 12px;
   height: 31px;
   margin: 0 0 0 -12px;
   float: left;
   background: url(../images/readmore.png) 0 0 no-repeat;
}

Tym razem element „przyklejamy” do lewej strony z użyciem float: left; oraz „wyciągamy” poza lewą krawędź ujemnym lewym marginesem o wartości 12px. Zmianie uległo również położenie tła, które wskazuje w tym momencie lewą część z obrazka, czyli pozycję 0 0;

Dzięki takiemu zabiegowi główna część przycisku może być dowolnie szeroka, gdyż jej tło będzie powielane poziomo, a elementy :before i :after zawsze będą przylegały do lewej oraz prawej krawędzi tworząc spójną całość.

Dekoracja paragrafu z tekstem

Kolejnym przykładem, któremu się przyjrzymy jest następujący box:
paragraf_przyklad
Prosty nagłówek, paragraf z treścią oraz link przenoszący do dalszych informacji. Nic skomplikowanego. Zwróć jednak uwagę na górną oraz dolną żółtą linię, która oddziela tekst od nagłówka i linku. To właśnie kolejne z zastosowań naszych pseudo-elementów. Tak naprawdę jeden mały szczegół dzieli ten prosty projekt od nieco większego wyzwania. Z punktu widzenia web designera właśnie takie krótsze od szerokości tekstu linie wpasowały się w projekt witryny. Gdyby żółte linie były takiej samej szerokości jak tekst, wszystko, co należałoby zrobić, to nadać dla paragrafu górny oraz dolny border w kolorze żółtym i sprawa byłaby załatwiona. Kreski są jednak krótsze i do ich wykonania idealnie nadały się :before i :after. Spójrzmy jak problem został rozwiązany w kodzie CSS:

p {
  width: 80%;
  padding: 15px 0 15px 20px;
  margin: 15px 0;
  position: relative;
}

p:before {
    content: "";
    display: block;
    width: 60%;
    height: 1px;
    position: absolute;
    top: -1px;
    left: 0;
    background-color: #efc73c;
}

p:after {
    content: "";
    display: block;
    width: 60%;
    height: 1px;
    position: absolute;
    bottom: -1px;
    left: 0;
    background-color: #efc73c;
}

Element p przyjął 80% dostępnej w boxie szerokości oraz otrzymał górny i dolny padding, który odsunie nasze żółte linie od samego tekstu. Równie ważna jest tutaj właściwość position: relative;, dzięki której element ten stanie się kontekstem pozycjonującym dla elementów :before i :after, którym została nadana position: absolute;

Spójrz na style dla elementu :before (:after działa analogicznie). Element ten po raz kolejny wyświetlamy jako element blokowy oraz nadajemy mu 60% dostępnej szerokości, dzięki czemu będzie to linia krótsza niż cały paragraf, który ma dekorować. Wysokość 1px oraz kolor tła żółty (tutaj można było pominąć wysokość i tło, a zamiast tego nadać np. dolny border o szerokości 1px). Element ten jest pozycjonowany absolutnie i wyciągnięty o 1px ponad górną krawędź paragrafu, tak by faktycznie znalazł się poza jego ramami. Podobnie jest z elementem :after, jednak ten znalazł się 1px poniżej swojego rodzica.

W ten prosty sposób odtworzyliśmy projekt zgodnie z życzeniem web designera, omijając niewygodne techniki np. podstawiania tła z obrazka lub mówienia „tego się nie da zrobić”.

To jeszcze nie wszystko

Do tej pory poznałeś niezbędną do pracy z pseudo-elementami teorię oraz zobaczyłeś 2 przykłady z życia wzięte, w których omawiane techniki znalazły idealne zastosowanie. To jednak nie wszystko! Wspomniałem, że dzięki właściwości content możemy dopisać do naszego elementu tekst (lub np. dodać pauzę do elementów listy ul), ale tak naprawdę możemy tam umieścić również obrazek lub treść któregoś z atrybutów. Aby dodać obrazek przed lub za naszym głównym elementem, możemy dla pseudo-elementu ustawić wyświetlanie blokowe, a następnie szerokość, wysokość oraz tło z danym obrazkiem. Jest jednak prostszy sposób, by tego dokonać. Zamiast tekstu w cudzysłowach, możemy wykorzystać zapis url() oraz podać ścieżkę do obrazka w ten sposób:

ul li:before {
    content: url(images/obrazek.png);
}

Jak wspomniałem, możemy również uzyskać treść jednego z atrybutów elementu, np. link do strony z atrybutu href elementu a:

a:after {
    content: attr(href);
}

Takie rozwiązanie pobierze wartość atrybutu href i wstawi ją za tekstem odnośnika. Może to być przydatne np. dla arkuszy stylów dostosowanych do druku, kiedy chcemy aby linki były wyświetlane jako adresy URL.

Podsumowanie

Mam nadzieję, że tym „z życia wziętym” poradnikiem rozjaśniłem dostatecznie temat pseudo-elementów, które okazuję się niezwykle przydatne, a czasem wręcz niezastąpione. Mam również nadzieję, że już w kolejnym projekcie zaczniesz dostrzegać elementy, które można stworzyć właśnie w ten sposób, jeśli do tej pory jeszcze omawianych technik nie używałeś. Na koniec dobra wiadomość – :before i :after działają w każdej nowej przeglądarce, a także w Internet Explorerze w wersji 8 i nowszych, więc nie ma powodów, by zastanawiać się czy warto z nich skorzystać już dziś.

Kończąc, oczywiście zachęcam do zadawania pytań, a osoby które z omawianych rozwiązań korzystają, do dzielenia się swoimi przykładami kreatywnego użycia pseudo-elementów!

UDOSTĘPNIJ ARTYKUŁ:

Powiązane artykuły

Darmowe

10 portali dla designerów – część I

Nowości

Kolejna edycja Bootcampu Web Design i UX wktótce!

Nowości

Kurs Webpack 2 – Wydajna Praca z JavaScript już dostępny!

Pozostań na bieżąco!

Już nigdy nie przegapisz ważnych informacji, promocji oraz nowych kursów. Zapisz się na newsletter już teraz!

Zapisując się do newslettera akceptujesz naszą politykę prywatności