Ревью верстки: 10 полезных замечаний и советов

Статья рассчитана на новичков в верстке, но не исключено, что и опытный верстальщик узнает себя в каком-то из пунктов. Примеры ниже написаны с использованием соглашения по именованию селекторов БЭМ, препроцессора Sass и шаблонизатора Jade.


Code-review для верстки часто пренебрегают, отчасти, возможно, из-за сложившегося стереотипа, что верстать нужно, набрав побольше воздуха, зажмурившись и раскидываясь хаками и костылями, пока не будет достигнута та самая неуловимая кроссбраузерность. А поддерживать чужую верстку — только человеку с крепкими нервами и достаточным запасом медикаментов.

Мы пообщались с разработчиками в Noveo и сошлись во мнении, что важно не только тестирование, но и ревью. Особенно важно ревьюить стажеров и новичков, чтобы скорректировать недочеты и не дать сформироваться вредным привычкам. Так, в какой-то момент у наших коллег накопилась небольшая статистика по замечаниям и советам, а как следствие появилась эта статья. Ниже в статье описаны 10 типичных ошибок верстальщиков-новичков и советы по их устранению.

Ошибка 1: Не продумана структура проектной папки

Довольно часто верстальщикам ставят задачи постранично и макеты предоставляют тоже постранично. Это иногда порождает иллюзии, что работы мало и вся верстка будет прекрасно себя чувствовать в 2—3 папках, а если нет, то всегда найдется время поправить структуру. Но чем больше блоков и страниц сверстано, чем ближе к релизу и чем больше страниц / компонентов уже интегрировано, тем сложнее что-то изменить.

Предлагаю с первого же коммита поддерживать прозрачную структуру. Вот пример структуры проектной папки, которую мы использовали на зимней стажировке 2016:

Идёт загрузка… Если ничего так и не загрузилось, то посмотрите пример здесь.

Совсем необязательно в точности копировать эту структуру, достаточно обратить внимание на ряд моментов:

1. Вспомогательные документы, блоки и страницы живут отдельно

В Jade базовый шаблон, блок карусели и страница должны находится в отдельных директориях. Так их будет проще найти. Кроме того, сборщику проекта для компиляции следует «скармливать» только папку со страницами, чтобы не засорять проектную папку ненужными HTML документами для компонент.

В scss общие стили типа reset, или подключения шрифтов, или лейаута верхнего уровня стоит также хранить отдельно от стилей для страниц и блоков. Также целесообразно импортировать все в один документ (например, main.scss) и только этот документ компилировать в css. По объективным причинам таких документов может быть несколько (например, из-за ограничения по количеству селекторов / весу css-документа в IE9 или для поставки специфических стилей для редко встречающихся устройств отдельно от основного документа), но, как и с Jade, не стоит компилировать все подряд.

2. Jade-блоки = БЭМ-блоки

Если у вас небольшой опыт работы с шаблонизаторами, это дробление может слегка напугать, но на самом деле работать с большим количеством документов для компонентов гораздо удобнее, чем в одном документе с тремя тысячами строк. Ничто не мешает объединять компоненты в директории, если проект большой. Так компоненты легко переиспользовать и «инклюдить» на разные страницы, а для компонентов с разными состояниями и/или разным контентом (например, для кнопок) можно написать миксин, который может в качестве входных параметров принимать контент, модификатор или значение атрибута.

В итоге в коде index.jade и других страниц должна быть строчка, указывающая на базовый шаблон, возможно, 1—2 тега верхнего уровня, инклюды и вызов миксинов.

Например:

3. Scss зеркалит Jade

Если в Jade-директории blocks есть какой-то документ, то стили для него должны находиться в Scss-директории blocks в документе с таким же названием.

Например, согласно структуре, указанной выше, стили для jade/1_blocks/header.jade должны лежать в scss/3_blocks/header.scss, а не где-то еще. Если следовать этому простому правилу, то вносить изменения будет удобно всем разработчикам на проекте, даже новым.

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

Добавить .gitkeep во все пустые папки можно с помощью этой команды:

После заполнения папок не забудьте удалить ненужные .gitkeep.

Ошибка 2: копипаста есть, комментариев нет

С копипастой нужно быть особенно аккуратным: вдумчиво все перечитать, исправить «под проект» и удалить лишнее. Однажды мне встретилось:

, при этом обычный <title> содержал совершенно другую строку :).

Не важно, делаете вы редизайн или используете решение из интернета, пока копипаста не будет переработана, рядом с ней должен быть комментарий с TODO, чтобы:

  • не забыть и не утащить этот кусок в продакшн,
  • дать понять другим разработчикам, что это не окончательное решение,
  • дать понять ревьюеру, что этот код будет изменен.

