Каскадность CSS. Приоритеты стилей. CSS каскадирование, специфичность, наследование: что это и как правильно использовать

Любой профессионал своего дела должен владеть терминологией. Если Вы занимаетесь версткой, можете ли без раздумий ответить на вопрос в заголовке статьи?

Возможно сейчас вы откроете для себя что-то новое. Давайте сделаем решительный шаг на пути к профессионализму:)

Наследование

Начнем с самой простой для понимания концепции CSS. Суть ее состоит в том, что стили, присвоенные некоторому элементу, наследуются всеми потомками (вложенными элементами), если они не переопределены явно. Например, размер шрифта и его цвет достаточно применить к дескриптору body чтобы все элементы внутри имели те же свойства. Но, для заголовков h1-h6 размер шрифта не будет присвоен, потому что у браузера для них есть своя таблица стилей по умолчанию, а наследованные стили имеют самый низкий приоритет. Аналогичная ситуация с цветом ссылок.

Таким образом, наследование позволяет сократить таблицу CSS. Но в то же время если стилей много, то отследить какой родительский элемент установил некоторое свойство, становится довольно сложно.

Каскадирование

Правила каскадирования позволяют разрешать ситуации, когда для одного элемента прописано несколько стилей. Каскадирование основано на присвоении некоторого приоритета каждому правилу. Авторские таблицы стилей имеют самый большой приоритет, меньший — пользовательские, самый низкий — таблицы стилей по умолчанию браузера. У пользователя есть возможность переопределить авторское правило путем добавления флага!important к своему.

Правила каскадирования определяют следующие приоритеты:

  1. пользовательские стили, отмеченные!important
  2. авторские стили, отмеченные!important
  3. авторские стили
  4. пользовательские стили
  5. стили по умолчанию

После каскадирования правила упорядочиваются на основе специфичности селекторов.

Специфичность

Специфичность — это некоторое число в системе с неопределенно высоким основанием, которое является отражением приоритета какого-либо правила. Вычисляется оно на основе специфичности каждого из селекторов, входящих в правило CSS.

Специфичность селектора разбивается на 4 группы — a b c d:

  • если стиль встроенный, т.е. определен как style="", то а=1
  • значение b равно количеству селекторов идентификаторов
  • значение c равно количеству классов, псевдоклассов и селекторов атрибутов
  • значение d равно количеству селекторов типов

Пример вычисления специфичности:

Селектор Специфичность Специфичность в системе
с основанием 10
Style="" 1,0,0,0 1000
#wrapper #content {} 0,2,0,0 200
#content .datePosted {} 0,1,1,0 110
div#content {} 0,1,0,1 101
#content {} 0,1,0,0 100
p.comment .datePosted {} 0,0,2,1 21
p.comment {} 0,0,1,1 11
div p {} 0,0,0,2 2
p {} 0,0,0,1 1

Неопределенно высокое основание системы счисления является следствием того, что неизвестно заранее, насколько большими будут числа a, b, c, d. Если они меньше 10, то удобно использовать десятичную СС.

Как и любая моя статья, эта начинается с введения. Дабы не говорить на разных языках, начнём с самых основ в мире CSS, то есть с терминологии. Чувствую себя преподавателем в университете - как же это круто.

Для того чтобы успешно разбираться в CSS и стать крутым специалистом в этой области, нужно первым делом разобраться с тем, что называют селектором. На изображении ниже представлена простейшая структура CSS-правила.

Селектор - это строка, представляющая собой формальное описание структуры, на основе которого выбирается элемент или группа элементов в дереве документа и применяется объявленный блок свойств.

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

Я не буду вдаваться в подробности того, что селекторы должны начинаться с буквы и некоторых других символов. Я также не буду говорить про неинтересные прописные истины, которые можно найти в любой статье на тему основ CSS. Речь в этой статье пойдёт про вес CSS-селекторов, а если говорить простым языком - о его числовом представлении и понимании.

Вес селекторов

Нет, здесь не идёт речь об их реальном весе (его нет), а также о количестве символов. Такой вес нельзя измерить весами, так как он не вещественен в обычном понимании и вообще не существует в нашем с вами мире людей. Зато он есть в виде нулей и единиц. Получается, что селектор можно взвесить, используя некую систему, о которой мы и будем говорить дальше.

Что такое вес селектора?

Вес селектора - это условные четыре позиции x, x, x, x , которые заполняются нулями и единицами в соответствии с содержимым селектора. Каждая из позиций имеет своё содержимое:

  • Инлайн стили
  • Идентификаторы
  • Классы, атрибуты и псевдоклассы
  • Теги и псевдоэлементы

