Правила CSS, которые облегчат вам жизнь

0
1114
views

Перевод статьи «CSS rules that will make your life easier».

Правила CSS

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

Цвета

Вот что я не выношу в веб-проектах, так это излишества в значениях цветов. Крупный, долгоживущий проект, над которым я работал несколько лет назад, имел больше 300 уникальных цветов, разбросанных по почти 40 CSS-файлам. Треть из них была оттенками серого. Отдельные цвета повторялись с небольшими различиями. Порой эти различия были совершенно незначительными, например, #3426D1 и #3426D2. Решение этой проблемы – использование атомарных цветовых классов или переменных (в SCSS или CSS) для допустимых цветов.

Ограничение числа допустимых цветов имеет дополнительное преимущество: так легче обеспечить, чтобы цвета фона и переднего плана соответствовали руководствам WCAG2.0 Color Contrast.

Еще один «располагающий» к багам подход это использование цветов альфа-канала, обычно путем объявления цвета с помощью функций rgba() или hsla(). Цвет, создаваемый таким образом, с любым значением альфа-канала кроме 1, является полупрозрачным. Восприятие этого цвета будет меняться в зависимости от фона. Обычно желаемый результат – вид заданного цвета на белом фоне, так что можно использовать hex-значения. Некоторые функции препроцессоров, такие как lighten() в SASS, могут генерировать полупрозрачные цвета, поэтому просто придерживайтесь жестко прописанных значений цвета или переменных.

Текст

Все свойства, влияющие на шрифты или зависящие от шрифтов, должны объявляться в одном месте, единоразово. Я люблю добавлять атомарные классы для шрифта, которые меняют font-size (через rem) и включают line-height, letter-spacing и word-spacing, подходящие для этой комбинации шрифта и размера, сразу после добавления любых @font-face правил. А после этого ни в каком наборе правил не должны использоваться никакие font-* или text-* свойства (за исключением text-overflow).

Объявление этих свойств исключительно однократно в комбинации с font-face обеспечивает стабильный хороший вид сайта. Регулировка line-height вместо padding или margin создает баги при обтекании текста. Регулировка font-weight отдельно от объявления шрифтов ведет к риску создания faux bold font. Изменение font-style для шрифта, который не поддерживает это свойство, создает faux oblique.

Наконец, старайтесь не устанавливать размер шрифта ни в чем, кроме rem. Использование em ведет к проблемам со вложенными элементами, поскольку em это скалярное кратное от текущего font-size. Использование px (или любых других четких единиц измерения) ведет к риску создания копии, трудной для чтения и неподдающейся для настройки пользователем. Дайте пользователю (или его браузеру) возможность устанавливать font-size так, как он посчитает нужным. Для этого не объявляйте font-size в элементах body или html и используйте только rem.

Правила CSS для текста

Отступы

На сайте, где главным является контент, отступы должны дополнять материалы. Любые статические единицы измерения (вроде padding: 4px) непременно будут выглядеть неправильно при каком-нибудь размере шрифта. А днамические единицы «отзывчивы» к размерам шрифтов. Таким образом, padding: .5em выглядит хорошо при любом размере.

Используйте em для свойств отступов.

Сетка

CSS Grid очень хорошо поддерживается (до IE10!) и позволяет упорядочивать контент в двух измерениях без добавления контейнерных элементов, таких как элементы row или col в Bootstrap. Дизайнеры часто работают в 12-колоночных сетках, а CSS-фреймворки, как правило, следуют их примеру. Но сетки, как и отступы, должны дополнять материал, а не ограничивать его. Они должны писаться в контексте, а не заранее установленным образом.

Выравнивание текста

Text-align часто используется для выравнивания вещей, не являющихся текстом. Это неподходящий инструмент. В подобных случаях лучше пользоваться flexbox.

Использование значений left и right не всегда работает с языками, где письмо идет справа налево или вертикально (некоторые браузеры с этим справляются, но не все).

Использование значения justify по отношению к тексту может привести к проблемам в некоторых языках с лигатурами, а это создает проблемы для людей с дислексией. Любой use case для text-align лучше решать с помощью flexbox. Всегда так делайте.

Контуры

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

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

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

Focus

Фокус и наведение

Как я уже сказал, остерегайтесь изменять стиль :focus, потому что он срабатывает как индикатор того, какой из элементов получает input а данное время. Добавление стилей к элементу :hover часто является хорошей идеей. Но не используйте этот псевдо-селектор для показа дополнительного текста, если вы не делаете того же для :focus (и, конечно, все это годится только для элементов, которые в принципе могут быть в фокусе).

