Blog webdeveloperski Patryk yarpo Jar

Specyficzność selektorów CSS

Autor wiadomości Maj 28, 2013

Każda większa strona internetowa posiada duży (lub bardzo duży) zbiór reguł CSS, czasem umieszczonych w kilku plikach. Do tego nierzadko znaleźć można dodatkowe reguły wklejone w znaczniku <style />, a także wstrzyknięte inline definicje przez atrybut `style' znaczników HTML (styl wewnętrzny).

Nie jest niczym dziwnym, że do jednego elementu w takich ogromie kodu zostanie przypasowana więcej niż jedna reguła. Może się zdarzyć, że reguły będą definiować te same właściwości wyglądu elementu w różny sposób. Jak w takiej sytuacji dojść do tego jak powinien wyglądać dany element? Odpowiedzią jest specyficzność (ang. specificity) każdego z selektorów. Można się także spotkać z określeniem "precyzja selektorów". W przypadku kilku deklaracji będących ze sobą w konflikcie (np. 3-krotnej definicji koloru tekstu) wybrana zostaje ta definicja tego selektora, który ma najwyższą specyficzność.

Wartość specyficzności (precyzja selektorów)

Wartość specyficzności wyliczana jest podobnie do klasyfikacji medalowej. Zamiast koloru medalu liczy się tu jednak co innego:

|styl wewnętrzny|   |id|   |class/pseudo-klasa/wybór atrybutu|    |element/pseudo-element|

Czyli specyficzność 0, 0, 0, 0 oznacza, że selektor nie posiada żadnej specyficzności. Natomiast 0, 1, 3, 4 oznacza np. taki zapis:

body#wrapper div.small a.bottom span.wide { color: red; }

Policzmy:

  • 1 identyfikator w selektorze
  • 3 klasy w selektorze (pseudo-klasa, np. :hover ma taką samą "moc". Zobacz przykład)
  • 4 nazwy elementów lub pseudo-elementów (zamiast którejś z nazw elementów mógłby być  pseudo-element - ma taką samą "moc")

Powyższy selektor mógłby dotyczyć np. takiego kodu HTML:

<body id="wrapper">
    <div class="small">
        <a href="#" class="bottom">
             <span class="wide">Tekst koloru czerwonego</span>
        </a>
    </div>
</body>

demo online

Co oznacza "styl wewnętrzny"?

Załóżmy, że kod z powyższego przykładu wzbogacimy:

<span class="wide" style="color: blue">Tekst koloru czerwonego? Nie, jestem niebieski.</span>

demo online

Co się stało? Styl wewnętrzny zawsze są ważniejsze niż jakiekolwiek definicje stylów w regułach przypisywanych elementom poprzez selektory.

Kod podany w atrybucie `style' (styl wewnętrzny) otrzyma specyficzność równą: 1, 0, 0, 0. Czyli wygra z (prawie) każdą regułą przypisywaną za pomocą selektorów. Przypadek, kiedy nie wygra zostanie opisany niżej. Warto jednak pamiętać, że do tego elementu zostaną przypisane wszystkie właściwości, z tym że wartość podana w atrybucie nadpisze wcześniejsze. Gdyby w naszej regule podać więcej właściwości (np. pogrubiony tekst) to style wewnętrzne (póki nie zdeklarują innej wartości tej właściwości) nie zmienią ich.

demo online

Warto tu też zauważyć, że specyficzność 1, 0, 0, 0 jest ważniejsza od 0, 10, 0, 0, a ta z kolei wygrywa z 0, 0, 0, 1000000000. Podobnie jak we wcześniejszym porównaniu do klasyfikacji medalowej. Jeden złoty medal to więcej niż 100 brązowych. Jeden styl wewnętrzny jest ważniejszy od 100 identyfikatorów w selektorze czy też od miliona elementów.

Wybór atrybutu

Być może pierwszy raz się z czymś takim spotykasz. Chodzi o możliwość wskazania wartości atrybutu elementu, np.:

<a href="/index.php">Home</a>

Do takiego elementu zostanie dopasowany następujący selektor:

a { color: green; } /* 0,0,0,1 */

Można jednak przypisać bardziej specyficzny selektor:

a[href="/index.php"] { color: yellow; } /* 0,0,1,1 */

demo online

Kilka innych przykładów związanych z wychwytywaniem elementów za pomocą wyboru atrybutów można przeczytać w dawnym wpisie:

Co z selektorem uniwersalnym oraz selektorami kontekstualnymi?

Selektor uniwersalny, czyli `*' ma wartość 0, 0, 0, 0. Oznacza to tyle, że element przyjmie wartości przypisane w takiej regule, ale ich zmiana wymagać będzie dowolnego selektora.

Selektory kontekstualne:

body > p { color: yellow; } /* <body> będące bezpośrednim rodzicem <p>: 0, 0, 0, 2 */
p + p { font-weight: bold; } /* <p> występując obok <p> (rodzeństwo): 0, 0, 0, 2 */

Występowanie selektorów kontekstualnych nie wpływa na wartość specyficzności selektora.

Uwaga, to jest !important (sic!)

Czasem zdarza się, że chcemy coś zdefiniować raz a dobrze i uniemożliwić późniejszą zmianę wyglądu danego elementu nawet poprzez styl wewnętrzny. Choć nie jest to polecany sposób i należy pomyśleć 5 razy nim się wykorzysta ważne deklaracje (ang. important declarations), to czasem okazują się one bardzo przydatne.

CSS:

a { color: green !important; } /* 0,0,0,1 */
body#wrapper p#my-text.very-important a[href="/index.php"] { color: yellow; } /* 0,2,1,3 */

HTML:

<body id="wrapper">
    <p id="my-text" class="very-important">
        <a href="/index.php" style="color: blue">Home</a>
    </p>
</body>

Z rachunku specyficzności wynika, że link powinien być żółty (ang. yellow). Ale zaraz, zaraz - dodaliśmy style wewnętrzne. Zatem będzie to kolor czarny (ang. black). A jak sądzisz, jaki będzie?

demo online

Zielony?! Jakim cudem? Tak właśnie działa ważna deklaracja. Po raz kolejny przestrzegam przed jej nadużywaniem. Z pewnością czasem przyda Ci się też Firebug pokazujący, która deklaracja stylów jest przypisana do danego elementu.

Co w przypadku remisu?

Może się zdarzyć, że dwie lub więcej selektorów ma taką samą specyficzność. Co wtedy?

Prosty algorytm [1]:

  1. Deklaracje użytkownika oznaczone jako `!important'
  2. Deklaracje autora oznaczone jako `!important'
  3. Normalne deklaracje autora
  4. Normalne deklaracje użytkownika
  5. Deklaracje oprogramowania użytkownika (np. przeglądarki)

Gdy i to nie jest wystarczające - kolejność wystąpienia danej reguły. Im bliżej użycia tym ważniejsze, np.:

a { color: red; } /* 0,0,0,1 */
a { color: blue; } /* 0,0,0,1 -> mimo wszystko linki będą niebieskie */

demo online

Warto przeczytać:

  1. http://www.yarpo.pl/2011/04/08/ksiazka-css-kaskadowe-arkusze-stylow-przewodnik-encyklopedyczny-wydanie-iii/
  2. wszystko Erica Meyera
  3. http://www.w3.org/TR/selectors/#specificity
  4. http://reference.sitepoint.com/css/specificity
Komentarze (0) Trackbacks (0)

Brak komentarzy.


Leave a comment

 

Brak trackbacków.