Оглавление
CSS
Синтаксис
- После значения свойства обязательно ставится точка с запятой.
- Шестнадцатеричное значение цвета сокращается. Для записи используются строчные буквы.
- Названия тегов и свойств в правилах пишутся строчными буквами.
- Начальный ноль для значений не сокращается (например,
.5вместо0.5). - Во всех случаях в стилях используются одинарные кавычки. В необязательных случаях кавычки не опускаются.
- После двоеточия в правилах ставится один пробел (
top: 10px;). А перед двоеточием пробел не нужен. - После запятых внутри значений
rgb(),rgba(),hsl(),hsla()илиrect()пробелы ставятся. Это повышает удобочитаемость. - До и после комбинатора между селекторами (например,
p > a) ставится один пробел. - Каждое объявление в правиле пишется на новой строке.
- Перед открывающейся фигурной скобкой ставится один пробел. После скобки запись идёт с новой строки.
- Закрывающая фигурная скобка пишется на новой строке и без отступа. Следующее после этого правило отделяется пустой строкой.
- Единицы измерения не пишутся, там где в них нет необходимости. Например,
border: 0. - Для проверки CSS-кода используйте stylelint.
/* 😊 Хорошо */
.selector,
.selector-secondary,
.selector[type="text"] {
padding: 15px;
margin-bottom: 15px;
background-color: rgba(0, 0, 0, 0.5);
box-shadow: 0 1px 2px #ccc, inset 0 1px 0 #fff;
}
/* 💩 Плохо */
.selector, .selector-secondary, .selector[type=text] {
padding:15px;
margin:0px 0px 15px;
background-color:rgba(0,0,0,.5);
box-shadow:0px 1px 2px #CCCCCC,inset 0 1px 0 #FFFFFF}
Порядок свойств
Объявления логически связанных свойств группируются в следующем порядке:
- Позиционирование
- Блочная модель
- Типографика
- Оформление
- Анимация
- Разное
Позиционирование следует первым потому, что оно влияет на положение блоков в потоке документа. Блочная модель идёт следующей, так как она определяет размеры и расположение блоков.
Все остальные объявления, которые изменяют вид внутренних частей блоков и не оказывают влияния на другие блоки, идут в последнюю очередь.
Сгруппированные объявления в правиле отделяются друг от друга пустой строкой.
Порядок объявления подробных правил, таких как font-size, font-family, line-height, должен соответствовать порядку в сокращённой версии правила. В случае совместного использования подробных и сокращённых правил, первой должна идти сокращённая версия.
.declaration-order {
/* Позиционирование */
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 100;
/* Блочная модель */
display: block;
float: right;
width: 100px;
height: 100px;
margin: 10px;
padding: 10px;
/* Типографика */
font: normal 13px/1.5 "Arial", sans-serif;
font-style: normal;
font-size: 13px;
line-height: 1.5;
font-family: "Arial", sans-serif;
text-align: center;
color: #333333;
/* Оформление */
background-color: #f5f5f5;
border: 1px solid #e5e5e5;
border-radius: 3px;
opacity: 1;
/* Анимация */
transition: color 1s;
/* Разное */
will-change: auto;
}
Имена классов
- Имена классов пишутся строчными буквами, используется дефис (но не знаки нижнего подчёркивания или camelCase). Дефисы служат разделителями во взаимосвязанных классах (например,
.buttonи.button-danger). - Имена классов должны быть такими, чтобы по ним можно было быстро понять какому элементу страницы задан класс: избегайте сокращений, не делайте их слишком длинными.
- Для написания классов используются английские слова и термины. Транслитом названия классов и атрибутов не пишутся.
/* 😊 Хорошо */
.alert-danger { … }
.tweet .user-picture { … }
.button { … }
.layout-center { … }
/* 💩 Плохо */
.testElement { … }
.t { … }
.big_red_button { … }
.knopka { … }
Варианты шрифта
Альтернативные варианты шрифта и тип семейства указываются в конце перечисления font-family.
В случае использования нестандартных шрифтов альтернативный веб-безопасный шрифт и тип семейства указываются, чтобы в случае отсутствия нестандартного шрифта в системе, изменения внешнего вида страницы были минимальны. Альтернативный шрифт должен быть такого же типа, что и нестандартный.
Порядок шрифтов следующий:
- нестандартный шрифт
- веб-безопасный
- тип шрифта
Список веб-безопасных шрифтов можно посмотреть здесь.
/* 😊 Хорошо: указан альтернативный веб-безопасный шрифт и его тип семейства */
body {
font-family: "Helvetica", "Arial", sans-serif;
}
/* Кому-то нравится Arial, кому-то Tahoma */
body {
font-family: "Helvetica", "Tahoma", sans-serif;
}
/* 💩 Плохо: указан только нестандартный шрифт */
body {
font-family: "Helvetica";
}
/* 💩 Плохо: указан только нестандартный шрифт и тип семейства, альтернативный веб-безопасный шрифт отсутствует */
body {
font-family: "Helvetica", sans-serif;
}
/* 💩 Плохо: Georgia — шрифт с засечками, а нестандартный шрифт — без засечек */
body {
font-family: "Helvetica", "Georgia", sans-serif;
}
Использование некроссбраузерных решений
Некоторые задачи могут быть легко решены CSS-свойствами, имеющими плохую поддержку браузерами. Использовать решения, приводящие к различному отображению в разных браузерах – допустимо редко.
/* 😊 Хорошо: используется старый и проверенный хак */
.aspect-ratio {
padding-bottom: 56.25%;
}
/* 💩 Плохо: используется современное решение, которое плохо поддерживается */
.aspect-ratio {
aspect-ratio: 16 / 9;
}
Многосоставные селекторы
Многосоставные (2-х и более) селекторы во многих случаях приводят к проблемам:
- необходимость учитывать не только очерёдность, но и «вес» селектора
- привязка стилей к определённой разметке (сложно модифицировать)
Многие методологии рекомендуют избегать вложений. Но это не означает его запрет, бывают ситуации, когда без этого сложно обойтись. К примеру, при стилизации выводимых из CMS фрагментов (контент-менеджер не должен заботиться о написании классов).
/* 😊 Хорошо: используется селектор по одному классу */
.btn {
display: block;
}
/* 💩 Плохо: используется сложный селектор */
.selector section div .btn {
display: block;
}
Стилизация по тегам и по id
Атрибут class специально существует для привязки стилей, используйте его. Редко допустима комбинация с тегами, псевдоселекторами или иными атрибутами. Не стилизуйте по id, ибо такие селекторы «больше весят» и их невозможно повторить в рамках одной страницы.
/* 😊 Хорошо: используется класс */
.btn {
display: block;
}
/* 💩 Плохо: используется айди */
#btn {
display: block;
}
/* 💩 Плохо: используется тэг */
.btn img {
display: block;
}
Использование !important и/или overflow: hidden; для исправления багов
Вместо поиска места проблемы (и её ликвидации) автор пишет правило с !important. Другой вариант: для ликвидации горизонтального скролла пишут overflow: hidden; на одной из общих обёрток.
Есть ситуации, когда такие «быстрые заплатки» допустимы (чужой чудовищно безграмотный код, который нужно исправить в условиях цейтнота). Однако если весь код написали вы, такие подходы — свидетельство вашей неспособности найти и решить проблему.
/* 💩 Плохо: горизонтальный скролл скрывается через костыль */
body {
overflow: hidden;
}
/* 💩 Плохо: правило перекрывается через !important */
.btn {
display: block !important;
padding: 20px !important;
}
Игнорирование переполнения/недополнения контентом
Переполнение и недополнение контентом/субблоками должно быть главным, о чём вы думаете, когда пишите стилизацию.
Если где-то есть текст, его может стать много или совсем мало (при этом вёрстка не должна сломаться, должна вести себя логично). Познакомьтесь с «Электрокардиографической одиннадцатиклассницей, предпочитающей циклопентанпергидрофенантрен» и с «Ю Ли».
Если в дизайне показан поток из 6 блоков (по 2 в ряд), нужно учесть что блоков может стать от нуля до 13 (не особо важно сколько именно, важно что много и что будет неполный последний ряд).
Один из «рефлексов верстальщика»: зафиксировал блоку ширину или высоту — подумай о переполнении.
/* 💩 Плохо: фиксированная высота для блока с текстом */
p {
height: 24px;
}
Объединение стилей обёрток и отдельных блоков
Обычно, есть раскладка блоков по страницам и есть сами блоки. Смешивать на одном селекторе стили для раскладки и стили оформления блоков — порочный путь, ибо усложняет перенос блоков и другую модификацию.
Самые большие неприятности возникают, когда небольшим блокам (к примеру, виджетам сайдбара) фиксируют ширину — это увеличивает количество точек изменения при необходимости менять ширину нескольких блоков в потоке (ширину сайдбара в нашем примере).
Если не хочется писать лишних обёрток, можно попробовать миксовать (термин из БЭМ) класс обёртки с классом блока на одном теге, но в этом случае вы (или другой разработчик) сможете смешать правила.
/* 💩 Плохо: на один блок повесили все стили */
.base-sidebar {
width: 300px;
height: 100%;
font-size: 10px;
line-height: 14px;
background-color: #0e9c58;
}
/* 😊 Хорошо: стили разграничиваются */
.base-sidebar {
width: 300px;
height: 100%;
}
.base-sidebar--green {
background-color: #0e9c58;
}
.base-sidebar--text-size-xs {
font-size: 10px;
line-height: 14px;
}
/* 😊 Хорошо: используется дополнительная обёртка */
.base-sidebar {
width: 300px;
height: 100%;
}
.base-sidebar .inner-wrapper {
font-size: 10px;
line-height: 14px;
background-color: #0e9c58;
}
Программирование на CSS-препроцессорах (особенно если не умеете программировать)
Не программируйте на CSS-препроцессорах. Когда мы разбираемся в работе/багах применённых стилей, меньше всего нам хочется тратить время на разбор сложных структур, из которых эти стили скомпилировались.
Да, с Sass/LESS/Stylus можно написать код, который будет коротким и его будет довольно сложно понять, но это не признак крутости. Совсем наоборот: сложнее = хуже (дольше разбираться как это работает). Нечто, более или менее похожее на программирование допустимо в CSS-препроцессорах в примесях (к примеру, в примесях-генераторах правил модульной сетки).
/* 💩 Плохо: тяжело читать */
@mixin calc-grid-column($index, $class, $type) {
@if ($type == width) and ($index > 0) {
.col-#{$class}-#{$index} {
width: percentage(($index / $grid-columns));
}
}
@if ($type == push) and ($index > 0) {
.col-#{$class}-push-#{$index} {
left: percentage(($index / $grid-columns));
}
}
@if ($type == push) and ($index == 0) {
.col-#{$class}-push-0 {
left: auto;
}
}
@if ($type == pull) and ($index > 0) {
.col-#{$class}-pull-#{$index} {
right: percentage(($index / $grid-columns));
}
}
@if ($type == pull) and ($index == 0) {
.col-#{$class}-pull-0 {
right: auto;
}
}
@if ($type == offset) {
.col-#{$class}-offset-#{$index} {
margin-left: percentage(($index / $grid-columns));
}
}
}
Быстрое чтение
Оставляйте пустую строку перед селектором или группой селекторов.
Работая с CSS-препроцессорами, оставляйте пустую строку перед любым вложенным селектором и @media.
/* 😊 Хорошо: отступы между строчками */
.promo {
display: block;
&__container {...}
&__item {...}
}
/* 💩 Плохо: отступы не соблюдены */
.promo {
display: block;
&__container {...}
&__item {...}
}
Сокращённая запись
Избегайте сокращённых объявлений. К примеру, если нужно задать только нижний внешний отступ, пишите margin-bottom: 10px; вместо margin: 0 0 10px.
/* 😊 Хорошо: изменяются только нужные свойства */
.element {
margin-bottom: 10px;
background-color: red;
background-image: url("image.jpg");
border-top-left-radius: 3px;
border-top-right-radius: 3px;
}
/* 💩 Плохо: изменяются свойства, которые нам и не нужны. Труднее читать. */
.element {
margin: 0 0 10px;
background: red;
background: url("image.jpg");
border-radius: 3px 3px 0 0;
}
Медиа-выражения
Помещайте media queries настолько близко к соответствующим наборам правил, насколько это возможно. Не объединяйте их в отдельную таблицу стилей, не помещайте их в конце файла.
/* 😊 Хорошо: медиа выражения рядом с селектором */
.element {
margin-bottom: 10px;
@media (min-width: 768px) {
margin-bottom: 14px;
}
}
.block {
background-color: #0e9c58;
@media (min-width: 768px) {
background-color: #00d171;
}
}
/* 💩 Плохо: создаётся отдельная таблица стилей */
.element {
margin-bottom: 10px;
}
.block {
background-color: #0e9c58;
}
@media (min-width: 768px) {
.element {
margin-bottom: 14px;
}
.block {
background-color: #00d171;
}
}
Интерактивные элементы
При создании интерактивных элементов (элементов, с которыми пользователь может как-то взаимодействовать — что-то происходит по нажатию на этот элемент или наведению на него), нужно учитывать следующие состояния:
hover— состояние при наведении мышью на элемент;focus— состояние при «наведении» на элемент с клавиатуры (табом). Фокус должен быть явно виден на странице, т.е. должно быть однозначно видно и понятно, какой элемент сейчас под фокусом. Наилучшим вариантом является стандартный outline. Не рекомендуется заменять его на смену цвета текста \ фона, так как такое изменение малозаметно. Допускается смена цвета outline на тот, который более вписывается в дизайн сайта;disabled— обязательное состояние, если семантически такое состояние есть.
В случае отсутствия необходимых состояний в макетах, запросите их у менеджера проекта \ дизайнера. Если контакта с дизайнером нет или по каким-либо причинам нет возможности отрисовать состояния, поставьте стандартные стили, применяемые в таких ситуациях: для ховера затемнение \ высветление цвета текста \ фона, для фокуса — стандартный аутлайн, для отключённого — выключить ховер и сделать фон \ текст серым.
Учитывайте область клика небольших элементов. Стоит добавлять таким элементам дополнительный padding, чтобы область элемента стала больше и в него было проще попасть.
Если на элемент можно кликать – следует использовать семантический тэг <button>.
Если элемент ведёт на другую страницу – следует использовать семантический тэг <a>.
Ни в коем случае не используйте div, span и другие неинтерактивные элементы.
/* 😊 Хорошо: все состояния описаны. Псевдоэлементом увеличена область клика. */
button {
position: relative;
width: 24px;
height: 24px;
background-color: #00d171;
}
button:hover,
button:focus {
background-color: #1aaa66;
}
button:active {
background-color: #0e9c58;
}
button:disabled {
opacity: 0.4;
cursor: not-allowed;
}
button::before {
position: absolute;
top: 50%;
left: 50%;
width: calc(100% + 40px);
height: calc(100% + 40px);
transform: translate(-50%, -50%);
content: '';
}
/* 💩 Плохо: состояние не описаны. На кнопку трудно кликать. */
button {
position: relative;
width: 24px;
height: 24px;
background-color: #00d171;
}
/* 💩 Плохо: интерактивный элемент сделан через <div> */
div.button {
position: relative;
width: 24px;
height: 24px;
background-color: #00d171;
}
Анимации
Не анимируйте свойства, который вызывают reflow (layout) элемента. То есть те свойства, которые влияют на размеры элемента или на положение соседних элементов. К таким свойствам можно отнести width и margin. Анимация таких свойств будет медленной и будет работать медленно на слабых устройствах, лучше обойтись без анимации или изменить принцип анимации, чтобы можно было обойтись без reflow.
Не анимируйте свойства, которые вызывают repaint у больших блоков. Такая анимация хоть и гораздо быстрее, чем анимация свойств с reflow, но всё равно может быть достаточно медленной.
Лучшие свойства для анимации — свойства, которые вызывают только compositing. Такая анимация будет наиболее производительной. Основная проблема, что такие свойства — только opacity и transform. Но через них можно сэмулировать анимацию большинства остальных свойств.
/* 😊 Хорошо: размер эмулируется с помощью transform */
button {
width: 24px;
height: 24px;
}
button:hover,
button:focus {
transform: scale(2);
}
/* 💩 Плохо: анимируется запрещённое свойство. */
button {
width: 24px;
height: 24px;
}
button:hover,
button:focus {
width: 48px;
height: 48px;
}
Явный transition-property
Для transition следует явно указывать анимируемое свойство для увеличения производительности.
/* 😊 Хорошо: указано анимируемое свойство */
button {
opacity: 1;
transition-property: opacity;
transition-duration: 0.2s;
transition-timing-function: ease;
}
button:hover,
button:focus {
opacity: 0.9;
}
/* 💩 Плохо: анимируются все свойства */
button {
opacity: 1;
transition-property: all;
transition-duration: 0.2s;
transition-timing-function: ease;
}
button:hover,
button:focus {
opacity: 0.9;
}
Амперсанд
Используйте амперсанд только перед:
- разделителем БЭМ-элемента,
- разделителем БЭМ-модификатора,
- псевдоэлементом или псевдоселектором.
Никогда не используйте амперсанд в местах разделения словосочетаний имён блоков, элементов или модификаторов.
.promo {
/* 😊 Хорошо: амперсанд перед псевдоклассом */
&:hover { ... }
/* 😊 Хорошо: амперсанд перед разделителем элемента */
&__item {
/* 💩 Плохо: амперсанд в месте разделения словосочетания в названии элемента */
&-link { ... }
}
/* 💩 Плохо: амперсанд в месте разделения словосочетания в названии блока */
&-shover { ... }
}