Ostatnia aktualizacja: 

Star rating w samym css

Komponenty oceny gwiazdkami są standardem w ocenie różnych materiałów - filmy, opinie o restauracjach... Okazuje się, że możemy stworzyć estetyczny i interaktywny komponent w samym CSS! Zobacz jak :) 

CSS
HTML
13m 56s
9.400+ wyświetleń
258+ pozytywnych reakcji

Interaktywny element formularza:
Ocena gwiazdkami

Jeśli nie chcesz ładować kolejnej biblioteki bazującej na jQuery aby stworzyć prosty formularz z oceną gwiazdkami, która reaguje na najechanie myszą tworząc przyjazny dla użytkownika efekt wyboru ilości gwiazdek - ten materiał jest w sam raz dla Ciebie. Zaawansowane selektory CSS czekają!

Transkrypt wideo

Cześć, witajcie na kodu.je. Z tej strony Wojtek,
w dzisiejszym odcinku stworzymy sobie system oceny gwiazdkami w samym CSSie, Zapraszam.

[ intro kodu.je ]

Zaczniemy od stworzenia kontenera na nasze gwiazdki.
Nazwiemy go sobie "stars" i chcemy aby każda nasza gwiazdka była znacznikiem input o typie "radio".

Każdy znacznik "radio" powinien oczywiście posiadać nazwę
w tym wypadku będzie to "star".
I swoją własną unikalną wartość,
aby móc rozróżnić poszczególne inputy od siebie.

Więc ja stworzę sobie tutaj pięć gwiazdek.
No i tak naprawdę moglibyśmy przejść do stylowania
naszego markupu, natomiast jak zapewne wiecie, stylowanie inputów o typie "radio" nie jest najprostsze.

Dlatego stworzymy sobie do tego odpowiednie labelki
poza tym, będzie to o wiele bardziej czytelne dla czytników ekranowych.

Musimy oczywiście zdefiniować dla jakiego znacznika jest ta labelka.
Będziemy to robić po identyfikatorach o prefiksie "star" i oczywiście zmieniać się będzie nam cyferka.

Nazwiemy to sobie "One Star" i analogicznie całą resztę labelek sobie stworzymy. Oczywiście musimy przypisać naszym inputom odpowiednie identyfikatory, czyli "star1" i analogicznie "star2" "star3" "star4" i tak dalej.

Jak widzicie nie jest to najprostsza struktura, musieliśmy trochę czasu spędzić, aby ją stworzyć.
Dlatego dla takich bardziej skomplikowanych struktur,
możecie wykorzystać bardzo przydatne narzędzie "EMMET".

Materiału o obsłudze tego narzędzia i czym on tak naprawdę jest,
możecie spodziewać się na naszym kanale, natomiast, po prostu służy on do szybszego tworzenia bardziej skomplikowanego markupu HTML.

Przejdźmy do naszego stylowania i zacznijmy od zdefiniowania naszego kontenera ".stars".

Ustawmy mu background na kolor biały. Ustawimy wysokość na 30 pikseli i szerokość na 200 pikseli, w paddingu 10 pikseli.

Możemy zaokrąglić boki o połowę wysokości, żeby to ładnie wyglądało
Jeszcze tylko na flexie, będzie nam łatwo zarządzać tymi gwiazdkami,
więc wyrównamy je w poziomie i w pionie.

Kontener wygląda już całkiem ok, przejdźmy więc do stylowania samych inputów.

Tak naprawdę nie chcemy aby te nasze kropeczki
były tam widoczne, więc przeniesiemy je poza obszar widzenia,
ponieważ ustawienie display: none, czy visibility="hidden" jest złą praktyką jeśli chodzi o dostępność i czytniki ekranowe o których wspominałem na początku tego wideo, więc przesuniemy sobie nasze inputy, które znajdują się wewnątrz naszego kontenera ".stars",
poza obszar widoczności.

Ustawimy żeby były wysunięte tak w lewo
żeby ich nie było widać.
Możemy przejść do stylowania naszej labelki
Ustawimy jej jakąś szerokość i wyskość.
Nadajmy jeszcze dodatkowo padding 5 pikseli
i możemy jeszcze podglądowo ustawić border
na kolor czarny, żeby tylko ładnie sobie zwizualizować, jak te elementy są ułożone w tym momencie.

Na razie nie będziemy nic robić z tym tekstem.
Stwórzmy sobie naszą faktyczną gwiazdkę. Zrobimy to przy pomocy pseudoelementu "before" na naszej labelce i zrobimy to takim ciekawym trikiem, dosyć prostym, czyli ustawimy na naszym contencie znak "★".