Например:

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

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

У авторов статей есть такой прием — вычитка, когда написанный текст перечитывают несколько раз, чтобы исправить пропущенные ошибки и перефразировать предложения, которые плохо звучат. Рекомендую активно проводить вычитку своего кода и особенно копипасты. Еще в борьбе с копипастой в стилях может очень пригодиться csscomb.

Ошибка 3: блоки влияют друг на друга, одни и те же селекторы встречаются в нескольких местах в scss

Великая сила амперсанда в Sass позволяет писать стили по БЭМ и делать это еще нагляднее. Такой код:

Будет скомпилирован в:

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

Блок — это отдельный компонент, который не знает о других блоках и их расположении.

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

Такой код будет ошибочным, т.к. состояние одного блока влияет на элемент в другом блоке:

Если возникает необходимость так написать, значит, что-то пошло не так на этапе именования, нужно незамедлительно вернуться к Jade и исправить атрибуты class так, чтобы каждый блок был независимым. Если же заплатка нужна срочно и времени на изменения разметки нет, то оставьте комментарии TODO в обоих документах: в scss и в jade.

Говоря о том, что блок не знает о других блоках, хочется вкратце упомянуть об одном полезном псевдоклассе, о котором постоянно забывают новички. Представьте лейаут верхнего уровня: есть блок с основным контентом и блок aside. Для двух этих блоков указана ширина в %, но на одной странице aside нет и ширина блока с основным контентом должна быть 100%. Тут нам на помощь придет псевдокласс only-child:

Идёт загрузка… Если ничего так и не загрузилось, то посмотрите пример здесь.

В случаях, когда only-child не подходит, используйте модификаторы.

Ошибка 4: не использовать миксины, когда можно использовать миксины

Миксины очень помогают следовать принципу DRY (Don’t Repeat Yourself), их активно используют в scss для таких абстрактных задач, как сетка, но о них почему-то забывают, когда речь заходит о верстке компонент. Например, у вас есть кнопки разных цветов, у которых на ховере происходит инверсия цвета. Для инверсии можно написать миксин и сделать стили чуточку чище:

Идёт загрузка… Если ничего так и не загрузилось, то посмотрите пример здесь.

Также советую обратить внимание на плейсхолдеры, которые, к сожалению, мне пока не встречались в верстке новичков.

В Jade тоже следует активнее использовать миксины. Например, для svg-спрайтов:

Идёт загрузка… Если ничего так и не загрузилось, то посмотрите пример здесь.

Ошибка 5: беспорядок в медиазапросах

Частая ошибка — смешивать mobile-first и desktop-first подходы. Сейчас, когда IE8 перестал фигурировать в спеках, можно смело переходить на mobile-first. Если макеты готовы только для десктопа, попробуйте повлиять на дизайнера, ссылаясь, например, на эту книгу. В любом случае, будете вы использовать min-width или max-width,  используйте что-то одно. Иначе в какой-то момент станет тяжело отслеживать логику изменения стилей, а значит, проблематично поддерживать верстку.

Кроме того, не стоит писать медиазапросы по хардкоду, используйте как минимум переменные для брейкпоинтов. Т.е. вместо:

должно получиться:

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

В scss есть возможность вкладывать медиазапросы в правила. Например:

Это будет скомпилировано в:

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

Большое количество медиазапросов не сказывается ощутимо на производительности, но, разумеется, сказывается на весе css документа. Если у вас большой проект со сложной организацией контента, медиазапросов много, то, возможно, стоит задуматься об их комбинации.

Ошибка 6: не интересоваться UX-проектированием

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

Для начала предлагаю обратить внимание на типичную ошибку новичка: ссылки и кнопки маленького размера, между ними мало пространства. Это ок, если взаимодействие происходит мышкой, но совершенно не годится, когда речь идет о тач-устройствах. Многократные попытки попасть по ссылке, которые в результате приводят к попаданию по соседней ссылке, очень быстро выводят пользователей из себя. Наверняка каждый из нас бывал в такой ситуации, и первое, что хочется сделать, — покинуть неудобный сайт. Чтобы такого не происходило с вашими пользователями, советую почитать гайдлайны от Google или SmashingMagazine.

Ошибка 7: все в пикселях, даже font-size

Советую сделать (если вы еще нее сделали) переход с px на em и rem для таких значений, как:

  • размер шрифта и высота строки,
  • размеры иконок,
  • размеры кнопок,
  • вертикальный ритм.