Как это читать?

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

Как заполнять?

H1 { color: #777; }

В этом примере селектором выступает заголовок h1 , который состоит из одного тега. Получается, что напротив столбца «тег» мы ставим единичку. Получается следующая картина: 0, 0, 0, 1 .

Всё это замечательно, но в реальных проектах встречается разве что в ядре стилей или normalize , а это значит, что нужно усложнить задачу.

#main .container article.post > header h1.giga { color: #777; }

Пример получился хардкорнее, чем предыдущий и в реальной жизни достоин премии «самого избыточного селектора». Такая избыточность должна преследоваться по закону, но подробнее на эту тему мы поговорим в отдельной части статьи. Окей, вернёмся к примеру и немного поработаем весами.

Давайте начнём слева, так как в начале стоит единственный идентификатор #main . Далее мы видим три класса.container , .post и.giga , а также три тега article , header и h1 . Для ещё большей наглядности я распишу это в виде этапов:

// Селектор #main .container article.post > header h1.giga // Начальный вес 0, 0, 0, 0 // Идентификаторы #main 0, 1, 0, 0 // Классы, атрибуты и псевдоклассы.container 0, 1, 1, 0 .post 0, 1, 2, 0 .giga 0, 1, 3, 0 // Теги и псевдоэлементы article 0, 1, 3, 1 header 0, 1, 3, 2 h1 0, 1, 3, 3 // Итог #main .container article.post > header h1.giga => 0, 1, 3, 3

Давайте напишем какой-нибудь безбашенный селектор, который я, надеюсь, никогда не увижу ни у кого в коде:

// Селектор body.page-posts #main .container article.post ul.list-unstyled > li:first-child h2.article-title:hover { color: #333; } // Начальный вес 0, 0, 0, 0 // Идентификаторы #main 0, 1, 0, 0 // Классы, атрибуты и псевдоклассы.page-posts 0, 1, 1, 0 .container 0, 1, 2, 0 .post 0, 1, 3, 0 .list-unstyled 0, 1, 4, 0:first-child 0, 1, 5, 0 .article-title 0, 1, 6, 0:hover 0, 1, 7, 0 // Теги и псевдоэлементы body 0, 1, 7, 1 article 0, 1, 7, 2 ul 0, 1, 7, 3 li 0, 1, 7, 4 h2 0, 1, 7, 5 // Итог body.page-posts #main .container article.post ul.list-unstyled > li:first-child h2.article-title:hover => 0, 1, 7, 5

Ну и напоследок, для полного понимания темы, будет пример с атрибутами и псевдоэлементами.

// Селектор.main:before { content: "3 .column.size-1of3"; } // Начальный вес 0, 0, 0, 0 // Идентификаторы 0, 0, 0, 0 // Классы, атрибуты и псевдоклассы.main 0, 0, 1, 0 0, 0, 2, 0 // Теги и псевдоэлементы:before 0, 0, 2, 1 // Итог.main:before => 0, 0, 2, 1

Вот такие вот дела.

На самом деле, тема очень простая, но очень важная на практике для посредственного (минимального) понимания того, как браузер определяет какой блок объявлений необходимо применить к тому или иному элементу на странице.

А что, если вес селекторов одинаковый?

Допустим, что у вас есть два или несколько селекторов так или иначе указывающих на один и тот же элемент. И вот так сложилось, что вы посчитали или просто взглянули на них, и вес оказался одинаковым. Не стоит отчаиваться, просто блок объявлений последнего селектора в вашем CSS-коде из этой группы и будет применяться к элементу. Как-то так. Мне кажется это логичным. Прямо как в поговорке «кто не успел, тот опоздал», но наоборот: «кто опоздал, тот и успел».

Зачем это нужно?

Это очень интересный момент, ибо понять какой блок объявлений будет применяться к элементу, можно и без расчёта веса селектора, то есть просто посмотрев на него и слегка подумав. Однако, глазомер может подвести, а вот машина не подведёт, посчитает вес и испортит вёрстку. Ошибка, конечно, не машины, а прослойки между компьютером и стулом, но это уже совсем другая история.

Ещё одним применением такого вот расчёта являются сервисы или скрипты, которые строят диаграммы специфичности CSS. Это может быть очень удобно для анализа и оценки избыточности вашего кода.

Интересным фактом будет то, что единственный раз, когда мне приходилось считать вес селектора, был тестом от Mail.ru на какой-то сертификат. Если интересно, то я поищу этот тест у себя в истории.

Ох, специально для вас у меня есть сервис, на который я наткнулся при подготовке к изложению этого материала: Specificity Calculator - это простой и эффективный калькулятор веса селекторов.

Специфичность селекторов

Раз уж зашла речь про вес CSS-селекторов, то неизбежно задумываешься о том, как бы его оценить: когда нужно ему худеть, а когда наоборот - поправляться. Как и у человека, у селекторов всё таки есть оптимальный вес.

Так сложилось, что многие веб-разработчики считают оптимальной специфичностью селекторов три вложения. Максимальной специфичностью селекторов называется пять вложений и рекомендуется стараться это число не превышать. Разумеется, вложений может быть и больше, так как в жизни всякое бывает. Хотя, лучше всего, если вы всё таки будете соблюдать эту рекомендацию хотя бы косвенно. Такой подход вам поможет сэкономить время в будущем.

Хорошо, всё это замечательно, но причём тут вес? - да очень просто, он напрямую от этого зависит. Чем больше вложений, тем больше вес. Логично, однако.

Оценить ваш CSS-код можно с помощью ресурса CSS Specificity Graph Generator . По предложенному вами CSS-коду строится интерактивный график специфичности вашего кода, на котором можно визуально определить проблемные участки ваших стилей.

Выводы

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

В данной главе подробно объясняется, почему каскадные таблицы стилей (Cascading Style Sheets, CSS) называются каскадными. Для начала давайте вспомним, какими способами можно добавить стиль на веб-страницу:

  • подключить внешнюю таблицу стилей;
  • добавить внутреннюю таблицу стилей в HTML-документ через тег . В итоге цвет тегов

    Будет красным.

    Это – один из способов управлять значимостью стилей. Еще один способ повысить приоритет – специально увеличить вес селектора, например, добавив к нему ID или класс.

    Объявление!important

    Если вы столкнулись с экстренным случаем и вам необходимо повысить значимость какого-либо свойства, можно добавить к нему объявление!important:

    P {color: red !important;} p {color: green;}

    Также!important перекрывает inline-стили. Слишком частое применение!important не приветствуется многими разработчиками. В основном, данное объявление принято использовать лишь тогда, когда конфликт стилей нельзя победить иными способами.

    Сброс стилей с помощью reset.css

    В предыдущей главе мы уже упоминали о том, что у каждого браузера есть свои встроенные стили HTML-документов, созданные для улучшения читабельности. Вы наверняка уже видели, как выглядит «голая» веб-страница в браузере: синие подчеркнутые ссылки, черный шрифт, полужирное начертание заголовков и т. д.

    Каждый браузер имеет свои отличия во встроенных стилях: например, в IE нет отступа от верхнего края окна, а в Firefox есть. Таких отличий существует много. Чтобы они не создавали помех для кроссбраузерности при написании собственного стиля CSS, можно воспользоваться методом сброса встроенных стилей.

    Инструмент для сброса стилей – это, по сути, та же самая таблица CSS, где описаны правила, которые сбрасывают встроенные стили браузеров, устанавливая базовые значения свойств. Называется такая таблица reset.css и служит для того, чтобы вы могли начать создавать стиль «с нуля». Вот пример стандартной таблицы сброса:

    Html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; } /* HTML5 display-role reset for older browsers */ article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } body { line-height: 1; } ol, ul { list-style: none; } blockquote, q { quotes: none; } blockquote:before, blockquote:after, q:before, q:after { content: ""; content: none; } table { border-collapse: collapse; border-spacing: 0; }

    HTML — основа всех веб-сайтов, служит для размещения основного контента на сайте. Если запустить HTML код в браузере, то можно увидеть текст, картинки и ссылки, которые не особо радуют глаз. Чтобы сделать красивые элементы и создать хороший дизайн веб-страницы нужно воспользоваться CSS

    CSS — язык стилизации веб-элементов. Он берет отдельную часть контента или всю страницу целиком, изменяя её визуальную составляющую. Чтобы свойства CSS применялись, им нужно на что-то ссылаться. Для этого используются селекторы, которых существует огромное множество.

    Селекторы. CSS

    Селекторов существует огромное количество, от общих(ссылающихся на все элементы веб-страницы) до тегов, классов и идентификаторов.

    Общие селекторы

    "*" — основной селектор в CSS. Он ссылается на каждый элемент веб-страницы находящийся в теге {body}. Чаще всего используется для обнуления отступов на странице:

    CSS

    Скопировать

    Селекторы тегов. CSS

    Данный селектор ссылается на каждый указанный тег. Например, если задать изменение шрифта для тегов p, то каждый параграф будет иметь этот стиль. Классы и идентификаторы используются чаще, но теги тоже имеют широкое применение. Например, когда нужно задать общие стили для тега body — шрифт, фон, отступы и т.д.

    CSS

    body {

    font-family: "Tahoma", serif;

    Скопировать

    Селекторы id. CSS

    Идентификаторы используются чаще чем обращение ко всем тегам. В основном, они используются для уникального элемента веб-страницы, который имеет индивидуальный дизайн. Это обусловлено тем, что один идентификатор можно задавать только для одного элемента страницы.

    Через id можно обращаться и к другим элементам, используя его как родительский селектор. Об этом позже.

    Чтобы использовать селектор идентификатора, задайте его в html, с помощью атрибута id. Введите его в css документе с решеткой вначале, без пробелов.

    HTML

    Тестовая страница

    Hello World!

    Любой тестовый текст

    Скопировать

    В CSS выглядит как:

    CSS

    body {

    font-family: "Tahoma", serif;

    background-color: rgba(235, 52, 52, 0.52);

    color: rgba(255, 255, 255, 0.71);

    #head {

    font-size: 1.8rem;

    text-align: center;

    padding: 15px 0;

    Скопировать

    Селекторы Классов. CSS

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

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

    Для начала задайте имя класса для элемента, через атрибут class. После этого можно обратиться к нему через css. Введите его название, с точкой вначале.

    HTML файл остаётся прежним в основе, но к нему добавляется новый атрибут из CSS:

    В CSS это выглядит как:

    CSS

    Text {

    font-size: 1.1rem;

    text-align: center;

    padding: 10px 0;

    Скопировать

    Родительские и селекторы. CSS

    Эти указатели немного отличаются от предыдущих и имеют свои уникальные функции.

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

    Чтобы обратиться к прямым потомкам элемента используйте запись X Y. Например, чтобы стилизовать все ссылки внутри параграфов, используем селектор "a"

    CSS

    color: rgba(255, 255, 255, 0.65);

    font-weight: bold;

    Скопировать

    Второй способ обращения к потомкам более конкретный. Например, если в теге

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

      Стили применяются только к тем тегам

        , которые находятся внутри самого элемента
        . К элементам, которые находятся внутри
      • , стили применяться не будут.

        Соседние селекторы применяются к тем элементам, которые находятся рядом с указателем. Допустим у вас на странице такой текст:

        Тег span находится по соседству с тегом . Поэтому, чтобы обратиться к нему, используем запись + .

        Селекторы атрибутов. CSS

        Дают возможность обратиться не ко всем элементам страницы, а лишь к тем, которые имеют определенный атрибут.

        В HTML это выглядит как:

        HTML

        Скопировать

        В CSS это выглядит как:

        CSS

        color: darkblue;

        text-decoration: none;

        Скопировать

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

        Приоритеты

        По приоритету селектору располагаются следующим образом.

        1. #id:not — id c псевдо-классом отрицания. Специфичность — 101.
        2. #id — простой идентификатор. Специфичность — 100.
        3. p.green.bold — тег с двумя классами. Специфичность — 21.
        4. body section div.header — третий потомок тега с классом. Специфичность -13.
        5. body section div — третий потомок тега. Специфичность — 11.
        6. div p — второй потомок. Специфичность — 2.
        7. p — обращение к тегу элемента. Специфичность — 1.
        8. * — обращение ко всем элементам. Специфичность — 0.

        Чем выше специфичность, тем выше приоритет.

        Свойства селекторов. CSS

        В языке CSS существует огромное количество свойств, которые и задают стили элементов. Для создания нужно указать селектор, а затем уже свойство, в фигурных скобках.

        Заключение

        Знание работы селекторов и их приоритетов позволит избежать множества ошибок при разработке веб-сайтов. Чтобы закрепить знания на практике, создайте страницу с заголовками, параграфами и списками. Измените их шрифт, цвет и отступы. Для отступов используйте общие селекторы, а для цвета и шрифтов используйте обращения к тегам элементов.

        Теги:

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

        Конечно, чтобы результат применения для тебя был предсказуем, ты должен научиться видеть, какое из правил одержит верх. Пришла пора разобраться, как рассчитывается специфичность.

        Как это выглядит

        Специфичность представляет собой группу из четырех чисел. Например, 0,0,0,0 или 0,0,1,2.

        Как подсчитать специфичность

        Специфичность считается по селектору. Правила подсчета очень просты:

        • каждый присутствующий в селекторе идентификатор добавляет к специфичности 0,1,0,0;
        • каждый класс, псевдокласс или атрибут добавляет к специфичности 0,0,1,0;
        • каждый элемент или псевдоэлемент добавляет к специфичности 0,0,0,1;
        • универсальный селектор и комбинаторы не учитываются.

        Давай закрепим полученные знания и поупражняемся в расчете специфичности.

        P {/*какие-то определения */} div p {/*какие-то определения */} p.note {/*какие-то определения */} form.feedbackForm input {/*какие-то определения */} #conten a:hover {/*какие-то определения */}

        Превая строка — одинокий селектор типа. Специфичность 0,0,0,1.

        Вторая строка — два селектора типа. Специфичность 0,0,0,2.

        Теретья строка — селектор типа и класса. Специфичность 0,0,1,1.

        Четвертая строка — два селектора типа, один класса и один атрибута. Специфичность 0,0,2,2.

        Пятая строка — селектор идентификатора, типа и псевдокласс. Специфичность 0,1,1,1.

        Кто победил?

        Сравниваются специфичности очень просто. Какое число больше, то определение и выиграло.

        Например:
        0,0,1,4 больше, чем 0,0,1,2.
        0,1,2,0 больше, чем 0,0,2,1.

        Учти, что первые (те, которые левее) числа всегда возьмут верх над последующими (более правыми). Они как бы находятся в более старшем разряде.

        Например, 0,1,0,0 больше, чем 0,0,8,9.

        Если тебе так удобнее, можешь мысленно отбросить запятые и рассматривать предыдущий пример, как 100>89. Только не запутайся, если какой-то из разрядов специфичности будет больше девяти (что может быть при сильно навороченном селекторе). Например, если получилась специфичность 0,1,10,14, запятые отбрасывать нельзя, а то все разряды попутаются.

        Специфичность и объявления

        Специфичность относится как бы не ко всему правилу в целом, а к каждому конкретному объявлению. Поэтому, может получиться что правило «отработает» не полностью. Например:

        Подопытный текст

        Div { color: #0f0; /* Специфичность 0,0,0,1. */ font-weight: bold; /* Специфичность 0,0,0,1. */ } .box { font-weight: normal; /* Специфичность 0,0,1,0. */ }

        Объявление из строки 2 для элемента

        отработает нормально, а объявление из строки 3 будет перебито объявлением из строки 6 (так как у него больше специфичность). Текст внутри нашего div будет зеленым, но не жирным.

        Этот простейший пример показывает насколько важно уметь считать специфичности. Во первых, всегда можно составить правильный селектор, чтобы нужное мне объявление победило. Во-вторых, если какое-то объявление не отработало, ты сразу же поймешь, почему и сэкономишь массу времени на отладке.

        Обрати внимание, что специфичность селектора идентификатора (0,1,0,0) всегда выше, чем селектора атрибута (0,0,1,0). Даже если этот атрибут — ! Поэтому:

        Form.feedback input { color: #f00; /* Специфичность 0,0,2,2. */ } #name { color: #0f0; /* Специфичность 0,1,0,0. - победа! */ }

        Встроенные стили

        По идее, кто-то уже давно должен был спросить, а зачем, собственно, в специфичности самая первая цифра? Ведь мы ее до сих пор никак не использовали!

        Все верно. Первая цифра зарезервирована для встроенных стилей. Считается, что их специфичность равна 1,0,0,0. Таким образом, встроенный стиль всегда перебивает стиль заданный во внешней или вложенной таблице стилей. Например:

        Этот текст будет зеленым

        Даже использовав селектор идентификатора, мы не перебъем встроенный стиль.

        Div#box { color: #00f; /* Специфичность 0,1,0,1. - маловато */ }

        Это что же получается? На встроенные стили нет никакой управы?

        Не волнуйся. Конечно, есть способ перебить встроенные стили (а заодно и все остальные объявления).

        Объявление!important

        Если очень нужно, можно пометить какое нибудь объявление, как важное (important). Такое объявление будет считаться заведомо победившим при сравнивании специфичностей. Да, да, в том числе победившем и встроенные стили. Давай немного изменим CSS для предыдущего примера:

        Div { color: #00f !important; /* важное объявление - сразу победа! */ }

        Даже слабенький по специфичности (0,0,0,1) селектор типа перебил встроенный стиль, ведь его объявление теперь стало важным!

        Детали применения!important хорошо описаны в нашем CSS-справочнике . Если хочешь узнать подробности — перейди по ссылке .

        Теперь, вооружившись знанием о расчете специфичности можно продолжить изучение наследования в CSS.