Nie musimy rysować żadnych trójkątów, które będą poobracane,
to jest o wiele szybsza metoda właśnie stworzenia takiej gwiazdki
i jeżeli macie taką możliwość, to jak najbardziej korzystajcie z tego typu rozwiązań.

Chcielibyśmy aby nasze gwiazdki były domyślnie srebrne
to jest heksadecymalny ekwiwalent koloru srebrnego.

Ustawimy sobie font-size na wyskość naszego kontenera,
no i oczywiście line-height również na 30 pikseli.

Jak widzimy ta nasza gwiazdka wypchnęła nam teraz tekst.
Jest dużo sposobów na jakie moglibyśmy ten problem rozwiązać,
przede wszystkim możemy ustawić sobie na razie kolor tego naszego tekstu na przezroczysty i powiedzmy że ustawimy to na takiej zasadzie
aby before miał ujemny margines z prawej strony, na całą szerokość
i możemy przejść do stylowania faktycznego podświetlania gwiazdek

Stwórzmy sobie selektor, który będzie mówił,
że jeśli najedziemy myszką na jakąkolwiek labelke
to chcielibyśmy aby ona zmieniła się na kolor pomarańczowy

Możemy sobie zmienić ten literał,
używając colorpickera z Bracketsa.

Teraz w momencie gdy najedziemy myszką
na naszą labelkę, to widzimy, że nie podświetliła się nam ta gwiazdka
tylko ten tekst.

No, ponieważ musimy ustawić, że chcemy zmienić kolor
naszego atrybutu before, który znajduje się na tej labelce,
która jest najechana myszką.

Teraz jak widzimy, nasze gwiazdki podświetlają się
tam gdzie przejedziemy na nie myszką.

Natomiast fajnie byłoby w momencie gdy najeżdżamy na gwiazdkę nr. 4,
to chcielibyśmy aby wszystkie poprzednie również były podświetlone,
bo chcemy dawać 4 gwiazdki, tak?

Więc jeśli wybieramy czwartą gwiazdkę to zakładamy,
że wszystkie poprzednie również powinny się świecić
A więc jak zrobić taki selektor w samym CSSie?

Ponownie pobierzmy sobie labelkę,
która obecnie jest shoverowana, czyli jest na niej myszka
i pobierzmy wszystkie następne elementy,
które znajdują się na tym samym poziomie, czyli mają tego samego rodzica czy tzw. rodzeństwo,
używając do tego sibling selectora i znajdziemy wszystkie before'y na naszym elemencie label.

W momencie gdy podejrzymy jak to wygląda,
to widzimy, że faktycznie ten efekt uzyskaliśmy,
natomiast niestety nie w tą stronę, czyli jeśli podświetlamy drugą gwiazdkę to wszystkie inne oprócz pierwszej się podświetlają

Dlaczego tak się dzieje?
Ponieważ pobraliśmy wszystkie następne elementy before na znaczniku label a niestety w CSSie nie ma czegoś takiego jak previous sibling selector, czyli wszystkie poprzednie elementy z tego samego poziomu

Jak możemy to obejść? Możemy użyć do tego flexa i ustawić na naszym kontenerze flex-direction, nie na row domyślne tylko na row-reverse.

W tym momencie wszystko podświetla nam się bardzo fajnie,
jeśli zaznaczymy, że chcemy trzecią gwiazdkę to wszystkie trzy się nam podświetlą. Natomiast jest jeszcze jeden problem, który może nie będzie taki oczywisty, jeśli pokażemy sobie ten nasz tekst, który znajduje się wewnątrz labelek, to zobaczymy, że użytkownik myśli, że zaznaczy dwie gwiazdki, a tak naprawdę jest tu napisane, że zaznaczy cztery.

To wynika z tego, że nasz markup jest w takiej kolejności
i niezależnie czy flex będzie nam to rysował od prawej do lewej,
to i tak kolejność musimy zmienić.

Zrobimy sobie to szybciutko i teraz jak widzimy, kiedy użytkownik zaznacza sobie np. 3 gwiazdki, to faktycznie klika labelkę odpowiadającą inputowi o typie "radio", który wskazuje, że kliknęliśmy 3 gwiazdki.

Możemy znowu sobie ten kolor ukryć i teraz wszystko działa poprawnie,
natomiast jak klikniemy sobie te nasze gwiazdki to nie ma żadnego indykatora wizualnego, że tak naprawdę coś tutaj jest kliknięte
Stwórzmy sobie selektor, który nam to umożliwi.

