Ошибки и спорные вопросы в HTML-CSS вёрстке

Часть 3: стилизация

Набор подходов и решений в области HTML-CSS-верстки, которые я считаю спорными или ошибочными (ошибки описаны мои, моих коллег, студентов). Все статьи цикла:

Стилизация

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

Набор стилей без Emmet-а

Используйте аббревиатуры Emmet-а для набора свойств — это быстрее ручного набора (даже с автодополнением) и так гораздо сложнее допустить опечатку.

Игнорирование кодгайда

Примеры кодгайдов: руководство по написанию кода школы Epic Skills (целиком написано мной), Стиль кода Академии HTML (немного приложил руку), Code Guide by @mdo — кодгайд от Марка Отто (автор Bootstrap), именно этим материалом вдохновлены две предыдущие ссылки, Принципы написания однородного CSS-кода — от Николаса Галлахера.

Для читаемости и простоты модификации важно не только правильно форматировать код, но и писать правила в некоторой очередности (с автоматической сортировкой может помочь CSScomb).

Неучёт ограничений и особенностей CSS

Я не смогу упомянуть все особенности стилизации. Постараюсь привести наиболее важные/забавные.

  • Внешние отступы перекрываются (для двух «блочных» соседей: если у первого есть margin-bottom: 30px;, а у второго margin-top: 20px;, расстояние между ними будет 30px). Но есть исключения (см. ниже).
  • При подсчёте размеров берется прописанный размер и к нему добавляется ширина бордюра и внутреннего отступа (можно написать для блока width: 100px; padding: 10px; и получить реальную ширину 120px). Сделать подсчёт размера более интуитивным помогает глобальное изменение box-sizing (см. ниже).
  • Внутри flex- и grid-контекстов перестают работать некоторые свойства (float, vertical-align, CSS-колонки), а внешние отступы перестают схлопываться.
  • Если внутри родителя с измененным transform дать какому-либо потомку position: fixed;, это не сработает, такой потомок не будет фиксирован во вьюпорте.
  • Flexbox прекрасен, но в ряде браузеров некоторые теги не могут стать flex-контейнерами. К примеру, в Safari невозможно сменить свойство display для тегов button, fieldset, legend, они не смогут стать flex-контейнерами. Учитывайте, однако, баги flexbox (перевод).

Любопытно, какие особенности использования CSS важны для вас. Напишите в комментариях.

Использование некроссбраузерных решений

Некоторые задачи могут быть легко решены CSS-свойствами, имеющими плохую поддержку браузерами. Использовать решения, приводящие к различному отображению в разных браузерах, допустимо редко и при условии согласования с заказчиком. Больше всего проблем кроссбраузерности наблюдается с продукцией Microsoft — Internet Explorer и Edge.

Примеры: CSS-фильтры, grid (поддержка старой версии спецификации означает, скорее, отсутствие поддержки).

Многосоставные селекторы

Многосоставные (2-х и более) селекторы во многих случаях приводят к проблемам:

  • необходимость учитывать не только очередность, но и «вес» селектора,
  • привязка стилей к определенной разметке (сложно модифицировать).

Многие методологии рекомендуют избегать вложений. Но это не означает его запрет, бывают ситуации, когда без этого сложно обойтись. К примеру, при стилизации выводимых из CMS фрагментов (контент-менеджер не должен заботиться о написании классов).

В БЭМ, который я использую (и всем советую) каскад напрямую не запрещен, но я ограничиваюсь двусоставным (крайне редко — трехсоставным).

Отдельно — о каскадной модификации. Это случай, когда вы меняете свойства вложенного блока, отталкиваясь каскадом от его родителя (вместо написания класса-модификатора). При необходимости получить такую же модификацию в другом месте начнутся проблемы. Однако, есть исключение: для некоторых проектов может быть удобно добавлять класс на корневом теге (html ) и менять что-либо каскадом, отталкиваясь от такого класса (может потребоваться при контроле загрузки шрифтов, определении браузера или его возможностей, изменении вида для авторизованного посетителя). Я считаю каскадную модификацию от корневого элемента допустимой.

Стилизация по тегам и по id

Атрибут class специально существует для привязки стилей, используйте его. Редко допустима комбинация с тегами, псевдоселекторами или иными атрибутами. Не стилизуйте по id, ибо такие селекторы «больше весят» и их невозможно повторить в рамках одной страницы.

Нюанс — стилизация заголовков: если использовать в селекторе тег, сложно добиться возможности быстро поменять уровень заголовка (может потребоваться в интересах SEO) или даже заменить заголовок на div . Стилизовать неконтентные заголовки нужно по классу и так, чтобы при смене тега визуально ничего не изменилось.

Написание вендорных префиксов

Если на вашем проекте вообще есть необходимость писать правила с вендорными префиксами, оставьте это автоматике постобработки CSS.

Смена box-sizing без возможности легко вернуть к умолчанию

Есть два способа сменить боксовую модель: простой и правильный.

