Оглавление
HTML
HTML-доктайп
В начале страницы обязательно должен быть указан актуальный doctype, чтобы браузер отображал её в режиме соответствия стандартам. Это гарантирует, что страница будет выглядеть единообразно во всех современных браузерах.
<!DOCTYPE html>
<html lang="ru">
<head>…</head>
<body>…</body>
</html>
Кодировка символов
Кодировка символов на странице всегда должна быть явно указана, чтобы обеспечить корректное отображение текста. Кодировка utf-8 предпочтительна.
<head>
<meta charset="utf-8">
<title>Заголовок страницы</title>
</head>
Отступы
Используйте отступы с двумя пробелами. Разместите файл .editorconfig (универсальные базовые настройки редактора) в папке проекта и установите его поддержку в редакторе.
<nav class="main-nav">
<ul>
<li><a href="/index.html">Главная</a></li>
<li><a href="/contacts.html">Контакты</a></li>
</ul>
</nav>
<img src="logo.svg" width="50" height="50" alt="Company">
Синтаксис
- Теги и атрибуты пишите строчными буквами.
- Значения атрибутов всегда пишите в двойных кавычках.
- Не добавляйте слэш (
/) в конец одиночного тега. - Не пропускайте необязательные закрывающие теги (например,
</li>или</body>). - Разделяйте крупные фрагменты разметки пустыми строками
<!-- 😊 Хорошо: Все тэги и атрибуты соответствуют правилам -->
<figure>
<img src="dog.png" alt="Собака" width="100" height="100">
</figure>
<!-- 💩 Плохо: тэги не совпадают, нарушены правила для атрибутов -->
<FIGURE>
<img src='DOG.png' ALT="Собака" width='100' HEIGHT="100" />
Порядок атрибутов
Атрибут класса у HTML-элементов пишется первым. Единообразное написание помогает легче считывать код и быстрее разбираться в назначении блоков по их классам.
Остальные атрибуты могут быть расставлены в любом порядке, но тоже единообразно для одинаковых элементов.
<a class="element element-big" id="element" href="/" data-name="element">Ссылка</a>
<input class="form-control" type="text" name="test">
<img class="pets-picture" src="cats.jpg" alt="Изображение котиков">
Логические атрибуты
Для логических атрибутов (например, checked, disabled, required) значение не указывается, а сами атрибуты указываются последними и в единообразной последовательности во всём документе.
<!-- checked="checked" необязательно -->
<input type="checkbox" required checked>
<input type="text" disabled>
<select>
<option value="1" selected>1</option>
</select>
Подписи полей ввода
Для улучшения взаимодействия пользователя с элементами форм, при нажатии на подпись поля, оно должно активироваться. Для этого элемент формы связывается с его описанием с помощью идентификатора и атрибута for тега <label>.
<!-- 😊 Хорошо: элемент формы radio связан с подписью через идентификатор -->
<input type="radio" id="choose">
<label for="choose">Радио кнопка</label>
<!-- 😊 Хорошо: элемент формы radio и подпись обёрнуты в label -->
<label>
<input type="radio"> Радио кнопка
</label>
<!-- 💩 Плохо: подпись не связана с элементом формы -->
<input type="radio" id="choose"> Радио кнопка
Размеры картинок
Изображениям <img> должны быть явно заданы с помощью атрибута размеры в пикселях. В случае пикселей размерность не нужна.
По возможности изображениям указываются действительные размеры, так как это улучшает производительность отрисовки страницы: браузер не будет перерисовывать страницу в процессе загрузки и отображения изображения.
<!-- 😊 Хорошо: размеры картинке заданы -->
<div class="logo-area">
<img src="logo.png" alt="" width="300" height="150">
</div>
<!-- 💩 Плохо: размеры картинке заданы в px -->
<div class="logo-area">
<img src="logo.png" alt="" width="300px" height="150px">
</div>
<!-- 💩 Плохо: размеры картинке не заданы -->
<div class="logo-area">
<img src="logo.png" alt="">
</div>
Отсутствие логичной иерархии заголовков
Иерархия важна как для SEO, так и для восприятия страницы в случае отсутствия стилей (не загрузились по каким-то причинам). Заголовки, так же, очень важны для доступности страницы.
<!-- 😊 Хорошо: порядок заголовков правильный -->
<h1>Главный заголовок</h1>
<h2>Второстепенный заголовок</h2>
<!-- 💩 Плохо: порядок заголовков нарушен -->
<h2>Второстепенный заголовок</h2>
<h1>Главный заголовок</h1>
Игнорирование семантики тегов
Часть тегов универсальны, часть имеют семантику (разной степени). К примеру, есть div — универсальный блок, а есть section — часть чего-либо (к примеру, большого «подвала»), которая при вырывании из контекста частично теряет смысл, и есть article — блок с наиболее выраженной семантикой (будучи вырван из контекста, сохраняет осмысленность полностью).
Всегда нужно применять наиболее подходящие по смыслу теги: списки, таблицы, параграфы, заголовки и пр. должны использоваться по назначению. Это улучшает индексацию сайта (и вообще понимание страницы роботами) и доступность.
<!-- 😊 Хорошо: блок размечен с соблюдением семантики -->
<header></header>
<section>
<article>
<figure>
<img>
<figcaption></figcaption>
</figure>
</article>
</section>
<footer></footer>
<!-- 💩 Плохо: семантика отсутствует -->
<div id="header"></div>
<div class="section">
<div class="article">
<div class="figure">
<img>
<div class="figcaption"></div>
</div>
</div>
</div>
<div id="footer"></div>
Ссылки с javascript:void(0)
Псевдо-протокол javascript: давно устарел. Он поддерживается браузерами, но не описывается в веб-стандартах.
Раньше такую конструкцию использовали для кнопок, но теперь доступен тэг button.
<!-- 😊 Хорошо: кнопка сделана через тэг <button> -->
<button type="button">Я кнопка</button>
<!-- 💩 Плохо: кнопка сделана ссылкой -->
<a href="javascript:void(0)">Я кнопка</a>
Поведение кнопки по умолчанию
По умолчанию у кнопки type="submit". Не забывайте явно указывать тип, чтобы избежать нежелательных багов.
<!-- 😊 Хорошо: кнопкам указан тип -->
<button type="button">Я просто кнопка</button>
<button type="submit">Я кнопка для отправки формы</button>
<!-- 💩 Плохо: типы кнопок не указаны -->
<button>Я просто кнопка</button>
<button>Я кнопка для отправки формы</button>
Ссылки с target="_blank"
Для ссылок с target="_blank" следует добавлять атрибут rel="noopener noreferrer". Это увеличивает производительность и безопасность приложения.
<!-- 😊 Хорошо: ссылке указан атрибут rel -->
<a href="https://svyaznoy.ru/" target="_blank" rel="noopener noreferrer">
Ссылка на сторонний ресурс
</a>
<!-- 💩 Плохо: атрибут rel не указан -->
<a href="https://svyaznoy.ru/" target="_blank">
Ссылка на сторонний ресурс
</a>
Телефоны и почта
Используйте <a> для всех элементов, которые могут куда-либо вести, даже если в макете этот элемент отрисован как обычный текст, так как в данном случае ссылка — логический элемент, а не визуальный.
tel:+1234567890– для указания телефона. Номер должен начинаться с плюса и состоять только из чисел без спецсимволов типа пробелов, круглых скобок или дефиса;mailto:mail@mail.ru– для указания e-mail;
<!-- 😊 Хорошо: для телефона сделана ссылка -->
<a href="tel:+79999999999">
+7(999)999-99-99
</a>
<!-- 💩 Плохо: телефон сделан как обычный текст -->
<span>
+7(999)999-99-99
</span>
Типограф
Когда текст статичен, мы имеем к нему доступ, он не приходит из CMS – следует прогонять его через типограф.
<!-- 😊 Хорошо: в тексте расставлены неразрывные пробелы -->
Каждая строка кода должна казаться написанной только одним человеком, вне зависимости от&nbsp;количества разработчиков.
<!-- 💩 Плохо: текст без специальных символов -->
Каждая строка кода должна казаться написанной только одним человеком, вне зависимости от количества разработчиков.
БЭМ. Зачем?
- Самодокументируемость.
- Имитация пространства имён (простота и безопасность модификации).
- Отсутствие зависимости от DOM-структуры.
- Проектное реиспользование блоков.
- Кросспроектное реиспользование блоков.
Само понятие БЭМ — не только метод именования селекторов, но парадигма восприятия проекта как набора сущностей (блоки, элементы, модификаторы). Полный стек БЭМ подразумевает двойную шаблонизацию и имеет относительно высокий порог входа. Используйте БЭМ хотя бы как способ именования селекторов.
<!-- Блок `search-form` -->
<form class="search-form">
<!-- Элемент `input` блока `search-form` -->
<input class="search-form__input">
<!-- Элемент `button` блока `search-form` -->
<button class="search-form__button">Найти</button>
</form>
Блок — это самостоятельная часть страницы
- Название класса должно быть простым и коротким.
- Название класса должно отвечать на вопрос «Что это?»
- Не используйте сокращения кроме наиболее частых
- Название не должно отвечать на вопрос «Как выглядит?»
<!-- .product — БЭМ-блок -->
<div class="product">
...
</div>
Блоки можно и нужно вкладывать друг в друга
- Нет ограничений на вложения блоков, помимо здравого смысла.
- Никакой дополнительной специфики вложенные блоки не имеют.
<!-- .page-header — БЭМ-блок -->
<div class="page-header">
<!-- .logo — вложенный БЭМ-блок -->
<a class="logo">...</a>
</div>
Элемент — часть БЭМ-блока
- Название класса формируется из названия блока с добавлением
__и названия элемента. - Название класса должно быть простым и коротким.
- Название класса должно отвечать на вопрос «Что это?»
- Избегайте сокращений, кроме наиболее частых.
- Название не должно отвечать на вопрос «Как выглядит?»
<div class="product">
<!-- product__image — БЭМ-элемент блока product -->
<img class="product__image" src="..." alt="...">
<!-- product__description — БЭМ-элемент блока product -->
<p class="product__description">...</p>
<!-- product__more-link — БЭМ-элемент блока product -->
<a class="product__more-link" href="">...</a>
</div>
Элемент можно использовать вне его блока только в исключительных случаях
Элемент — часть блока, но, поскольку, БЭМ-дерево независимо от HTML-дерева, элемент можно использовать и вне его блока в некоторых исключительных условиях (сам блок должен быть на странице).
Пример: расположение попапа-элемента не внутри блока-родителя, а в самом конце DOM (дабы показывать попап независимо от ограничения видимости родителей).
<body>
<header>
<div class="tooltip">
<button class="tooltip__anchor"></button>
</div>
</header>
<div class="tooltip__box">
Контент в тултипе в конце DOM
</div>
</body>
Элементов может не быть
Не у всех блоков должны быть элементы: кнопка — всегда БЭМ-блок, но БЭМ-элементы у неё внутри встречаются относительно редко.
<!-- Нет ошибки: блок без элементов -->
<a class="btn" href="">Скачать</a>
Как отличить БЭМ-блок и БЭМ-элемент
Просто задайте себе вопрос: «Эта сущность может потребоваться мне отдельно, сама по себе? Или она нужна только внутри её родителя?» Если нужна отдельно — это БЭМ-блок, если мыслима только внутри родителя — это БЭМ-элемент.
В действительно сомнительных случаях делайте выбор в пользу БЭМ-блока.
Не забывайте о миксовании (возможности иметь на одном теге и класс уровня БЭМ-элемента какого-то родительского блока, и свой класс уровня БЭМ-блока).
На всех проектах (кроме совсем уж крошечных или имеющих гарантировано нулевую возможность модификации) есть фрагменты дизайна, которые мудро всегда делать БЭМ-блоками по причине высокой вероятности повторения.
Некоторые фрагменты дизайна — всегда БЭМ-блоки
- Кнопка (любые кнопки)
- Блоки внутри форм (блок для текстового поля, блок для радиокнопки и т.п.)
- Пагинация
- Табы
- Лейблы (метки)
- Социальные ссылки
- «Лайк» со счётчиком
<button type="button" class="btn">Кнопка</button>
Модификатор — дополнительный класс для смены оформления или поведения
- Название класса формируется из названия блока/элемента с добавлением -- и названия модификатора.
- Название должно быть простым и коротким.
- Название класса может отвечать на вопросы «Что это?», «Что меняется?», «Чем отличается от прочих?»
- Избегайте сокращений, кроме наиболее частых.
<!-- .product--size-large — БЭМ-модификатор -->
<div class="product product--size-large">
...
</div>
Модификатор нельзя использовать самостоятельно
Класс модификатор никогда не должен использоваться самостоятельно, но всегда только с тем классом, который он модифицирует.
<!-- 😊 Хорошо: модификатор сопутствует модифицируемому классу -->
<div class="product product--size-large">
...
</div>
<!-- 💩 Плохо: модификатор без класса, который он модифицирует -->
<div class="product--sale">
...
</div>
Миксование — комбинирование на одном теге классов БЭМ-блока и БЭМ-элемента
Комбинация возможна в любом сочетании: БЭМ-блок + БЭМ-элемент, БЭМ-блок + БЭМ-блок, БЭМ-элемент + БЭМ-элемент. Этот подход позволяет:
- Добавить некоторые стилевые свойства, необходимые только в месте добавления (использование модификатора нерационально). Пример: для
.btnвнутри.page-headerнеобходим внешний левый отступ в 37 пикс. Можно дописать для тега с.btnдополнительный класс.page-header__btnи дать отступ с помощью этого селектора. Это нормальная практика, её можно спокойно использовать. - Объединить стилизацию 2-х и более блоков. Пример: для
.articleи для.page-footer__sectionшрифтовые свойства одинаковы. Можно вынести определение шрифтовых свойств в новый блок.textи дописать этот класс на.articleи.page-footer__section. Этот подход излишне связывет части страницы (напоминает OOCSS и класс-хелпер), не делайте так. - Обойтись без тега-обёртки с добавляемым селектором. Пример: страница каталога, 7+ товаров в потоке, каждый товар —
.product, но каждому элементу потока нужны стилевые свойства ячеек модульной сетки (по которой выстроен потоковый вывод). Можно добавить для.productкласс ячейки модульной сетки, что бы не делать обертку с этим классом. Это чревато конфликтом отступов/размеров, не смешивайте на одном теге классы обёртки и содержимого.
Миксование несколько ухудшает восприятие кода и увеличивает вероятность ошибки смешения стилей, при которой вы пишите стилевое правило в контексте не того селектора, где оно реально нужно.
<div class="page-header">
<div class="page-header__nav-wrap">...</div>
<a class="btn page-header__btn" href="/buy">...</a>
</div>
<div class="slider">
<div class="promo slider__inner">
<div class="promo__item slider__item">
...
</div>
</div>
</div>
БЭМ-дерево плоское, в отличие от DOM
В классах БЭМ-элементов нельзя прописывать иерархию (два и более сегмента __ недопустимы).
<div class="promo">
<div class="promo__description">
<!-- 😊 Хорошо: вложенный элемент не имеет особенностей -->
<a class="promo__link" href="">...</a>
</div>
</div>
<div class="promo">
<div class="promo__description">
<!-- 💩 Плохо: попытка прописать иерархию -->
<a class="promo__description__link" href="">...</a>
</div>
</div>