Tym razem pobierzemy wszystkie inputy, które znajdują się w kontenerze .stars, które są zaznaczone, w tym przypadku będzie to jeden element,
ponieważ jeśli mamy wszystkie inputy o typie "radio" i każdy z nich ma ten sam atrybut name, wtedy tylko jeden input może zostać zaznaczony.

Oczywiście jeśli mielibyśmy tutaj inputy o innej nazwie, wtedy ten selektor może nie zadziałać, ale my zakładamy, że tylko takie się w tym markupie pojawią.

Więc pobraliśmy sobie tego inputa i chcielibyśmy aby wszystkie nasze następne labelki z tego samego poziomu,
podały nam swój pseudoelement before no i podświetliły go na ten kolor pomarańczowy.

Zobaczmy jaki będzie tego efekt.
Po kliknięciu w czwartą gwiazdkę, wszystkie pozostałe nam się podświetliły, oprócz tej czwartej i tak samo dzieje się z pozostałymi gwiazdkami, czyli jeśli klikniemy sobie pierwszą to nie widzimy, że cokolwiek jest kliknięte.

Dlaczego tak się dzieje?
Zobaczmy sobie na nasz selektor, szukamy sobie kontenera "stars"
Następnie szukamy wszystkich inputów, które są zaznacznone, powiedzmy że trzeci będzie zaznaczonym inputem, czyli szukamy sobie to jest input pierwszy, to jest input drugi i to jest input trzeci.

Znaleźliśmy go tj. linijka siedemnasta, następnie chcemy znaleźć wszystkie kolejne before'y na znaczniku label. To szukamy znaczników label, tu jest nasz znacznik label, czyli tj. pierwsza gwiazdka która nam się podświetli, tutaj mamy kolejny input więc go omijamy, tu jest kolejny label czyli już drugi, znowu input i koniec, to jest koniec kontenera "stars".

Więc mamy tylko dwie labelki, pomimo że zaznaczyliśmy gwiazdkę nr.3,
powinniśmy przenieść te nasze labelki poniżej inputów o typie "radio",
tak aby ten selektor mógł zadziałać i w tym momencie gdy klikniemy 3 gwiazdki to widzimy, że ten stan został zapisany i wszystkie 3 gwiazdki świecą się na pomarańczowo.

Oczywiście nasz selektor najeżdżania myszką również działa
Tak naprawdę moglibyśmy już usunąć tego naszego bordera
i nasz komponent wygląda już naprawdę ładnie,
ale nie widzimy czy znaczniki input są zaznaczone,
w tym momencie po prostu wierzymy, że selektory są napisane dobrze
i że faktycznie jest to zaznaczone.

Możemy sobie to sprawdzić przy pomocy odrobiny JavaScriptu,
więc dopiszmy sobie do pliku HTML.

Załadujmy sobie plik "script.js", on jest pusty w tym momencie, no i stworzymy sobie funkcję countStars, ona nie będzie nam liczyć tych gwiazdek tylko będzie pobierać wartość zaznaczonego inputa,
natomiast nazwa podaje nam liczbę gwiazdek, moglibyśmy to nazwać sobie np. getRating albo inaczej.

Więc pobieramy sobie nasz zaznaczony element radio, na obiekcie dokument wywołujemy querySelector i tutaj będziemy widzieli faktyczną siłę tej metody, ponieważ querySelector umożliwia pobranie konkretnego elementu bez żadnych operacji JavaScriptowych,
czyli nie musimy pobierać np. całej listy wszystkich znaczników input
i sprawdzać po kolei czy któryś z nich jest zaznaczony,
poprzez porównywanie wartości wewnątrz np. warunków.

Możemy stworzyć analogicznie selektor taki jak zrobiliśmy w CSSie,
czyli pobrać sobie z naszego kontenera '.stars input'
który będzie zaznaczony.

Pozostaje wpisać to tylko a konsolę,
czyli "checkedRadio.value" i w momencie gdy klikniemy nasz kontener "stars", to chcielibyśmy aby ta funkcja "countStars" się wykonała.

Więc zobaczmy jaki będzie efekt,
klikamy sobie na pierwszą gwiazdkę,
widzimy że zwróciło nam jedynkę,
klikamy na drugą gwiazdkę,
widzimy, że zwróciła się dwójka,
trójka, czwórka i piątka.

Oczywiście tutaj te zdarzenia wywołują nam się troszkę więcej razy niż byśmy chcieli, natomiast chodzi o to, że faktycznie te radio buttony zostały zaznaczone.

Jak widzicie CSS daje nam duże możliwości,
jeśli chodzi o tworzenie nawet skomplikowanych systemów wizualnych
i nie musieliście ładować żadnego pluginu JavaScriptowego
czy jQuery aby wykonać właśnie taki system oceny gwiazdkami.

