Ta strona używa cookies
sprawdź politykę prywatności

Rozumiem

Dlaczego !important jest dla słabiaków? Specificity w CSS.

21/5/2019
Bartek Cis

Chcesz poradzić sobie ze stylowaniem aplikacji w CSS i uniknąć użycia wyrażenia !important? Zrozum Specificity a życie stanie się łatwiejsze.

Czego się dzisiaj dowiesz?

Dzisiaj opiszę czym jest specyficzność czyli Specificity w CSS. Jeśli jeszcze go nie znasz to pomogę Ci je zrozumieć. Jestem przekonany, że zdecydowanie pogłębi to Twoją ogólną wiedzę o budowie aplikacji.

W następnej części pokażę jak radzić sobie ze stylowaniem bez użycia wyrażenia !important. To prawdziwy hack 🙂

Dlaczego o tym piszę?

Kochasz wyrażenie !important w CSS? A może to trudna miłość bo momentami potrafi być uczuciem wręcz przeciwstawnym? Kto nie widział CSS’ów aplikacji “zapaćkanych” tym wyrażeniem? To naprawdę utrudnia życie wszystkim którzy budują aplikację obecnie i będą to robić w przyszłości.

Wszystko zaczyna się od braku znajomości CSS a konkretnie pojęcia Specificity ale jeśli nawet ktoś ma mgliste zrozumienie tej zasady a nie potrafi jej wykorzystać do własnych celów tu wtedy… używa !important. A potem to jest już tylko gorzej…

Specificity

Czyli po polsku Specyficzność. Jeśli dany selektor w CSS jest bardziej specyficzny to jest on traktowany jako ważniejszy. Wtedy interpreter CSS użyje tego stylu do elementu opisanego tym selektorem.

Podobnie jest w życiu. Im programista ma bardziej specyficzny, nerdowski wygląd to jest ważniejszy w stadzie. Jest większa szansa, że pójdzie do lepszego projektu lub będzie zarabiał więcej.

Dobra już całkiem poważnie. Specificity przyjmuje trójelementową skalę 0-0-0 gdzie elementy z lewej są bardziej specyficzne / ważniejsze niż te z prawej:

Więc każdy selektor ma jakąś swoją wagę.

Specificity 0-0-0

Selektor globalny * , kombinatory +, >, ~, ‚ ‚, ||, selektor negacji :not().

Specificity 0-0-1

Wszystkie selektory podstawowe (typu) np. div, p , body itp. oraz pseudo-elementy :before i :after

Specificity 0-1-0

Selektory klas np. .form , selektory atrybutów np. [name] , pseudo-klasy np. :focus czy selektory strukturalne jak np. :last-of-type.

Specificity 1-0-0

Te selektory mają największą wagę. Są to te które używają id np. #form-button.

Jak widzisz stylowanie po ID nie tylko wyłamuje się od ogólnej konwencji i jest nie spójne z resztą CSS ale też zaburza hierarchię (bo je nadpisuje) niemal wszystkich innych styli które piszesz. Dlatego jest to złą praktyką.

Jeżeli chcesz dowiedzieć się więcej na ten temat to sprawdź MDN.

Jak obliczać Specificity?

To jak już wiesz jak przypisywać Specificity możesz obliczyć wagę każdego selektora:


Po prostu sumuje się wszystkie elementy w obrębie całego selektora i porównuje ze sobą. Ten styl który ma najwyższą wartość zostanie użyty. Jeżeli dwa elementy posiadają taką samą wartość to zostanie użyty ten który zdefiniowano później ( zasada Cascaded w CSS 🙂 ).

Ja pracuje na Visual Studio Code i po najechaniu na dany selektor pięknie wyświetla mi wyliczone Specificity:

Specificity i SASS

Oczywiście wszystko ciągle obowiązuje gdy używasz np. SASS’a. Tamtejszy kod jest potem kompilowany do CSS.

Sprawa się trochę komplikuje gdy używasz np. Styled Components czyli “CSS in JS”. Sam nie jestem pewien ale to się chyba wtedy kompiluje do inline-styles (o tym za moment) i określenie Specificity może być trudniejsze…

Swoją drogą sam niedawno robiłem projekt w GatsbyJS przy użyciu Styled Components i rzeczywiście ichniejszy moduł do CSS wywalał mi dziwne bobki… Pewnie ten kalkulator Specificity nie działał zbyt precyzyjnie (albo ja go źle używałem…).