Простой способ меняет это свойство для универсального селектора:

* { box-sizing: border-box; }

При этом если потребуется использовать в проекте сторонний компонент, автор которого не менял боксовую модель, стили компонента сломаются.

Есть более безопасный и более правильный путь:

html { box-sizing: border-box; }
*, *::before, *::after { box-sizing: inherit; }

То есть, все элементы наследуют box-sizing от корневого, но если потребуется поменять, достаточно на каком-либо селекторе вернуть box-sizing: content-box; и все его потомки унаследуют это свойство.

Использование !important и/или overflow: hidden; для исправления багов

Встречал такое: вместо поиска места проблемы (и ее ликвидации) автор пишет правило с !important . Другой вариант: для ликвидации горизонтального скролла пишут overflow: hidden; на одной из общих обёрток.

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

Игнорирование переполнения/недополнения контентом

Переполнение и недополнение контентом/субблоками должно быть главным, о чём вы думаете, когда пишите стилизацию.

Если где-то есть текст, его может стать много или совсем мало (при этом верстка не должна сломаться, должна вести себя логично). Познакомьтесь с «Электрокардиографической одиннадцатиклассницей, предпочитающей циклопентанпергидрофенантрен» и с «Ю Ли».

Если в дизайне показан поток из 6 блоков (по 2 в ряд), нужно учесть что блоков может стать от нуля до 13 (не особо важно сколько именно, важно что много и что будет неполный последний ряд).

Один из «рефлексов верстальщика»: зафиксировал блоку ширину или высоту — подумай о переполнении.

Объединение стилей оберток и отдельных блоков

Обычно, есть раскладка блоков по страницам и есть сами блоки. Смешивать на одном селекторе стили для раскладки и стили оформления блоков — порочный путь, ибо усложняет перенос блоков и другую модификацию.

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

Если не хочется писать лишних оберток, можно попробовать миксовать (термин из БЭМ) класс обертки с классом блока на одном теге, но в этом случае вы (или другой разработчик) сможете смешать правила.

Использование CSS-импортов

Обычно, я прошу студентов забыть, что в CSS есть @import, на что есть несколько причин:

  • если в одном CSS-файле указан импорт другого, то импортируемый фал начнет загружаться только после парсинга первого файла, то есть, загрузка будет последовательной (помните, что рендеринг блокирован во время загрузки стилевых файлов),
  • до наступления эпохи http2 (когда за одно соединение с сервером можно будет получить два и более файла) лучше конкатенировать все стилевые файлы в один.

Программирование на CSS-препроцессорах (особенно если не умеете программировать)

Не программируйте на CSS-препроцессорах. Когда мы разбираемся в работе/багах применённых стилей, меньше всего нам хочется тратить время на разбор сложных структур, из которых эти стили скомпилировались.

Да, с Sass/LESS/stylus я могу написать код, который будет коротким и его будет довольно сложно понять, но это не признак крутости. Совсем наоборот: сложнее = хуже (дольше разбираться как это работает). Нечто, более-менее похожее на программирование допустимо в CSS-препроцессорах в примесях (к примеру, в примесях-генераторах правил модульной сетки).

Из допустимого (интуитивно понятного) на мой взгляд: вложения селекторов и @media в контекст селекторов, амперсанд, переменные, разбиение на файлы (и препроцессорный импорт таких мелких файлов в диспетчере подключений). Подробнее — в коротком руководстве о том, как не выстрелить себе в ногу с препроцессорами и БЭМ.

Неучёт возможных проблем с загрузкой

Вы знаете что происходит внутри браузера, когда вы отправляете запрос на какой-либо адрес? Как он загружает ресурсы (и когда отправляет за ними запросы), что именно случается перед показом страницы на экране? Хорошо, если ответ положительный. Если же не уверены, то познакомьтесь с объемным описанием того, как работает браузер. Это материал примерно 2011 года, но, полагаю, если механизмы и изменились, то незначительно.

Если совсем коротко: загрузка стилевых файлов блокирует рендеринг (поэтому мы и пишем их в head, чтоб скорее загрузились, читайте, так же, про Critical CSS), загрузка JS-файлов (без специальных атрибутов) останавливает выполнение очереди загрузки прочих файлов до загрузки и выполнения скрипта (поэтому мы стараемся писать подключения скриптов перед /body (но не всегда получается)).

Неучёт количества будущих точек модификации

Хорошо написанные стили, помимо логичности и быстрой читаемости, обладают еще одним важным свойством: при модификации нужно менять правила в минимальном количестве мест.

Вернемся к примеру о блоках-виджетах в сайдбаре: если прописать ширину самим блокам-виджетам, то в случае необходимости сменить ширину сайдбара, править придется в нескольких местах (для каждого блока). Если же виджеты имеют ширину 100% и реальная ширина сайдбара прописана единожды для селектора сайдбара, точка модификации лишь одна.

Понравилась статья? Ставьте лайк, делитесь в соц. сетях или купите мне кофе.