Jest on, po pierwsze dobrze czytelny przez czytniki ekranowe,
a serwer www może łatwo obsłużyć taki formularz, w którym znajdowałby się taki element zbierający oceny od widzów czy też oczywiście użytkowników.

Co sądzicie o tym przykładzie?
Koniecznie dajcie nam znać w komentarzu i jeśli chcielibyście być na bieżąco z naszym materiałami, możecie też zasubskrybować nasz kanał.

Trzymajcie się i do zobaczenia w kolejnym ciekawym przykładzie

10 kwietnia 2022

Komentarz od autora

Ten materiał dobrze się zestarzał. Po ponad pięciu latach od jego nagrania, nie mam zbyt wielu uwag. Jedyne na co zwróciłbym uwagę, to kwestie dostępności. Faktycznie, przez zastosowane rozwiązanie gwiazdki mogą być czytane od tyłu (tj. 5, 4, 3, 2, 1 ) przez czytniki ekranowe. Nie musi to być problem, ale warto o tym pamiętać.

Druga kwestia, to koniecznie powinniśmy owinąć to rozwiązanie w poprawny formularz HTML, tak aby funkcjonował on zgodnie z ideą Progressive Enhancement, skoro obecne rozwiązanie nie wymaga ani krzty JavaScriptu.

Zobacz kod źródłowy

Nie mam nic do ukrycia! Eksperymentuj z moimi przykładami :) 

Poznaj Wojtka

Cześć! Nazywam się Wojciech Połowniak i jestem programistą Fullstack z zacięciem do tworzenia jakościowych materiałów szkoleniowych.

Uwielbiam automatyzację, VR oraz interaktywne sposoby przekazywania wiedzy. Tematy takie jak UX, dostępność czy devops również nie są mi obce.

Jestem też organizatorem meet.js oraz Techspeakerem pod banderą Mozilli... A to jeszcze nie wszystko.

Chcesz więcej?

Nie ma sprawy! Koduje to długie godziny darmowej treści dostępnej na wyciągnięcie ręki.

Newsletter

Jeśli chcesz być na bieżąco z najnowszymi inicjatywami od twórców koduje? Zapisz się na newsletter - nie spamujemy!

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

W przyszłości, możemy udostępnić Ci informacje o dodatkowych kursach naszego autorstwa.

Najczęściej zadawane pytania

Jaka tematyka jest poruszana na Koduje?
expand_more
Mówimy o HTML, CSS i JavaScript - zarówno na backendzie, jak i frontendzie. Tematyka taka jak Devops, architektura i infrastruktura oprogramowania również pojawią się na kanale!
Czy mogę zaproponować temat kolejnych wideo?
expand_more
Oczywiście, że tak! Najlepiej sugerować materiały w sekcji komentarzy na YouTube 
Jak to możliwe, że Koduje jest darmowe? 
expand_more
Moją pasją jest dzielenie się wiedzą w sposób zrozumiały i klarowny, jednocześnie interaktwny i angażujący. Tworząc materiały, utrwalam też własną wiedzę. Wierzę, że za to widzowie nie powinni płacić
W sieci można znaleźć strony przypominające do koduje.pl, o co chodzi?
expand_more
Niestety, na przełomie lat wiele osób próbowało podszyć się pod Koduje i wykorzystać nasze materiały do promocji własnych kanałów dystrybucyjnych.  Jeśli masz wątpliwości, czy dana strona współpracuje z Koduje - daj nam o tym znać. Nie pochwalamy piractwa, plagiatu ani szarej strefy prawa autorskiego.
Czy prowadzicie szkolenia indywidualne?
expand_more
W chwili obecnej, niestety nie. Na przełomie lat prowadziłem kursantów przez ich przygodę z programowaniem, z czego każdy otrzymał pracę jako programista. Jeśli jesteś zainteresowany lekcjami indywidualnymi, zapraszam do kontaktu mailowego.
Czy oferujecie płatne kursy?
expand_more
W przyszłości nie wykluczamy możliwości tworzenia dedykowanych kursów o danych zagadnieniach. Zapisz się na nasz newsletter, aby być na bieżąco z naszymi najnowszymi płatnymi materiałami.
Jak mogę się z wami skontaktować?
expand_more
Czytamy komentarze na YouTube! Śmiało możesz zadać pytanie na dowolny temat pod którymkolwiek z naszych wideo. Poza tym możesz skontaktować się z nami mailowo bądź poprzez fanpage na Facebooku
Obecnym właścicielem marki jest Wojciech Połowniak. Zobacz zakładkę o nas!