Руководство по написанию кода frontendanon

Руководство по написанию кода frontendanon

Стандарты для разработки гибкого, надежного и поддерживаемого кода на Pug(Jade) и Stylus.

Оглавление

Золотое правило

Строго соблюдайте предложенные здесь или свои собственные соглашения. Если вы нашли ошибку, будь она большая или маленькая, сразу сообщите об этом. Если у вас есть что дополнить или вы хотите принять участие в разработке этих соглашений, пожалуйста, создайте issue на GitHub.

Каждая строка кода должна казаться написанной только одним человеком, вне зависимости от количества разработчиков.

Настройки редактора кода

Установите в вашем редакторе следующие настройки, которые помогут избежать распространенных несогласованностей в коде и грязи:

  • Использовать мягкие отступы размером в два пробела.
  • Обрезать конечные пробелы при сохранении.
  • Кодировка файлов UTF-8.
  • Добавлять новую строку в конец файлов.

Подумайте над документированием и применением этих настроек в файле .editorconfig вашего проекта. Для примера, ознакомьтесь с файлом настроек для Bootstrap. Узнайте больше об EditorConfig.

Синтаксис

  • Используйте мягкие отступы с двумя пробелами — это единственный способ гарантировать, что ваш код будет везде одинаково выглядеть.
  • Вложенные элементы должны иметь отступ (два пробела).
  • В атрибутах всегда используйте двойные ковычки, но не одинарные.
  • Не добавляйте слэш ("/") в конец одиночного тега — Спецификация HTML5 говорит, что это необязательно.
<!DOCTYPE html>
html(lang="en-us")
  head
    meta(charset="UTF-8")
    meta(http-equiv="X-UA-Compatible" content="IE=Edge")
    meta(name="viewport" content="width=device-width,initial-scale=1")
    title Title page
    link(rel="stylesheet", href="css/main.css")
  body.page
    include blocks/header/header.pug
    ...
    include blocks/text/text.pug
    script(src="js/main.js")

HTML5 doctype

Укажите в начале каждой вашей HTML-страницы этот тип документа. Это заставит браузер работать в режиме соответствия стандартам, что обеспечит единообразное отображение ваших страниц в разных браузерах.

<!DOCTYPE html>
html
  head

Атрибут языка

Из спецификации HTML5:

Для указания языка документа авторам рекомендуется прописывать атрибут языка в корневом элементе html. Это поможет инструментам синтеза речи определить какое произношение использовать, а инструментам перевода - какие правила, и так далее.

Подробнее познакомиться с атрибутом lang можно в спецификации.

Список кодов различных языков на Sitepoint.

html(lang="en-us")

Режим совместимости Internet Explorer

IE поддерживает использование специального <meta>-тега, который указывает в режиме совместимости с какой версией IE следует отрендерить страницу. Если обстоятельства не требуют какой-то специальной версии IE, то самым правильным будет заставить браузер использовать режим самой последней версии (edge mode).

Для получения дополнительной информации следует познакомиться со статьей на Stack Overflow.

meta(http-equiv="X-UA-Compatible" content="IE=Edge")

Кодировка символов

Явно объявив кодировку символов, вы быстро и легко обеспечите правильное отображение вашего контента. При этом, вы сможете избежать использования символьных сущностей в вашем HTML-коде, при условии, что их кодировка совпадает с кодировкой документа (как правило, UTF-8).

head
  meta(charset="UTF-8")

Подключение CSS и JavaScript

Согласно спецификации HTML5, при подключении CSS и JavaScript файлов не требуется указание атрибута type, так как text/css и text/javascript являются значениями по умолчанию.

Ссылки на спецификацию HTML5:

<!-- Внешний CSS -->
link(rel="stylesheet", href="css/main.css")

<!-- CSS внутри документа -->
style
  /* ... */

<!-- JavaScript -->
script(src="js/main.js")

Практичность важнее чистоты

Старайтесь соблюдать стандарты HTML и семантику, но не за счет практичности. Используйте меньшее количество разметки с наименьшим числом тонкостей, когда это возможно.

Порядок атрибутов

Для удобства чтения HTML-атрибуты должны быть указаны именно в этом порядке:

  • class
  • id, name
  • data-*
  • src, for, type, href
  • title, alt
  • aria-*, role

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

a(class="..." id="..." data-modal="toggle" href="#") Какая-то ссылка

input(class="form-control" type="text")

img(src="..." alt="...")

Логические атрибуты

Логические атрибуты одни из тех, которые не требуют объявленного значения. XHTML требует от вас задать значение, но в HTML5 нет такого требования.

За подробной информацией обратимся к разделу о логических атрибутах на WhatWG:

Наличие логического атрибута у элемента говорит об истинном его значении, а отсутствие атрибута — о ложном.

Если вы должны указать значение атрибута, но вам это не нужно, следуйте этой рекомендации от WhatWG:

Если атрибут присутствует, его значение должно быть либо пустой строкой или [...] каноническим именем атрибута без начальных или конечных пробелов.

Если коротко, то не указывайте значение логическому атрибуту.

input(type="text" disabled)

input(type="checkbox" value="1" checked)

select
  option(value="1" selected) 1

Сокращение разметки

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

<!-- Неплохо -->
span(class="avatar")
  img(src="...")

<!-- Лучше -->
img(class="avatar" src="...")

Разметка, генерируемая с помощью JavaScript

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

Подход к разработке стилей

    Mobile first использующий следующие разрешения:
  • mobile (экраны шириной от 0 до 640px), стили пишутся без использования медия выражений
  • tablet = 40em (экраны шириной от 640px и больше), стили пишутся в медиа выражении @media (min-width: tablet)
  • screen = 64em (экраны шириной от 1024px и больше), стили пишутся в медиа выражении @media (min-width: screen)
  • screen_large = 90em (экраны шириной от 1440px и больше), стили пишутся в медиа выражении @media (min-width: screen_large)
.element
  ...

.element-avatar
  ...

.element-selected
  ...

@media (min-width: tablet) 
  .element
    ...

  .element-avatar
    ...

  .element-selected
    ...

@media (min-width: screen)
  .element
    ...

  .element-avatar
    ...

  .element-selected
    ...

@media (min-width: screen_large)
  .element
    ...

  .element-avatar
    ...

  .element-selected
    ...

Синтаксис

  • Используйте мягкие отступы с двумя пробелами — это единственный способ гарантировать, что ваш код будет везде одинаково выглядеть.
  • При группировке селекторов помещайте каждый селектор на отдельную строку.
  • Фигурные скобки не используются.
  • После объявления : не ставится.
  • Каждое объявление должно находится на отдельной строке для более точного сообщения об ошибках.
  • Для свойств, значения которых разделены запятыми, следует оставлять по одному пробелу после каждой запятой (например, box-shadow).
  • Не оставляйте пробелов после запятых внтури значений rgb(), rgba(), hsl(), hsla(), или rect(). Это помогает различать различные цветовые значения (запятая без пробела) от нескольких значений одного свойства (запятая с пробелом).
  • Начальный ноль для значений (например, 0.5 вместо .5).
  • Все 16-ичные значения записывайте строчными буквами (в нижнем регистре), например, #fff. Строчные буквы гораздо легче различить при просмотре файла, поскольку они, как правило, имеют больше уникальных форм.
  • Используйте короткие 16-ичные значения везде, где это возможно, например, #fff вместо #ffffff.
  • Всегда берите в кавычки значения атрибутов внутри селектора, например, input[type="text"]. В некоторых случаях это делать необязательно, но это является хорошей практикой для поддержки согласованности.
  • Опускайте единицы измерения при нулевом значении, например, margin: 0; вместо margin: 0px;.

Есть вопросы по перечисленным соглашениям? Ознакомьтесь с разделом о синтаксисе статьи о каскадных таблицах стилей на Википедии.

/* Плохой Stylus */
.selector, .selector-secondary, .selector[type=text] {
  padding:15px;
  margin:0px 0px 15px;
  background-color:rgba(0, 0, 0, 0.5);
  box-shadow:0 1px 2px #CCC,inset 0 1px 0 #FFFFFF
}

/* Хороший Stylus */
.selector,
.selector-secondary,
.selector[type="text"]
  padding 15px
  margin 0 0 15px
  background-color rgba(0,0,0,0.5)
  box-shadow 0 1px 2px #ccc, inset 0 1px 0 #fff

Порядок объявления

Объявления свойств должны быть по алфавиту

.declaration-order 
  background-color #f5f5f5
  border 1px solid #e5e5e5
  border-radius 3px
  bottom 0
  color #333
  display block
  font normal 13px "Helvetica Neue", sans-serif
  height 100px
  left 0
  float right
  line-height 1.5
  opacity 1
  position absolute
  right 0
  text-align center
  top 0
  width 100px
  z-index 100

Место для media query

Помещайте media queries настолько близко к соответствующим наборам правил, насколько это возможно. Не объединяйте их в отдельную таблицу стилей. Не помещайте их в конце файла. В противном случае это приведет к тому, что media queries будут не замечены в будущем. Вот типичная структура:

.element
  ...

.element-avatar
  ...

.element-selected
  ...

@media (min-width: tablet) 
  .element
    ...

  .element-avatar
    ...

  .element-selected
    ...