Обычно (хотя и не всегда) бывает удачной мыслью использовать оба псевдо-селектора :hover и :focus для одного набора правил. (Добавление селектора :focus к стилям наведения для кнопки может привести к тому, что нажатая кнопка будет выглядеть «застрявшей»).

Прозрачность

Установление свойства opacity элемента в 0 не прячет его от инструментов доступности. Этот элемент по-прежнему занимает место в документе и его копия по-прежнему читается экранными считывающими устройствами.

Есть только два случая, когда использование свойства opacity разумно:

  • когда элемент становится видимым (быстрый переход от 0 до 1)
  • для стилизации диалогового окна (чтобы немного просвечивал контент под ним).

Остерегайтесь перекрытия полупрозрачных слоев. Уровень прозрачности мультипликативен, поэтому контент, находящийся под двумя слоями, у каждого из которых установлено opacity: 50%, отображается, как если бы он был под одним элементом с opacity: 25%.

Селекторы

Придерживайтесь использования классов и подобных классам селекторов. Использование id, селекторов типов и универсальных селекторов ведет к головной боли. В специфичности CSS id-селекторы всегда побеждают любой другой селектор, но предполагается, что атрибуты id уникальны (на странице), так что они бесполезны для применения стилей, используемых повторно.

Производительностью селекторов в современных браузерах вполне можно пренебречь. Поэтому, хотя вы могли слышать, что универсальный селектор (*) не отличается высокой производительностью, мои сомнения насчет его использования связаны лишь с тем, что он слишком общий практически для любого use-case. Использование селекторов вроде .my-class > * в конечном итоге приводит к выпадению какого-то дочернего элемента. Поэтому с тем же успехом можно добавить классы к нужным элементам и обращаться к ним напрямую.

Аналогичные аргументы можно привести относительно использования селекторов типов, таких как div или main. Они охватывают слишком много элементов и обычно, чтобы быть полезными, требуют уточнений, например, div.some-class. Составные селекторы вроде этого имеют большую специфичность, чем одиночные селекторы классов, а это ведет к ошибкам, о которых я расскажу чуть дальше.

Правила CSS

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

На противоположной от слишком общих селекторов стороне спектра находятся слишком специфичные селекторы. К проблемам приводят оба варианта. Излишне специфичные селекторы порождают еще более специфичные селекторы или ужасные объявления !important. Каждый последующий селектор становится новым препятствием, которое нужно преодолеть при внесении изменений в стили. Такой подход приводит к созданию постоянно растущих и хрупких таблиц стилей, с которыми мы все боимся работать.

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

.btn {
  color: black;
}
.btn--primary {
  color: green;
}
.btn--primary--light {
  color: white;
}

В этом примере каждый одиночный селектор класса более специфичен, чем его предок, что устраняет необходимость задавать наборы правил для .btn.btn—primary или .btn.btn—primary—light.

Фокус в том, чтобы придерживаться, где только возможно, одиночных селекторов классов, писать их в порядке возрастания «важности» и стараться не использовать декларации !important.

Text-transform

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

Z-index

Если в таблицу стилей включено какое-либо правило z-index, там в конце концов окажутся и два других правила, объявляющих z-index: 9999; и z-index: 99999;. Попытки использовать атомарные классы или переменные для ограничения числа допустимых z-index не помешают разработчикам использовать calc() и SCSS-вычисления с целью изменения значения для их use-case. А кроме того, эти попытки совершенно не достигнут цели из-за того, как работают контексты наложения.

По своему опыту могу сказать, что в большинстве случаев (хотя и не во всех) использование z-index может быть заменено:

Всеми силами избегайте использования z-index.

Расположение элементов на странице

Псевдо-элементы

Использовать псевдо-элементы ::before и ::after не только полезно, но и зачастую очень интересно! На применении этих двух псевдо-элементов основано много стилистических приемов. Кроме того, пока в них нет текста (указанного через их свойство content), они могут считаться семантическими. Помещение текста в эти элементы может стать источником проблемы: текст может как читаться, так и не читаться устройствами для обеспечения доступности, это зависит от браузеров и устройств. С подобной несогласованностью лучше не связываться, а для этого не стоит помещать текст в эти псевдо-элементы.

Псевдо-элементы ::first-letter и ::first-line работают не так, как вы, вероятно, думаете. Они нацелены только на первую букву/строку в элементе блочного уровня. Также возникают проблемы, когда селектор ::first-line некорректно указывает на набор двухбайтных символов (например, в японской кане) и диграфы.

Манипуляция со стилями выделенного текста или текста плейсхолдера с помощью

