Специфичность правил в CSS
Сегодня довелось познакомиться поближе с понятием CSS specificity. Началось всё со странного (с моей точки зрения) поведения браузеров. Код был примерно таким:
<head>
<style>
table {
width: 80%;
}
table.rating td {
text-align: left;
border: 1px solid gray;
border-collapse: collapse;
}
td.number {
text-align: center;
}
</style>
</head>
<body>
<table class="rating">
<tr>
<th>Head 1</th>
<th>Head 2</th>
<th>Head 3</th>
</tr>
<tr>
<td>10</td>
<td class="number">20</td>
<td class="number">30</td>
</tr>
</table>
</body>
</html>
По моей логике, раз оба правила обращаются к одной ячейке, применяться должно то которое стоит ниже в коде (CSS cascading). Однако браузеры упорно сдвигали цифры влево, а Firebug показывал что правило, стоящее выше в коде перекрывает то которое стоит ниже, никак это не объясняя.
Стало быть, проблема в стилях, а не в браузерах, решил я, и перед тем как постить вопрос на StackOverflow решил прошвырнуться по документам W3C о сортировке правил в CSS.
Итак, оказалось что правила сортируются в три этапа. Вначале — по источнику и важности, в таком порядке:
- user-agent declarations
- user normal declarations
- author normal declarations
- author important declarations
- user important declarations
Чем правило ниже в этом списке, тем больше у него приоритет. Т.е. обычные стили сайта перекрывают обычные пользовательские стили, но перекрываются важными стилями автора и пользователя. Что меня тут удивило – то что правила автора вставлены “между” правилами пользователя. Я с пользовательскими правилами пока дела не имел, так что сталкиваться не приходилось, но поведение любопытное.
На втором этапе сортировки правила сортируются по специфичности (specificity). Специфичность считается так:
Сама специфичность состоит из трёх чисел: a,b,c,d , и рассматривается как четырёзначное число в большой системе счисления.
- a принимается равной 1 если правило находится в атрибуте style в HTML и 0 в остальных случаях. Это сразу выделяет правила в style в “отдельный класс”, всегда имеющий более высокий приоритет
- b это число id-атрибутов в селекторе. При прочих равных правила с id-атрибутами всегда стоят выше чем правила без них
- c это число других атрибутов и псевдоклассов
- d – число имён элементов и псевдоэлементов
На третьем этапе правила с одинаковой важностью и специфичностью сортируются уже по позиции в CSS-файле или файлах. Чем ниже находится правило, тем выше его приоритет. Тут уже “ничьей” быть не может, даже если происхождение, приоритет и специфичность одинаковы одно из правил всегда окажется выше другого.
Итак, в моих стилях у селекторов одинаковое происхождение и важность. Посмотрим какая у них будет специфичность:
table: 0,0,0,1 (Одно имя элемента)table.rating td: 0,0,1,2 (Один класс, два имени элемента)td.number: 0,0,1,1 (Один класс, одно имя элемента)
Если вам понадобится вычислить специфичность правил (ни один из известных мне dev tools для браузеров этого не делает), можно воспользоваться онлайн-калькулятором.
Ну что ж, ещё один день прошёл не зря, я лучше понял CSS и в следующий раз уже не попадусь так просто на подобном поведении браузера. Чего и Вам желаю
Да есть такая штука. Поэтому всегда делаю полное наследование, т.е. типа:
table.rating td{…}
table.rating td.number{…}
Да, тоже вариант
Но всё равно полезно разбираться как оно внутри работает.