От автора: после нескольких лет написания и поддержки нескольких очень больших веб-проектов и множества более мелких, я разработал некоторую эвристики для написания поддерживаемого CSS. Я использовал для именования BEM, SMACSS и CSS Modules, хотя эта статья сама по себе не посвящена именованию. (Я склонен использовать сочетание атомарных классов и именования BEM.) Эта статья о полезных правилах написания CSS, о свойствах и значениях, которые я использую или которых избегаю.
Цвета
Моя больная мозоль — это изобилие цветовых значений в веб-проекте. В большом, долгоживущем проекте, над которым я работал несколько лет назад, было объявлено более 300 уникальных цветов в 40 файлах CSS. Треть из них были оттенками серого. Фирменные цвета повторялись с небольшими различиями оттенков. Многие из этих цветов отличались буквально незаметными значениями, такими как #3426D1 и #3426D2. Решением этой проблемы является использование атомарных классов цвета или переменных (в SCSS или CSS) для принятых корпоративных цветов.
Ограничение количества принятых цветов дает дополнительное преимущество, заключающееся в упрощении проверки соответствия цветов фона и переднего плана рекомендациям WCAG2.0 «Цветовой контраст».
Другая практика, имеющая тенденцию приводить к ошибкам — использование цветов с альфа-каналами, обычно путем объявления цвета с помощью функций rgba() или hsla(). Цвет, созданный таким образом, со значением альфа-канала, отличным от 1, полупрозрачен. Воспринимаемый цвет теперь изменяется в зависимости от фона. Обычно желаемый цвет — это то, как он выглядит на белом фоне, поэтому вместо него можно использовать шестнадцатеричное значение. Некоторые функции препроцессоров, такие как SASS lighten(), генерируют полупрозрачный цвет, поэтому придерживайтесь жестко закодированных значений или переменных.
Типографика
Все свойства, которые влияют или зависят от шрифта, должны быть объявлены один раз в одном месте. Сразу после объявления каких-либо правил @font-face, я добавляю атомарные классы для шрифта, изменяющие font-size (через rem) и включающие line-height, letter-spacing и word-spacing, которые являются подходящими для этой комбинации и размера шрифта. После этого никакие свойства font-* или text-*(за исключением text-overflow) не должны использоваться ни в одном наборе правил.
Объявление этих свойств один раз в сочетании с font-face гарантирует, что текст на сайте всегда выглядит правильно. Корректировка line-height вместо padding или margin создаст ошибки при переносе текста. Корректировка font-weight отдельно от объявления шрифта создает риск создания искусственного шрифта. Изменение font-style шрифта, который это не поддерживает, создает искусственный наклон.
И, наконец, избегайте установки размеров шрифта в чем-либо, кроме rem. Использование em вызывает проблемы при вложении элементов, поскольку em является скалярной кратной единицей для текущего font-size. Использование px (или любых других «фиксированных» единиц) увеличивает риск создать текст, который трудно прочитать и который невозможно будет настроить пользователем. Разрешить пользователю (или браузеру пользователя) устанавливать такое значение font-size, которое они считают правильным, возможно не объявляя font-size для элементов body или html, и только с помощью rem.
Отступы
На сайте, ориентированном на контент отступы должны дополнять дизайн. Любое статическое измерение padding: 4px выглядит неправильным при некоторых размерах шрифта. Динамическое измерение, реагирующее на размеры шрифта, например padding: .5em, выглядит правильно при любом размере шрифта. Используйте em для свойств отступов.
Сетка
CSS Grid очень хорошо поддерживается (вплоть до IE10!) и позволяет организовать контент в двух измерений без дополнительных элементов контейнера — как элементы сетки Bootstrap row или col. Дизайнеры часто работают в сетках из 12 столбцов, а CSS-фреймворки, как правило, следуют этому правилу, но сетки, как и отступы, должны дополнять дизайн, а не ограничивать его. Сетки должны описываться в произвольном порядке, а не в заранее определенном формате без контекста. Не раздувайте CSS «фреймворками сеток».
Выравнивание текста
text-align часто используется для выравнивания чего-либо, кроме текста. Это не неверный подход. Используйте для такого типа выравнивания flexbox. Используя значений left и right не всегда работает для языков с написанием справа налево или вертикально (некоторые браузеры соотносят их со значениями потока start и end, но не все). Использование значения justify в тексте может вызвать проблемы в некоторых языках с орграфами, а также может вызвать проблемы у людей с дислексией. Каждый вариант использования text-align лучше решается с помощью flexbox, поэтому вместо этого используйте его. Всегда.
Обводка
Контур обводки для элементов это то, с помощью чего браузеры индицируют, какой элемент в данный момент выделен фокусом. Контуры по умолчанию, как правило, достаточно заметны, чтобы быть полезными для каждого пользователя, включая тех, кто нуждаются в высокой контрастности. Однако, как правило схема по умолчанию переписывается (или удаляется), поскольку она не соответствует дизайну сайта. Если вы не заменяете стиль обведения контуром фокуса каким-либо другим заметным и доступным индикатором фокуса, не удаляйте и не отменяйте свойство обведения.
Фокус и наведение
Как было сказано выше, остерегайтесь изменения стиля :focus, потому что он работает как индикатор того, какой элемент в настоящее время выделен фокусом ввода. Добавление стилей для :hover часто привносит красивые штрихи, но не используйте этот псевдо-селектор для отображения дополнительного текста, если вы не делаете то же самое для :focus (и, конечно, если элемент является фокусируемым). Как правило, но не всегда, уместно использовать как :hover, так и :focus для того же набора правил. (Добавление селектора :focus в стили наведения для кнопки может привести к тому, что нажатая кнопка будет выглядеть «застрявшей».)
Непрозрачность
Добавление значения 0 для opacity элемента на самом деле не скрывает его от инструментов доступности. Элемент все еще занимает место в потоке документа, и его текст все еще читается программами чтения с экрана. Единственные два варианта использования, для которых целесообразно использование свойства opacity — это при вводе элемента в представление (быстрый переход от 0 к 1) и при стилизации модельного диалогового окна (таким образом, содержимое под ним частично просматривается через фон). Остерегайтесь «стекированных» полупрозрачных наложений. Уровень непрозрачности является мультипликативным, поэтому содержимое ниже двух наложений, каждое из которых отображается с opacity: 50%, приведет к тому, что нижнее будет отображаться так, как будто для него задано opacity: 25%.
Селекторы
Придерживайтесь использования классов и классоподобных селекторов. Использование идентификаторов, типов и универсальных селекторов сопряжено с потенциальными сложностями. В специфичности CSS селекторы идентификаторов всегда имеют приоритет над любыми другими селекторами, но атрибуты id должны быть уникальными (для каждой страницы), поэтому они бесполезны для применения повторно используемых стилей.
Производительность селектора в современных браузерах — незначительная проблема, поэтому, несмотря на то, что вы, возможно, слышали о том, что универсальный селектор (*) не работает, у меня на практике возникает проблема связанная с тем, что он слишком общий для почти каждого варианта использования. Использование селектора наподобие .my-class > * в конечном итоге приведет к выпаданию какого-либо дочернего элемента, поэтому вы можете просто добавить классы к элементам, которые хотите стилизовать, и выбрать их напрямую.
В силу аналогичных соображений можно не использовать селекторы типа, такие как div, main. Они имеют тенденцию соответствовать слишком большому количеству элементов и обычно требуют большего количества деталей, чтобы быть полезными, например div.some-class. Подобные составные селекторы имеют более высокую специфичность, чем одиночные селекторы классов, что связано с проблемами, рассмотренными ниже.
Придерживайтесь селекторов классов (.class), атрибутов ([attribute]) и псевдо-классов (:focus). Все они имеют одинаковый уровень специфичности.
Специфичность
На противоположном конце спектра от селекторов, являющихся слишком общими (как, например, *), находятся селекторы являющиеся слишком специфичными. Оба случая вызывают проблемы. Слишком специфичный селектор порождает еще более специфичные селекторы или страшные объявления !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-индексов не только помешает разработчикам использовать calc() и математические вычисления SCSS для изменения значения для их варианта использования, но и полностью нивелирует цель из-за того, как работают контексты стека.
По моему опыту, в большинстве, если не во всех, сценариях z-index могут быть заменены путем реструктуризации HTML для использования естественного контекста стека (элементы ниже в коде страницы отображаются выше в контексте) или путем добавления свойства к элементу или его родительскому элементу, чтобы ввести новый контекст стека. Избегайте использования z-index любой ценой.
Псевдо-элементы
Использование псевдо-элементов ::before и ::after не только полезно, но часто еще и весело! Многие приемы стилизации основаны на использовании этих двух псевдо-элементов, и, когда в них нет текста (через их свойство content), они считаются семантическими. Проблема с размещением текста в этих элементах заключается в том, что то, читаются они или нет устройствами доступности, зависит от конкретных браузеров и конкретных устройств. Лучше не иметь дело с этим несоответствием, избегая размещения в них текста.
Псевдо-элементы ::first-letter и ::first-line не работают так, как вы, вероятно, думаете. Они предназначены только для первой буквы / строки в элементе уровня блока. Существуют также проблемы с селектором ::first-line, неправильно выбирающим двухбайтовые символы (такие как японская кана) и орграфы.
Манипулирование стилями выделенного текста или текста-заполнителя с помощью ::selection и ::placeholder, соответственно, часто приводит к проблемам. Для ::placeholder решение просто: вы не должны использовать заполнители. Это особенно актуально для важных вещей, например, для меток полей или подсказок. Включая стили ::placeholder, вы поощряете разработчиков, дизайнеров и авторов использовать их, к большому разочарованию ваших пользователей.
Изменение стилей выделения, обычно color и background-color, приводит к более тонким, но существенным ошибкам. Несмотря на то, что цвета выбора по умолчанию не согласованы в разных браузерах и устройствах, и они не всегда обеспечивают приемлемый контраст с цветом текста вашего сайта, пользователи иногда перезаписывают их по причинам доступности. Изменение цветов в этом случае может либо не сработать (из-за того, что пользовательские привилегии доступа CSS превосходят ваши), либо может привести к конфликтам с их таблицам стилей (если вы используете !important). Использование этого псевдо-элемента, чтобы гарантировать доступную контрастность, может привести к нарушению работы для тех людей, которым вы хотите помочь.
(Хотя я уже не помню все подробности, несколько лет назад я столкнулся с проблемой, когда автоматически переведенный в Chrome текст стал невидимым, потому что он опирался на стили ::selection, которые я изменил.)
Переходы и анимация
Переход или анимация свойств, отличных от opacity и transform заставляют браузер перерисовывать или переформатировать страницу. Это может не быть проблемой на высокопроизводительной машине разработчика, но это приведет к зависанию на недорогих ноутбуках и телефонах. Плохая анимация хуже, чем отсутствие анимации.
Меньше движения
Написание анимации, которая полезна, красива и безопасна, является непростым делом. С появлением медиа-запроса prefers-reduced-motion мы можем помочь сделать наши страницы более безопасными для людей с вестибулярными расстройствами и менее раздражающими для всех. Хотя добавление этого медиа-запроса не является серебряной пулей, это помогает. Я написал вложенное правило для отказа, означающее, что все CSS-анимации останавливаются, если автор не включает для элемента класс safe-animation.
/* 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 — это модифицированная форма сброса Мейерса. Однако есть несколько правил, которые я удаляю из сброса. Я не люблю удалять значки элементов списков ol и ul. Я считаю, что это побуждает разработчиков использовать эти элементы несемантическим образом, таким как группировка элементов, которые являются близкими физически, но не онтологически. Я также удаляю правило, задающее line-height: 1для body. Установка атрибутов, которые влияют на шрифт или зависит от него, отдельно от установки шрифта, является ошибкой.
Некоторые дополнения к файлу сброса приведены ниже. Я не люблю включать в свой CSS атомарный класс .hidden, потому что есть лучший вариант, который будет работать, даже если CSS не загружается — атрибут hidden. Поведение браузера по умолчанию при установке display: none для скрытых элементов может быть перезаписано даже случайно, поэтому я включаю правило для его принудительного применения.
body { /* более интуитивное определение размеров */ box-sizing: border-box; } *, ::before, ::after { box-sizing: inherit; } i, cite, em, var, dfn, address { /* предотвращает несоответствующее использование наклонного шрифта */ font-style: normal; } b, h1, h2, h3, h4, h5, h6, strong, th { /* предотвращает несоответствующее использование жирного шрифта */ font-weight: normal; } [hidden] { /* вводит семантику доступности */ 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); }
Именование BEM
Я не могу закончить эту статью без упоминания о соглашениях об именах. Мне нравится именование BEM, потому что оно хорошо читаемо. <button class=»btn—primary»/> говорит мне, что это за кнопка. Единственное, в чем я отхожу от официальной методологии BEM, это то, что мне нравится использовать один класс для элемента (за исключением атомарных классов). <button class=»btn btn—primary»/> — это оскорбляет мою чувствительность, потому что второй класс уже говорит мне, что стили выходят из базового набора правил btn. Это также создает две причины для изменения строки.
В моем CSS это выглядит так:
.btn, .btn--primary { /* базовые стили кнопок */ } .btn--primary { /* переопределение первичной кнопки */ /* имеет естественную высшую специфичность */ }
В SCSS вы можете добиться того же эффекта, используя @extend.
Заключение
Это были мои практические правила, которые в течение нескольких лет помогают мне поддерживать большие базы кода со многими участниками. Они не идеальны, и я всегда корректирую их (prefers-reduced-motion является новым), но я надеюсь, что это может помочь другим разработчикам.
Источник: https://www.freecodecamp.org
Редакция: Команда webformyself.