::selection и ::placeholder в указанном порядке часто приводит к проблемам. Что касается ::placeholder, все просто: не нужно использовать плейсхолдеры. Это особенно верно для всего, что имеет значение, например, меток ввода или подсказок. Включая стили ::placeholder, вы поощряете разработчиков, дизайнеров и авторов использовать их, а это по большей части лишь раздражает пользователей.

Изменение стилей выделения, обычно color и background-color, приводит к более мелким, но при этом более коварным багам. Цвета выделения, установленные по умолчанию, разнятся в зависимости от браузера и устройства, они не всегда дают приемлемый контраст с цветом текста на вашем сайте. Однако, пользователи порой переписывают их самостоятельно по причинам, связанным с доступностью. Изменение цветов в этом случае может или не работать (потому что пользовательский CSS для обеспечения доступности перекрывает ваш), или помешать работе пользовательского CSS (если вы используете !important). Применение этого псевдо-элемента в попытках гарантировать контраст для лучшей доступности может в результате только навредить всем тем людям, которым вы хотели помочь.

(Я уже подзабыл подробности бага, с которым я столкнулся несколько лет назад, но тогда автоперевод в Chrome отображался невидимым из-за того, что он зависел от измененных мной стилей ::selection).

Переходы и анимации

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

See the Pen ROCK 🎸 by Vangel Tzo (@srekoble) on CodePen.

Prefers Reduced Motion

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

/* https://github.com/mozdevs/cssremedy/issues/11#issuecomment-462867630 */
@media (prefers-reduced-motion: reduce) {
  *:not(.safe-animation),
  *:not(.safe-animation)::before,
  *:not(.safe-animation)::after {
    animation-duration: 0.01s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0s !important;
    scroll-behavior: auto !important;
  }
}

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

Сброс расширений

Мой обиходный сброс CSS это измененная форма сброса Мейера. Я убрал оттуда несколько правил. В частности, мне не нравится идея удаления значков списка из элементов ol и ul. Я считаю, что это поощряет разработчиков использовать эти элементы несемантическим образом, например, для группировки элементов, которые близки физически, а не онтологически. Также я удалил правило, устанавливающее line-height для body в 1. Установка атрибутов, влияющих на шрифт (или зависящих от шрифтов), отдельно от установки самих шрифтов является багом, который только и ждет, чтобы проявиться.

Ниже я указал, какие дополнения внес в этот набор правил. Я не люблю добавлять атомарный класс .hidden в мой CSS, потому что есть вариант получше – атрибут hidden. Он будет работать, даже если CSS не загружается. Поведение браузера относительно спрятанных элементов display: none, установленное по умолчанию, может быть переписано, в том числе и случайно. Поэтому я добавил правило для его принудительного применения.

body {
  /* more intuitive sizing */
  box-sizing: border-box;
}
*, ::before, ::after {
  box-sizing: inherit;
}
i, cite, em, var, dfn, address {
  /* prevent faux italic */
  font-style: normal;
}
b, h1, h2, h3, h4, h5, h6, strong, th {
  /* prevent faux bold */
  font-weight: normal;
}
[hidden] {
  /* enforce accessible semantics */
  display: none !important;
}

Также я считаю полезным класс visually-hidden. Хотя для невидимого, но читаемого считывающими устройствами текста я чаще использую aria-label, я обычно включаю где-нибудь следующее правило:

/* https://a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden {
  position: absolute !important;
  height: 1px;
  width: 1px;
  overflow: hidden;
  clip: rect(1px, 1px, 1px, 1px);
}

Именование в стиле БЭМ

Не могу завершить эту статью, не упомянув хоть раз соглашения об именах. Мне нравятся имена БЭМ, потому что они хорошо читаются. <button class=»btn—primary» /> точно сообщает мне, что это за кнопка. Мое единственное отступление от официальной методологии БЭМ состоит в том, что я предпочитаю использовать один класс для элемента (с возможным исключением для атомарных классов). Когда я вижу <button class=»btn btn—primary» />, это задевает мои чувства, потому что второй класс уже говорит мне, что стили расширены по сравнению с базовым набором правил btn. Это также создает два повода для изменения строки, а это красный флаг.

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

.btn, .btn--primary {
  /* base button styles */
}
.btn--primary {
  /* primary button overrides */
  /* has naturally higher specificity */
}

В SCSS можно достигнуть того же эффекта, используя @extend.

Заключение

Я пользуюсь этими правилами на протяжении нескольких лет. Они помогают мне поддерживать большие кодовые базы, в создании которых принимает участие много людей. Конечно, эти правила не идеальны и я постоянно их улучшаю (prefers-reduced-motion это новшество), но я надеюсь, что они смогут помочь и другим людям.

ОСТАВЬТЕ ОТВЕТ

Please enter your comment!
Please enter your name here