Взвешиваем селекторы CSS

    Ближе к двум часам ночи в голову в месте с мыслями о вечном приходят не менее вечные вопросы — «в чём смысл жизни ?», «зачем вообще человеку спать ?» или «Какого чёрта эта #%^$ не работает ?» и чем ближе утро, тем сильнее начинает волновать именно этот самый последний вопрос.

    Чуть ниже я расскажу о том какого чёрта сss селекторы иногда не ведут себя так, как нам кажется правильным, и о том как они на самом деле должны себя вести.


    Глава один – идём направо!


    Селекторы взвешивают, чтобы узнать какой из стилей будет примененен, когда несколько селекторов так или иначе указывают на один и тот же элемент, и пытаются изменить один и тот же его стиль. Кто больше весит того и стили, а законы взвешивания в тысячу раз проще тех, которые кажутся чисто эмпирически.

    Итак, взвешиваем — сначала представим пару рядов из 8 чисел:

    0,1,0,0,0,0,0,0
    

    1,0,0,0,0,0,0,0
    


    Знакомьтесь — так в числах выглядят некоторые два селектора, чтобы никто ни о чем не догадался назову их условно «верхний» и «нижний»

    Чтобы узнать какой из них тяжелее, нужно выполнить следующие действия и ничего не перепутать:
    1. Смотрим на крайние левые числа
    2. Выбираем из них большее. — именно этот селектор и будет самым тяжелым
    3. Если числа одинаковые, сдвигаемся на число вправо и повторяем инструкции из пункта 2.
    4. Если все числа одинаковые то применяются стили из селектора который был объявлен последним


    Самая страшная тайна


    Если вы это прочитаете, от вас навсегда уйдет душевный покой, но по крайней мере вы сможете спать по ночам.

    Раскрывая самую страшную тайну я расскажу, как собственно превратить обычный селектор в такие понятные и красивые цифры? Всё как всегда очень просто:

    1. Теги. за каждый тег в селекторе можно накинуть в самое правое число единичку:

      a – это 0,0,0,0,0,0,0,1
      div a – это  0,0,0,0,0,0,0,2
      

    2. Классы, за каждый класс или псевдокласс в селекторе можно накинуть по единичке во второе число справа

      .head .logo – это  0,0,0,0,0,0,2,0
      .logo.big  –    0,0,0,0,0,0,2,0
      div:first-child – 0,0,0,0,0,0,1,1
      .logog > .big – и это тоже 0,0,0,0,0,0,2,0
      
      

      Да, вы все верно поняли. Css селектор плевать хотел на все эти ваши изыски типа пробелов или «>».
    3. За каждый ID в селекторе добавляем по единичке в третье справа число.

      #head – это  0,0,0,0,0,1,0,0
      #head  #logo –  тоже  0,0,0,0,0,2,0,0
      


    Я думаю суть вы уловили, теперь можно приступать к небольшой викторине, чтобы это проверить:

    Викторина


    <head>
        <title></title>
        <style>
            span p
            {
                background-color: gray;
            }
            html p
            {
                background-color: red;
            }
        </style>
    </head>
    <body>
        <div>
            <span><p>?</p></span>
        </div>
    </body>
    

    Вопрос: Какого цвета бэкграунд будет в абзаце?
    Ответ: Правильно, красного, потому что селектор не волнует что вам там кажется, и расстояние между тэгами его не интересует. А так как вес тэгов равен – применится последний.

    <head>
        <title></title>
        <style>
            div.test1
            {
                background-color: gray;
            }
            div > .test1
            {
                background-color: yellow;
            }
            
            div .test1
            {
                background-color: red
            }
        </style>
    </head>
    <body>
    <div>
        <div class='test1'>?</div>
    </div>
    </body>
    

    Вопрос: Какого цвета бэкграунд будет в нашем диве?
    Ответ: Правильно, красного, потому что при измерении веса глубоко все равно поставили вы там пробел между классами, знак больше или написали их вплотную. Вес у всех этих селекторов одинаковый, а значит применится последний.

    <head>
        <title></title>
        <style>
            #id1 div
            {
                background-color: gray;
            }
    
            #id2
            {
                background-color: red
            }
        </style>
    </head>
    <body>
    <div id="id1">
        <div id="id2">?</div>
    </div>
    </body>
    

    Вопрос: Все тот же.
    Ответ: А ответ, для разнообразия другой: наш див будет серым. Потому что как я уже упоминал выше селектору абсолютно безразлично что вы там имели ввиду. У первого селектора вес больше, и никого не волнует что скорее всего ожидали вы не такого поведения.

    Продолжаем раскрывать секреты


    У нас осталось еще так много чисел, и наверняка так хочется узнать что же все они значат – продолжаем раскрывать секреты.
    1. Селектор * абсолютно невесомый, то есть совсем.
    2. Селектор атрибутов это самый обычный псевдокласс и весит он столько же сколько и обычные классы
    3. Любой инлайновый стиль написанный в атрибуте style=”” элемента автоматически получает приоритет0,0,0,0,1,0,0,0, что сразу делает его очень крутым.
    4. А следующие четыре цифры это все наши старые знакомые только с атрибутом !important

      div
      {
          background-color: gray !important;
      }
      
      Имеет вес при определении свойства background-color -  0,0,0,1,0,0,0,0
      
      .header 
      {
          background-color: gray !important;
      }
      
      0,0,1,0,0,0,0,0
      
      


    Все мы любим викторины


    <head>
        <title></title>
        <style>
        a.class1
        {
            color: blue;
        }
        a[href="#"]
        {
            color: green;
        }
        a[href^="#"] 
        {
            color: red;
        }
        </style>
    </head>
    <body>
    <a class="class1" href="#">?</a>
    </div>
    </body>
    


    Вопрос: Какого цвета будет знак вопроса в ссылке?
    Ответ: Красного, неважно что селектор на точное совпадение атрибута выглядит более специфичным, чем селектор который выбирает все что «начинается с». Вес они имеют одинаковый.

    <head>
        <title></title>
        <style>
            #id1
            {
                background-color: gray !important;
            }
        </style>
    </head>
    <body>
    <div id="id1" style="background-color: red;">?</div>
    </body>
    


    Вопрос: Мой оригинальный запатентованный вопрос.
    Ответ: !important круче всего, даже круче чем инлайн стили – так что бам-бам-бам – серого!

    Исходники всех тестов лежат тут

    P.S. немного порно

    <head>
        <title></title>
        <style>
            #id1
            {
                background-color: gray !important;
            }
        </style>
    </head>
    <body>
    <div id="id1" style="background-color: red !important;">red</div>
    </body>
    
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 38
    • +23
      Эрик А. Мейер «CSS-каскадные таблицы стилей. Подробное руководство», Глава 1
      • 0
        спасибо основой послужила другая книжка после которой у меня остались некотоыре вопросы. скачаю прочитаю отпишусь по впечатлениям :)
      • +3
        Зачем в начале 8 чисел, если используется всего 3?
      • +14
        Стало модно писать километровые статьи на элементарные темы, при этом даже не особо в них разбираясь.
        • +4
          потому и пишу — чтобы разобраться, и понять. если гдето накосячил дайте знать пожалуйста :)
        • +1
          Интересно, а какой вес по Вашей схеме имеют унаследованные стили?
          • 0
            Или вы меня непоняли или я вас :) я не писал ничего про наследование стилей( хотя полагаю что любой явно заданый стиль имеет приоритет перед унаследованным ) здесь я попытался написать всё, но только про вчисление веса селекторов.
          • +1
            «Да, вы все верно поняли. Css селектор плевать хотел на все эти ваши изыски типа пробелов или «>».»

            У меня было много раз, когда это:
            .test > .a {
            style: foo;
            }
            .test .a {
            style: foo2;
            }
            не работало (пока во втором не добавляешь >). Вы уверены, что селекторы знак ">" не учитывают?
          • 0
            А все что вы написали актуально для всех браузеров?
            • 0
              То что описал автор описано в стандарте CSS:
              www.w3.org/TR/CSS2/cascade.html
              так что браузеры должны прислушиваться к этому.
              • 0
                Я не спорю, что должны. Но так ли это? По крайней мере, в IE 7-8.
                • 0
                  Ну так проверьте и по результату отчитайтесь.
                  Или вам кто-то запрещает?

                  Селекторы по атрибуту в ie8 не работают.
                  Селекторы вида .foo.bar не работают в ie6.
                  • 0
                    >Селекторы по атрибуту в ie8 не работают.

                    И в IE8 и в IE7 селекторы работают по атрибуту.
                    input[type=«submit»]{color:red;}// IE7+
                    • 0
                      input[type="submit"]{color:red;}// IE7+ 
                      
                  • 0
                    >> Но так ли это?
                    А вот это интересный. Мне тоже это интересно.
              • 0
                Каскад — зло
                • +1
                  Зачем примеры выкладывать на GitHub?
                  jsFiddle подходит значительно лучше.
                  • +10
                    Статья про селекторы без картинки из звездных войн есть зло. www.stuffandnonsense.co.uk/archives/images/specificitywars-05v2.jpg — вставьте кто-нибудь, ибо кармы не хватает…
                    • +10
                      Запросто:
                      • +1
                        Надо добавить инлайн, даже не знаю кто там будет в роли инлайна выступать. + импортант.
                    • +3
                      Я запомнил это так:
                      тег — единицы
                      класс — десятки
                      id — сотни
                      В результате получается:

                      html div #test1 .test2 #test3 = 212
                      #test1 #test2 #test3 = 300 (этот и будет применен)

                      • –3
                        Как прекрасно, что БЭМ позволяет почти не задумываться о таких неинтуитивных вещах :)
                        • +1
                          Это нужно знать когда пытаешься переопределить стиль, а он не срабатывает =) В свое время я тоже ломал голову почему мой класс не применялся jsfiddle.net/Fv5K8/
                          • 0
                            В БЭМ нет каскада, а значит не надо ломать голову над переопределением стилей. Всегда применяется последнее правило.
                            • +1
                              Это неправильное отношение к вещам: я эту часть вещей не использую, поэтому знать их не буду. В пхп не пишу классами, значит ооп учить не буду, в JS использую только jQuery значит нативный JS учить не буду, итд.
                              Это базовые понятия цсс и знать их обязан человек который работает с цсс, эти базисы описаны в каждой книге по цсс в первых главах.
                              Не всю же жизнь работать с БЭМ? Придет время и «я с этим не работал поэтому не знаю» не прокатит, особенно когда имеются ввиду самые основы.
                              • 0
                                Вообще-то, я не о том, что этого знать не нужно, а о том, что «как хорошо, что этим замысловатым каскадом можно не пользоваться благодаря методологии БЭМ».
                                • 0
                                  БЭМ — частный случай работы только с классами. В любом случае иногда удобно делать иерархию. При чем я не могу сказать что каскады — неинтуитивные. В паскале присоить значение переменной — := это не интуитивно только тем кто этого не знает. Если писать акуратно, то каскады будут так же понятны и интуитивны как и БЭМ, а по глупости можно и в БЭМ делов натворить таких что черт ногу сломит.
                        • +1
                          Хм. Всегда придерживался такого правила: «Разработчики стандартов скорее всего не идиоты и придерживаются логики и здравого смысла. Я тоже не идиот и поэтому буду придерживаться логики и здравого смысла, который заключается в том, что [b]чем точнее(подробней) или ближе(`физически`) описание к самому элементу, находящемуся в рамках определенной последовательности, при прочих равных — тем правило тяжелее[/b]».
                          Ну, вообщем, проблем не возникало. Хотя допускаю, что логика может быть несколько нарушена, если человек часто работает с какими нибудь не очень то «логичными» вещами, и у него выработались определенные правила, то вполне логично может выглядеть и другой взгляд. И поэтому, статья скорее годная чем наоборот)
                          Не вижу повода для скептики, уважаемые гуру.
                          • 0
                            Эти вещи в спецификациях описаны, да и опытным путём выясняются запросто после нескольких «Какого чёрта эта #%^$ не работает ?»
                            • 0
                              Неужели каскадирование и специфичность — это страшные тайны?) Кстати, автор забыл указать про весомость селекторов из стилей автора, стилей пользователя и браузерных стилей. Там есть довольно интересные грабли относительно !important.
                              • 0
                                с этим я просто не сталкивался, хотя это наверно интересно да. а вот например то что селектор задающий стили всем потомкам какогонибудь айдишника(id1) весомее селектора напрямую выбирающего айдишник(id2) одного из этих потомков — не всегда кажется таким уж очевидным :)) или пока не проверил я не знал что весомее .class1.class2 или .class1(пробел).class3 — пока не проверил :) так что некоторые вещи для меня были дейтсвительно тайной и даже пишут о них совсем не часто :))
                              • 0
                                Спасибо огромное! Учту.
                                • 0
                                  <irony>Порно у Вас красное :-)</irony>
                                  • 0
                                    ты забыл про псевдоклассы типа :active и :hover
                                    • 0
                                      Если сейчас добрая половина постов этом блоге повергает меня в ужас и отчаянье, и заставляет думать, что за полтора года я безнадежно отстала от верстки и возвращение будет стоить немалых усилий; то преподносимый как откровение пересказ куска спецификации прямо возвращает веру в себя и настраивает на позитивный лад.
                                      А я-то испугалась, что за восемь позиций? А всё так банально.
                                      • 0

                                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.