В рамках БЭМ для блока: rem для размера шрифта блока, em — для остальных величин блока. Для элемента есть 2 стратегии:

  1. em для размера шрифта, если структура html уже утвердилась и вряд ли добавится / убавится еще один уровень вложенности,
  2. rem — если в рамках блока вероятны изменения (перемещение элементов, добавление или удаление оберток и т.п.).

Чтобы понять разницу между единицами изменения или выбрать между em и rem, предлагаю обратить внимание на канал DevTips, на котором в весьма непринужденной форме объясняются основы верстки.

Также с псевдоэлементами и em стоит быть осторожней:

«Если в IE9+для одного и того же псевдоэлемента задать размер шрифта через разные селекторы, то он просто перемножит все размеры шрифтов.» (источник)

Ошибка 8: не думать о переполнении и предельных значениях

Верстая по макету, мы имеем дело с идеальной ситуацией. Так новички довольно часто забывают про угрозу переполнения, т.е. когда контент не помещается в блок или элемент и выходит за его пределы. Эту ситуацию нужно срочно исправлять, ведь верстальщик — это еще и своего рода переводчик интерфейса с языка дизайнерского на язык, понятный программистам. Поэтому очень важно в процессе верстки выявить предельные значения объема текста для кнопок, заголовков и прочих элементов с ограниченной вместимостью. Об этих предельных значениях стоит сообщить разработчикам (как минимум написать комментарий в HTML) и по возможности ограничить переполнение в css:

Идёт загрузка… Если ничего так и не загрузилось, то посмотрите пример здесь.

То же касается и изображений. Совсем не факт, что изображения будут загружаться в правильных пропорциях или что они будут обрезаться программно в процессе загрузки. Если гарантии сохранения пропорций нет, то лучше сразу в верстке сделать обертку и применить одну из двух техник: вписывание или растягивание по ширине.

Идёт загрузка… Если ничего так и не загрузилось, то посмотрите пример здесь.

Можно также с надеждой смотреть в сторону object-fit, однако у этого свойства пока довольно слабая поддержка.

Ошибка 9: уделять недостаточно внимания графике

Графику обычно делят на 3 части: иконки, изображения контента, фоновые изображения. С фоновыми изображениями у новичков обычно проблем не возникает,  а вот с иконками и контентными изображениями все не так хорошо.

Сегодня стоит предпочесть svg-спрайты иконочным шрифтам, если нет требований к поддержке совсем старых версий IE. Подробное сравнение двух подходов можно прочитать тут и тут. SVG-спрайт тоже можно кешировать, т.е. можно ссылаться на внешний файл, если набор иконок большой и повторяется от страницы к странице. Для кешируемых спрайтов есть полифил, добавляющий поддержку в IE. А в одностраничных приложениях спрайт обычно добавляется в базовый шаблон.

Контентные изображения, например, фото товара, — главная причина большого веса сайтов. На десктопах (особенно на экранах с большой плотностью пикселя) нам нужны изображения в большом разрешении. Их вес обычно не вызывает проблем, т.к. в основном десктопы используют высокоскоростные подключения с неограниченным трафиком. Пользователи мобильных устройств же вынуждены выкачивать лишние мегабайты изображений. А если у них низкая скорость передачи данных, бывают обрывы? Получаем не очень довольных пользователей. Остается только надеяться, что они не в роуминге. Эту ситуацию легко исправить с помощью атрибута scrset у <img> или с помощью тега <picture>. Постепенно поддержка этих возможностей становится лучше, а для старых браузеров есть полифил. Для подробного ознакомления с техникой поставки разных контентных изображений для разных устройств советую бесплатный курс «Responsive images» от Udacity.

Ошибка 10: Pixel Perfect? Не, не слышал.

Не зря этот пункт последний в этой статье — о Pixel Perfect часто забывают (кстати, не только новички). С одной стороны, верстальщик почти всегда действует, опираясь на макет, с другой — немножко от этого макета отступает. В процессе работы над проектом какие-то компоненты могут меняться местами, от каких-то отказываются, появляются новые и т.п. Размеры элементов могут немного меняться в зависимости от контента (смотри переполнение и предельные значения). В конце концов, дизайнер может допустить ошибку при выравнивании элементов по сетке. Все это — адекватные причины, чтобы локально отказаться от pixel perfect и верстать «по ситуации». В идеале каждое отступление от макета должно быть задокументировано.

В случаях, когда нет причин отклоняться от макета, стоит четко ему следовать (помочь в этом может, например, расширение для Chrome — Pixel Perfect).

В заключение хотелось бы призвать верстальщиков активнее участвовать в code-review, ведь это повод не только улучшить качество кода начинающего верстальщика, но и систематизировать знания уже опытных коллег, ревьюеров.


За материал выражаем благодарность международной IT-компании Noveo.