Тарифы        11.07.2019   

Селекторы в 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; }

    Аббревиатура CSS расшифровывается как Cascading Style Sheets (каскадные таблицы стилей), где одним из ключевых слов выступает «каскад». Под каскадом в данном случае понимается одновременное применение разных стилевых правил к элементам документа - с помощью подключения нескольких стилевых файлов, наследования свойств и других методов. Чтобы в подобной ситуации браузер понимал, какое в итоге правило применять к элементу, и не возникало конфликтов в поведении разных браузеров, введены некоторые приоритеты.

    Ниже приведены приоритеты браузеров, которыми они руководствуются при обработке стилевых правил. Чем выше в списке находится пункт, тем ниже его приоритет, и наоборот.

    1. Стиль браузера.
    2. Стиль автора.
    3. Стиль пользователя.
    4. Стиль автора с добавлением!important.
    5. Стиль пользователя с добавлением!important.

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

    Как задавать пользовательский стиль рассказывалось в (см. рис. 1.3 и 1.4).

    !important

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

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

    • !important добавлен в авторский стиль - будет применяться стиль автора.
    • !important добавлен в пользовательский стиль - будет применяться стиль пользователя.
    • !important нет как в авторском стиле, так и стиле пользователя - будет применяться стиль пользователя.
    • !important содержится в авторском стиле и стиле пользователя - будет применяться стиль пользователя.

    Синтаксис применения !important следующий.

    Свойство: значение!important

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

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

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

    Если к одному элементу одновременно применяются противоречивые стилевые правила, то более высокий приоритет имеет правило, у которого значение специфичности селектора больше. Специфичность это некоторая условная величина, вычисляемая следующим образом. За каждый идентификатор (в дальнейшем будем обозначать их количество через a) начисляется 100, за каждый класс и псевдокласс (b) начисляется 10, за каждый селектор тега и псевдоэлемент (c) начисляется 1. Складывая указанные значения в определённом порядке, получим значение специфичности для данного селектора.

    * {} /* a=0 b=0 c=0 -> специфичность = 0 */ li {} /* a=0 b=0 c=1 -> специфичность = 1 */ li:first-line {} /* a=0 b=0 c=2 -> специфичность = 2 */ ul li {} /* a=0 b=0 c=2 -> специфичность = 2 */ ul ol+li {} /* a=0 b=0 c=3 -> специфичность = 3 */ ul li.red {} /* a=0 b=1 c=2 -> специфичность = 12 */ li.red.level {} /* a=0 b=2 c=1 -> специфичность = 21 */ #t34 {} /* a=1 b=0 c=0 -> специфичность = 100 */ #content #wrap {} /* a=2 b=0 c=0 -> специфичность = 200 */

    Встроенный стиль, добавляемый к тегу через атрибут style , имеет специфичность 1000, поэтому всегда перекрывает связанные и глобальные стили. Однако добавление !important перекрывает в том числе и встроенные стили.

    Если два селектора имеют одинаковую специфичность, то применяться будет тот стиль, что указан в коде ниже.

    В примере 19.1 показано, как влияет специфичность на стиль элементов списка.

    Пример 19.1. Цвет списка

    HTML5 CSS 2.1 IE Cr Op Sa Fx

    Список

    В данном примере цвет текста списка задан зелёным, а второй пункт списка с помощью класса two выделен красным цветом. Вычисляем специфичность селектора #menu ul li - один идентификатор (100) и два тега (2) в сумме дают значение 102, а селектор .two будет иметь значение специфичности 10, что явно меньше. Поэтому текст окрашиваться красным цветом не будет. Чтобы исправить ситуацию, необходимо либо понизить специфичность первого селектора, либо повысить специфичность второго (пример 19.2).

    Пример 19.2. Изменение специфичности

    /* Понижаем специфичность первого селектора */ ul li {...} /* Убираем идентификатор */ .two {...} /* Повышаем специфичность второго селектора */ #menu ul li {...} #menu .two {...} /* Добавляем идентификатор */ #menu ul li {...} .two { color: red !important; } /* Добавляем!important */

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

    Вопросы для проверки

    1. Какая специфичность будет у селектора table.forum tr:hover p?

    2. Какая специфичность будет у селектора #catalog .col3 .height div?

    В больших проектах при разрастании CSS файлов получается не очень радостная ситуация. Из-за большого количества правил возникает трудность с тем, чтобы определить, какие стили должны быть применены к конкретному элементу. Какие-то стили наследуется, что-то определено через целую цепочку всевозможных селекторов, где-то используется .class , где-то #id , а где-то вообще inline-style .

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

    1. Никогда не использовать ID селекторы в CSS . У них нет никаких преимуществ по сравнению с class .
      • Все, что можно сделать с ID , можно сделать и с class .
      • ID не могут быть переиспользованны.
      • Вес ID очень большой. Перебить ID нельзя даже сотней цепных class-ов .
    2. Не создавайте излишних селекторов. Если .header-nav {} прекрасно работает, то не используйте определение .header .header-nav {} . В этом случае ничего не изменится и никакой выгоды от этого не будет.
    3. Не конкретизируйте селекторы, пока это действительно не понадобится. Если .nav {} работает, то не используйте ul.nav {} . Такая запись лишь сократит варианты использования данного класса .nav , а так же повысит вес селектора без очевидной пользы.
    4. Заставьте себя использовать .class , потому что это идеальные селекторы.

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

    Это все очень простые правила и следовать им не так-то трудно.

    Уменьшение веса ID

    Предположим у вас есть виджет на странице и вы хотите его стилизовать:

    ...

    И, например, мы не можем изменять HTML код виджета, чтобы избавиться от ID. Поэтому мы делаем так:

    #widget { ... }

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

    { ... }

    Это селектор атрибута. В данном случае это уже определение не для ID , а для элемента. Если говорить точно, то селектор говорит: «Эй, найди мне элемент, у которого есть атрибут id со значением widget ».

    Прелесть такого подхода в том, что мы снизили вес ID до веса класса. Но это хак.

    Безопасное увеличение веса

    Увеличить вес селектора мы можем так:

    Btn.btn.btn.btn { ... }

    Но я надеюсь, что никогда не придется использовать такую запись на проектах.

    Здесь мы видим, что цвет, заданный в .box a {} , перетирает цвет текста кнопки. В итоге текст сливается с фоном кнопки.

    Конечно, мы можем исправить это, если поставим !important (jsfiddle.net/csswizardry/3N53n/1), но нет, спасибо, избавимся от этого!

    Мы можем добавить дополнительный селектор в секцию .btn {} (23 строка) jsfiddle.net/csswizardry/3N53n/2 , но это не самое лучшее решение. Что, если проблема с кнопкой будет не только в .box , а где-либо еще? Каждый раз добавлять новый селектор – плохой вариант.

    Поэтому мы продублируем .btn.btn : http://jsfiddle.net/csswizardry/3N53n/3

    Это так же не самое лучшее решение, но все же мы увеличили вес селектора и цвет на кнопке теперь такой, какой и должен быть.

    Теперь мы знаем 2 способа изменения веса селектора, но помните, что все же это хаки и не стоит ими сильно увлекаться.

    Допустим, у Вас есть несколько селекторов которые ссылаются на один и тот же элемент:

    Открыв HTML страницу где элемент span находится внутри элемента div мы увидим подчеркнутый текст. А если мы пойдем дальше и с помощью плагина Firebug посмотрим стили вложенного элемента, мы увидим следующее:

    Div span { text-decoration:underline; } span { text-decoration:none; }

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

    Правила специфичности

    Специфичность селекторов (selector"s specificity) определяет их приоритетность в таблице стилей. Чем специфичнее селектор, тем выше его приоритет.

    В спецификации по CSS 2.1 этой теме посвящен небольшой раздел. Существует 4 правила по которым вычисляется специфичность селекторов:

    1. Самый высокий приоритет имеет атрибут style . Это правило перекрывает все селекторы описанные в стилях.
    2. Второе место занимает присутствие ID в селекторе(#some-id).
    3. Далее идут все атрибуты(в том числе и атрибут class ) и псевдоклассы(pseudo-classes) в селекторе.
    4. Самый низкий приоритет у селекторов с именами элементов и псевдоэлементами(pseudo-elements).

    Все 4 правила сводятся в одну систему a-b-c-d (где а - наивысший приоритет) и образуют специфичность.

    Селектор Специфичность a-b-c-d Правило №
    * 0-0-0-0 -
    li 0-0-0-1 4
    li:first-line 0-0-0-2 4
    ul li 0-0-0-2 4
    ul ol+li 0-0-0-3 4
    form + * 0-0-1-1 3, 4
    table tr td.second 0-0-1-3 3, 4
    h2.block.title. 0-0-2-1 3, 4
    #xyz 0-1-0-0 2
    style=" " 1-0-0-0 1

    Пример специфичности - правило №1:

    content

    Текст внутри элемента p будет отображаться синим цветом независимо от селектора с айди(id), где также указано свойство color со значением red . Правило номер 1 всегда перекрывает все селекторы и имеет наивысшую приоритетность.

    Правило №2:

    • first
    • second

    Несмотря на то что селектор с id указан в стилях сверху, именно он повлияет на отображение документа, так как более специфичен нежели селектор с классом second .

    Правило №3:

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

    Вернемся к первому примеру этой статьи - правило №4:

    div span { text-decoration:underline; } span { text-decoration:none; }

    Первый селектор выигрывает у второго потому что включает в себя 2 последних правила специфичности, в то время как второй - всего одно. Чтобы убрать декорирование текста в данном случае следует использовать класс или более специфичный селектор:

    Div span { text-decoration:underline; } body span { text-decoration:none; }

    Теперь селекторы имеют одинаковый вес(0-0-0-2 = 0-0-0-2) касательно специфичности. Второй селектор просто перекроет свойство первого так как описан ниже.

    Уверен, что большинство верстальщиков точно знают 2 первых правила специфичности селекторов про id и style и эта статья не была для них чем-то новым. Но не стоит забывать о двух оставшихся, ведь это может существенно приостановить процесс создания верстки и увеличить время выявления возникшей ошибки.

    Вот и все о чем я хотел рассказать. Надеюсь, что статья была вам интересна.

    --
    Владислав Razor Чапюк, апрель 2009