Koncepcja Specificity

Choć na pierwszy rzut oka może się to wydawać nieco zawiłe to w zasadzie jest bardzo proste. Po prostu daj sobie chwilę aby to przemyśleć 🙂

Jeśli piszesz już od jakiegoś czasu CSS to napewno intuicyjnie czułeś/aś, że jest gdzieś taka zasada.

Inline Styles

Czyli coś takiego:

Jeżeli zobaczysz style zdefiniowane z poziomu kodu HTML to wiedz, że mają specificity 1-0-0-0 są więc ważniejsze od wszystkich (no prawie 🙂 ) reguł zdefiniowanych w pliku .css.

Wszelkie modyfikacje CSS dokonane z poziomu JavaScript są właśnie inline styles. Nadpisują pozostałe CSS’y.

!imporant

I tu się zaczyna zabawa 🙂 Ta właściwość ma specificity 1-0-0-0-0 czyli nadpisuje wszystkie style które zostały zdefiniowane w innych miejscach!

Jeśli ktoś już kiedyś użył tego wyrażenia próba naprawienia może być zbyt ryzykowna (np. w przypadku produkcyjnej aplikacji) i kolejni developerzy powielają ten błąd. Bo co innego mają robić? Ale jak uniknąć takiego scenariusza?

Case Study

Zobacz jak może rozpocząć się reakcja łańcuchowa… Będzie to uproszczony przykład aby tylko oddać całą sytuację.

Janek

Dostał zadanie odświeżyć wygląd formularza aplikacji w której pracuje. Jest to dość duży projekt więc struktura plików .css też jest skomplikowana. Szczerze mówiąc trochę się to już wszystko pomieszało jak kolejne osoby dopisywały różne rzeczy tu i tam…

Chce zrobić wszystko zgodnie ze sztuką, używa tylko selektorów klas (jak wszyscy przed nim) i konwencji BEM.

Kod

Zastaje takie style:


Zastanawia się po co ktoś miałby dodawać te selektory atrybutów (w zasadzie ma rację bo nie służą one niczemu w tym wypadku. Komplikują tylko sytuację). Postanawia je ominąć i dodaje taki kod:


Choć nowy styl powinien działać bo jest pod starym to się tak nie dzieje… Janek nie wie o co chodzi i w końcu postanawia dodać !important:


Jako, że inni członkowie nie znają dobrze CSS ( bo po co? ) taka zmiana wpleciona w jeszcze kilka innych przechodzi Code Review i mina zostaje podłożona…

Gdzie jest problem?

Janek nie wiedział, że stary kod miał specificity 0-2-0 (ciekawe czy wiedział to jego twórca) a jego modyfikacja nie mogła zadziałać bo miała tylko 0-1-0. Dodał !important otrzymując 1-0-0-1-0 osiągając cel ale utrudnił pracę sobie i innym.

Hack dla !important

Co mógł zrobić Janek w takiej sytuacji zamiast używać !important? Poczytać o specificity i zrobić to np. tak:


Ale sytuacja nie zawsze jest tak oczywista mógłby więc namierzyć źródło starych styli, dowiedzieć się jaką mają wagę i zrobić coś takiego:


Powtórzenie tej samej nazwy klasy daje nam dodatkowy punkt specificity. Powyższy przykład ma siłę 0-3-0 więc wystarczająco aby nadpisać stary styl 🙂 Po co komu !important?

@keyframes

Jeżeli chcesz nadpisać !important możesz też użyć haka z animacją. Gdzie zmieniasz daną właściwość za pomocą animacji np. z 1 powtórzeniem. Generalnie nie polecam tylko wspominam jako ciekawostkę 🙂

Podsumowanie

Specificity to super właściwość która pozwala na rozwiązywanie wielu problemów przy tworzeniu wizualnej szaty aplikacji. Jej dobre zrozumienie wprowadza Cię na wyższy level w kontekście CSS.

Współczesne edytory IDE same obliczają Ci specificity dla poszczególnych selektorów. Wystarczy sprawdzić 🙂

Użycie reguły !important jest w większości przypadków bezzasadne. Następnym razem zastanów się nad innym rozwiązaniem jak natrafisz na trudności przy stylowaniu aplikacji.

Podziel się z innymi 🙂

Cześć jestem Bartek.

Na tym blogu wprowadzę Cię w tajniki Front-Endu i programowania webowego.

Warto
Social media & sharing icons powered by UltimatelySocial