От автора: обычно когда вы пишите стили, вы даже не задумываетесь об очередности в CSS. Соблюдение очередности не самая приоритетная задача, но все же она имеет значение! Очередность работает, когда есть одинаковые селекторы и элементы с одинаковой специфичностью. Если специфичность полностью совпадает, то порядок стилей имеет значение. Применяются более поздние стили.
В одном файле стилей
К примеру, у нас есть HTML код:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <link rel="stylesheet" href="styles.css"> </head> <body> <div class="module module-foo module-bar"> Module </div> </body> </html> |
Порядок атрибутов в HTML не играет никакой роли, а вот порядок в стилях очень важен. Разберем свойство background:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/* Все селекторы совпадают И обладают одинаковой специфичностью */ .module { background: #ccc; padding: 20px; max-width: 400px; margin: 20px auto; } .module-foo { background: orange; } /* Побеждают ПОСЛЕДНИЕ объявления */ .module-bar { background: lightblue; /* Я выиграл! */ /* Остальные стили */ } |
Специально запутанный пример
Порядок не ограничивается только одним объявлением стилей. Еще более важен порядок объявления стилей в документе.
Обратите внимание на документ ниже с тремя разными объявлениями стилей. Назовем их кусочками. Эти кусочки — это <link rel=»stylesheet»>, блок style и @import.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <!-- #1 --> <link rel="stylesheet" href="1.css"> <!-- #2 --> <style> .module-baz { background-color: pink; } </style> </head> <body> <div class="module module-foo module-bar module-baz"> Module </div> <!-- #3 --> <style> @import "2.css"; /* Contains .module-bar { background: #f06d06; } */ </style> </body> </html> |
Я пометил наши кусочки как #1, #2 и #3. Все они содержат селекторы с одинаковой специфичностью. Кусочек #3 объявлен последним, а значит, он побеждает.
Асинхронно загружаемые стили CSS тоже соблюдают очередность
Скажем, вы загружаете CSS при помощи специального загрузчика типа loadCSS. Что будет, если загрузить четвертый CSS файл с точно такими же настройками, как в запутанном примере выше?
Загрузчик loadCSS по умолчанию вставляет стили в конец тега head. То есть этот файл станет #3, а блок style перед закрывающим тегом body превратится в #4. Кусочек #4 в таком случае выиграет.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <link rel="stylesheet" href="1.css"> <script src="loadCSS.js"></script> <script> loadCSS("2.css"); </script> <!-- 2.css будет вставлен в этом месте --> </head> <body> <div class="module module-foo module-bar module-late"> Module </div> </body> </html> |
На самом деле, нельзя вставлять теги link и style в тег body (хоть это и работает). Вероятность того, что загруженные при помощи loadCSS стили не сработают, крайне мала. Можно указать ID, чтобы контролировать порядок CSS:
1 2 3 4 |
<script id="loadcss"> // файл CSS будет загружен прямо перед тегом script с этим кодом loadCSS("path/to/mystylesheet.css", document.getElementById("loadcss")); </script> |
Странный критический CSS
Есть причина, из-за которой вам может понадобиться loadCSS. Может возникнуть ситуация, когда вам понадобится намеренно отложить загрузку стилей из-за вставки критического CSS кода в head, чтобы эти стили попали в первый пакет и ускорили отрисовку страницы.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> /* #1 Критический CSS код */ </style> <script> /* #2 Загружаем оставшийся CSS */ </script> </head> <body> <div class="module module-foo module-bar"> Module </div> </body> </html> |
Практика критического CSS включает в себя перемещение селекторов на один кусочек вверх, т.е. в #1. Самый первый в очередности блок и самый легкий для перезаписи. Чисто теоретически, могут возникнуть конфликты с тем, какие стили будут применены в случаях со страницей только с критическим CSS и полностью загруженными стилями. После полной загрузки основные стили будут идти после критических, и все будет работать как положено.
Необходимо точно решить, какие стили перенести в критические, а какие нет, чтобы избежать странных мерцаний при смене стилей.
Странные расширения
Расширения в препроцессорах ведут себя странно. К примеру, вы хотите по-разному стилизовать элемент:
1 |
<div class="module module-variation">Module</div> |
Код препроцессора будет таким (супер упрощенный код чисто для демо):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
%variation { background: orange; } .module { background: #ccc; padding: 20px; max-width: 400px; margin: 20px auto; } .module-variation { @extend %variation; } |
Вы можете подумать: «хорошо, .module-variation объявлен ПОСЛЕДНИМ, он выиграет, фон будет оранжевым». Это не так, так как расширение перемещает селектор в то место, где расширение было объявлено. В нашем случае это место находится перед стилями, которыми мы пытались переписать фон. Скомпилированный CSS код:
1 2 3 4 5 6 7 8 9 10 |
.module-variation { background: orange; } .module { background: #ccc; padding: 20px; max-width: 400px; margin: 20px auto; } |
Свойство background примет значение #ccc, а не то, что мы хотим. Наверное, проще такую проблему решить при помощи специфичности, а не очередности стилей. Родные расширения, когда будут введены, будут менее запутанными.
Довольно запутанный механизм
Никто не хочет думать об этом. Определять стили с помощью специфичности куда легче. Однако об этом нужно знать, так как ненужное раздувание специфичности тоже плохая практика.
Автор: Chris Coyier
Источник: //css-tricks.com/
Редакция: Команда webformyself.