Свойства с префиксами

Используется autoprefixer, необходимости в прописывании префиксов нет.

/* Свойства с префиксами */
.selector
  box-shadow: 0 1px 2px rgba(0,0,0,.15)

Правила с одиночными объявлениями

В случаях, когда набор правил включает в себя только одно объявление, оно пишется, так же как с несколькими. Любой набор правил с несколькими объявлениями должен быть разделен на отдельные строки.

/* Одиночные объявления */
.span1 
  width 60px
.span2 
  width 140px
.span3 
  width 220px

/* Несколько объявлений, по одному на каждую строчку */
.sprite 
  display inline-block
  width 16px
  height 15px
  background-image url(../img/sprite.png)

.icon           
  background-position 0 0
.icon-home      
  background-position 0 -20px
.icon-account   
  background-position 0 -40px

Сокращенная запись

Старайтесь ограничить использование сокращенных объявлений в тех случаях, когда необходимо явно задать все доступные значения. Наиболее часто злоупотребляют сокращением следующих свойств:

  • padding
  • margin
  • font
  • background
  • border
  • border-radius

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

На сайте Mozilla Developer Network есть отличная статья о сокращенной записи свойств для тех кто не знаком с такой формой записи.

/* Плохой пример */
.element 
  margin 0 0 10px
  background red
  background url("image.jpg")
  border-radius 3px 3px 0 0

/* Хороший пример */
.element
  margin-bottom 10px
  background-color red
  background-image url("image.jpg")
  border-top-left-radius 3px
  border-top-right-radius 3px

Вложенность

Избегайте излишнюю вложенность. Лучше вообще не использовать. То, что вы можете ее использовать, не означает, что вы всегда должны это делать. Применяйте вложенность только если вам нужно сократить область видимости стилей до родительского элемента, а также при наличии нескольких элементов, которые должны быть вложены.

// Без вложенности
.table > thead > tr > th
  ...
.table > thead > tr > td
  ...

// С вложенностью
.table > thead > tr
  > th
    ...
  > td
    ...

Комментарии

Код написан и поддерживается людьми. Убедитесь, что ваш код является описательным, хорошо прокомментирован и доступным (понятным) для других. Хорошие комментарии к коду передают контекст и цель кода, а не просто повторяют название класса или компонента.

Обязательно пишите законченные предложения для больших комментариев и короткие фразы для общих замечаний.

/* Плохой пример */
/* Modal header */
.modal-header
  ...

/* Хороший пример */
/* Обертывающий элемент для .modal-title и .modal-close */
.modal-header
  ...

Имена классов

  • Используется "классическое именование" БЭМ
  • Придерживайтесь коротких и емких имен классов настолько, насколько это возможно.
  • Используйте осмысленные имена; используйте структурные или целенаправленные имена вместо презентационных.
  • Классы с префиксами должны основываться на ближайшем классе-родителе или на каком то базовом классе.
/* Плохой пример */
.t
  ...
.red
  ...
.header
  ...

/* Хороший пример */
.tweet
  ...

.important
  ...

.tweet-header
  ...

Селекторы

  • Используйте имена классов вместо имен тегов для оптимальной производительности отображения.
  • Избегайте использования нескольких селекторов по атрибуту (например, [class^="..."]) для часто встречающихся компонентов. Это негативно повлияет на производительность браузера.
  • Используйте короткие селекторы и старайтесь ограничить количество элементов в каждом селекторе до трех.
  • Вкладывайте классы в ближайший родительский класс только в случае необходимости (например, когда не используете классы с префиксами).

Дополнительно к прочтению:

/* Плохой пример */
span
  ...
.page-container #stream .stream-item .tweet .tweet-header .username
  ...
.avatar
  ...

/* Хороший пример */
.avatar
  ...

.tweet-header .username
  ...

.tweet .avatar
  ...

Организация кода

  • Посмотрите организацию файловой системы в README.md
  • Организуйте разделы кода согласно вашим компонентам.
  • Разработайте последовательную иерархию для комментариев.
  • Отделяйте разделы кода несколькими пустыми строками. Это упростит просмотр кода в крупных файлах.
  • Когда вы используете множество CSS-файлов, разбивайте их по компонентам, а не по страницам. Страницы могут быть переработаы и компоненты перемещены с одной страницы на другую.
/*
 * Заголовок раздела для компонента
 */

.element
  ...


/*
 * Заголовок раздела для компонента
 *
 * Иногда возникает необходимость включения дополнительного контекста для всего компонента. Сделайте это в этом месте, если это достаточно важно.
 */

.element
  ...

/* Контекстный под-компонент или модификатор */
.element_heading
  ...