6 лет назад мы обсуждали с сообществом критерии качества вёрстки, которые мы используем в обучении, чтобы наши выпускники радовали рынок своими умениями и подходом к работе.
С тех пор в разработке интерфейсов произошло море изменений: сначала в продакшн пришли флексы, потом подтянулись гриды, умер IE, все переехали из Фотошопа в Фигму, и много чего ещё. Каждое это изменение влияло на наши критерии, и мы постоянно их дорабатывали.
Сейчас пришло время снова обсудить с сообществом обновлённые критерии, чтобы наши выпускники продолжали радовать индустрию своим уровнем.
Ниже представлена обновлённая система критериев, которую мы планируем внедрить на осенних запусках курсов. Мы публикуем её сейчас, чтобы собрать обратную связь от сообщества и внести изменения в критерии.
Что описывают и что не описывают эти критерии
Эти критерии касаются нашего первого уровня вёрстки, то есть задач, связанных с фиксированной вёрсткой без адаптивности и без специфичных требований к вёрстке (например, по натяжке на конкретную CMS).
Критерии для задач, связанных с адаптивностью, автоматизацией, натяжкой на CMS или вёрсткой под React, мы тоже планируем обсудить с сообществом, когда подготовим их.
Как устроена система критериев
На курсе ученик верстает макет (вот такого уровня сложности), и на защите в конце курса эту вёрстку по критериям качества проверяет случайный наставник. Защита считается успешной, если зачтены все обязательные критерии.
Помимо обязательных есть и дополнительные критерии, их выполнение для успешной защиты не нужно, но они позволяют более точно оценить качество работы и показать ученику как улучшить свой код. Дополнительные критерии в нашей системе помечены звёздочкой.
Для удобства обсуждения критерии разбиты на категории, некоторые критерии относятся к процессу приёмки проекта, некоторые к качеству кода.
Также для многих критериев мы попытались написать обоснование, зачем нужен критерий, и почему он именно такой. И будем рады, если в результате обсуждений появятся новые обоснования или дополнятся текущие.
TEST-01. Кроссбраузерность
Необходимо смотреть на размеры и расположение блоков, внешнее сходство с макетом.
Необходимо проверить работу анимации, если такая имеется.
Допускаются небольшие отличия в отображениях шрифтов.
Вёрстка должна идентично отображаться в последних стабильных версиях браузеров Chrome, Firefox, Safari, если иное не указано в техзадании проекта.
Назначение критерия
Пользователи сайта могут использовать разные браузеры в разных системах, поэтому нужно добиваться единого отображения.
TEST-02. Технологии
Проект должен быть сделан на HTML и CSS без использования сторонних библиотек и фреймворков.
Назначение критерия
Задача курса — научить решать задачи с помощью базовых технологий. Полученная база позволит разобраться, как работают фреймворки или библиотеки.
TEST-03. Размеры страницы
У каждой страницы есть минимальная ширина по фрейму.
При ширине окна больше минимальной страница центрируется.
Горизонтальная прокрутка появляется только при ширине, меньше минимальной.
Допускаются расхождения по горизонтали, не превышающие ширину полосы вертикальной прокрутки.
Примеры и назначение критерия
![Скриншот экрана на большом разрешении. Только вертикальный скролл. Скриншот экрана на большом разрешении. Только вертикальный скролл.](https://habrastorage.org/getpro/habr/upload_files/41d/145/bbc/41d145bbca9d23d40b05ef27fe5d2d23.png)
![Если на странице убрать лишние элементы, и выставить разрешение артборда (1020px), то горизонтальный скролл пропадает. Если на странице убрать лишние элементы, и выставить разрешение артборда (1020px), то горизонтальный скролл пропадает.](https://habrastorage.org/getpro/habr/upload_files/1fb/dd7/be8/1fbdd7be8cb43e790d6507a8a7cc624d.png)
Зачем нужен критерий
В качестве ориентира для ширины страницы используется фрейм, потому что мы считаем Figma преобладающим форматом макетов и поэтому пользуемся терминами этого графического редактора. В учебных макетах мы учли минимальную ширину, но в реальной разработке минимальная ширина страницы может отличаться от размера фрейма.
У страницы должна быть минимальная ширина, чтобы у пользователей с меньшим разрешением при просмотре страницы оставались работоспособны все элементы сайта.
Контент страницы должен быть отцентрирован, чтобы у пользователей с большим разрешением при просмотре страницы контент находился перед глазами — в центре страницы.
TEST-04. Переполнение
Длина текста
Текст должен оставаться в рамках родительского блока при переполнении.
Текст не должен обрезаться или вываливаться из родительского блока при переполнении.
Текст не должен смещать другие блоки.
Родительский блок должен сохранять минимальные размеры при недополнении.
Слова, длиннее минимальной ширины, должны переноситься.
Размеры элементов
Контент больше ширины родителя не должен выходить за его пределы, ломать сетку или смещать другие блоки.
Количество элементов
При увеличении количества элементов они должны оставаться в рамках родительского блока.
Элементы могут переноситься на следующую строку при уменьшении размера родителя.
При минимальном количестве элементов или их отсутствии родительский блок должен сохранять минимальные размеры.
Последние блоки в сетках должны выравниваться по направлению текста.
Примеры и назначение критерия
Длина текста
Текст должен оставаться в рамках родительского блока при переполнении и не должен вываливаться или обрезаться из родительского блока.
![](https://habrastorage.org/getpro/habr/upload_files/6d7/81c/241/6d781c241a815ec18cc65d9292f041d6.png)
Родительский блок должен сохранять минимальные размеры при недополнении.
![](https://habrastorage.org/getpro/habr/upload_files/3b8/936/def/3b8936def474026009aff9bde621022c.png)
Слова длиннее минимальной ширины должны переноситься.
![](https://habrastorage.org/getpro/habr/upload_files/e53/3cb/598/e533cb5988ce8b81ecd1933f96c9bf1b.png)
Размеры элементов
Контент больше ширины родителя не должен выходить за его пределы, ломать сетку или смещать другие блоки.
![](https://habrastorage.org/getpro/habr/upload_files/fcf/7d8/6d1/fcf7d86d18a5dc921ac03faa2a5e9d31.png)
Контент больше ширины родителя не должен выходить за его пределы, ломать сетку или смещать другие блоки.
Количество элементов
При увеличении количества элементов они должны оставаться в рамках родительского блока и последние блоки должны выравниваться по направлению текста.
![](https://habrastorage.org/getpro/habr/upload_files/086/656/413/08665641332e8ab6cd5f65020d14f214.png)
Элементы могут переноситься на следующую строку при уменьшении размера родителя.
![](https://habrastorage.org/getpro/habr/upload_files/216/96f/4c8/21696f4c89b5a4e9e7cf3022cba6ffb7.png)
При проверке переполнения в браузере Safari необходимо добавлять текст не через инспектор браузера, а через редактор кода, редактируя страницу HTML. В противном случае текст будет добавляться в одну длинную строчку.
Зачем нужен критерий
Верстальщик должен предусматривать ситуации, в которых контент может меняться, и подготавливать вёрстку к изменениям контента.
TEST-05. Шрифты
Следующие текстовые параметры должны соответствовать параметрам из макета:
семейство шрифта
font-family
;насыщенность шрифта
font-weight
;начертание шрифта
font-style
;размер шрифта
font-size
;высота строки
line-height
;цвет текста
color
.
Назначение критерия
При проверке этого пункта следует ориентироваться именно на параметры, указанные в макете. Из-за особенностей отображения шрифтов на разных платформах, определение этого критерия на глаз может привести к ошибке. Помимо этого, стоит допускать разное межбуквенное расстояние в макете и в финальной вёрстке. Считать разное межбуквенное расстояние ошибкой стоит только в том случае, если оно явно указано в макете.
TEST-06. Pixel Perfect
При наполнении контентом, как в макете, элементы каждой страницы соответствуют макету.
Допускаются:
различия в 5 пикселей по высоте при расстояниях более 30 пикселей и 2 пикселя по ширине;
различия в отображении шрифтов, связанные со сглаживанием на различных платформах.
Примеры и назначение критерия
![Пример идеального прохождения ПП. Пример идеального прохождения ПП.](https://habrastorage.org/getpro/habr/upload_files/744/f7b/537/744f7b53733b70aad1dfa592903d7f98.png)
![Пример не идеального, но допустимого несовпадения элементов. Пример не идеального, но допустимого несовпадения элементов.](https://habrastorage.org/getpro/habr/upload_files/b8c/a4d/1ad/b8ca4d1ad9896a180b966b0058d76f0e.png)
![Вариант несовпадения. Вариант несовпадения.](https://habrastorage.org/getpro/habr/upload_files/c61/a0d/0a9/c61a0d0a9eda4ca520390b26cb2745f0.png)
![Вариант, когда накопились несоответствия по предыдущим блокам. Смещение макета в PixelPerfect исправляет эту проблему. Вариант, когда накопились несоответствия по предыдущим блокам. Смещение макета в PixelPerfect исправляет эту проблему.](https://habrastorage.org/getpro/habr/upload_files/d30/0ef/958/d300ef958a18f4cd19bd1d0eadc1bc2e.png)
Рекомендуем проверять с помощью инструмента PerfectPixel (работает в Chrome, Firefox).
Зачем нужен критерий
Заказчик может не принять работу, если вёрстка будет отличаться от согласованному макета. Поэтому веб-разработчик должен не просто сверстать сайт по образцу, а сделать это близко к согласованному макету.
Чтобы сайт как можно точнее совпадал с утвержденным дизайном, веб-разработчики придерживаются концепции Pixel Perfect. Это способ вёрстки строго по макету, при котором размеры и интервалы из макета соблюдаются с точностью до нескольких пикселей.
Допустимые различия нужны для компенсации несоответствий макету, связанных с отличиями отображения элементов в разных графических редакторах, браузерах и операционных системах.
TEST-07. Стайлгайд
Все состояния элементов должны соответствовать стайлгайду, предусмотренному в макете. Стайлгайд — это часть дизайна проекта, он имеет наивысший приоритет. При наличии стайлгайда верстальщик должен ему следовать.
Если в стайлгайде не предусмотрены состояния элемента, то их нужно реализовать на своё усмотрение.
Для элементов форм, кнопок и ссылок:hover
, focus
, active
.
Для элементов форм: disabled
.
Назначение критерия
При проверке этого пункта следует оценивать наличие эффектов и их соответствие стайлгайду.
TEST-08. Взаимодействие
При взаимодействии с элементами (наведение, нажатие) ни сам элемент, ни окружающие его блоки не меняют своего положения, если такое поведение не предусмотрено макетом.
Примеры
Правильно
Неправильно
Неправильно
Неправильно
PROJ-01. Кодгайд
Код должен быть написан с соблюдением требований кодгайда Академии.
Примеры и назначение критерия
Правильно. Код написан в одном стиле.
<section class="news">
<h2 class="news-title">Новости</h2>
</section>
<section class="news">
<h2 class="news-title">Галерея</h2>
</section>
.news {
color: #000000;
}
.news-title {
color: #ff0000;
background-color: #ffffff;
}
Неправильно. Одинаковые элементы разметки имеют разные отступы и переносы.
<section class="news-title">
<h2 class="news-title">
Новости
</h2>
</section>
<section class="news-title"><h2 class="news-title">Галерея</h2></section>
Неправильно. Один и тот же цвет написан в разных нотациях.
.news {
color: red;
}
.news-title {
color: rgb(255, 0, 0);
background-color: #ffffff;
Зачем нужен критерий
Требования, перечисленные в кодгайде Академии, нужно соблюдать в рамках обучения. В других компаниях требования могут отличаться.
Кодгайд необходим для сохранения единообразия кодовой базы, которое помогает всем участникам команды работать в одинаковых условиях.
PROJ-02. Именование
Названия папок, файлов, атрибутов, классов должны состоять из английских слов.
Рекомендуем записывать слова полностью, без сокращений. Для сокращений можно использовать слова из списка часто используемых слов.
Примеры и назначение критерия
Именование папок и файлов
Правильно. Названия папок и файлов состоят из английских слов.
barbershop/
styles/
styles.css
images/
logo.svg
hammer.jpg
sun.png
Неправильно. Названия папок и файлов написаны транслитом или не словами.
proekt/
stili/
stili.css
SCripts/
MySctips.js
i/
logotip.svg
098sd9f8sd0f8.png
imagine image.jpg
Именование классов
Правильно. Названия классов состоят из английских слов.
.header-logo {
…
}
.footer-social {
…
}
Неправильно. Названия классов написаны транслитом.
.shapka {
/* стили */
}
.podval {
/* стили */
}
.glavniy-logotip {
/* стили */
}
Правильно. Значения атрибутов состоят из английских слов.
<label for="name"></label>
<input class="field" id="name" type="text">
Зачем нужен критерий
Английский язык — это общепринятая договорённость в среде разработчиков. Единый подход именования позволяет быстрее знакомиться с кодовой базой.
PROJ-03. Название папок и файлов
Файлы и папки должны быть записаны строчными буквами без пробелов между словами.
Примеры и назначение критерия
Правильно. Названия файлов и папок написаны строчными.
barbershop/
styles/
styles.css
images/
logo.svg
hammer.jpg
sun.png
Неправильно. Названия папок содержат прописные буквы.
barbershop/
Styles/
Styles.css
SCripts/
MySctips.js
IMAGES/
imagine image.jpg
В качестве разделителей должны использоваться только дефисы -
или подчёркивания _
. Выберите только один стиль — -
или _
. Разделители должны использоваться последовательно.
Правильно. Многосоставные названия разделяются дефисами.
barbershop/
images/
logo-full.svg
twitter-logo.jpg
header-bottom-border.png
Неправильно. Многосоставные названия содержат разные разделители.
barbershop/
images/
logotip.svg
link__active-before.png
header-border_bottom.jpg
Зачем нужен критерий. Перечисленные требования продиктованы кодстайлом Академии. В других командах и проектах требования могут отличаться. Критерий говорит о том, что важно соблюдать кодстайл команды, в которой вы работаете. Кроме того, в некоторых системах названия папок и файлов регистрозависимые, и единообразное именование защитит вас от возможных проблем, связанных с регистром.
PROJ-04*. Закомментированный код
В проекте не должно быть закоментированных фрагментов кода без осмысленного текстового пояснения.
Примеры и назначение критерия
Правильно. Комментарий описывает механику взаимодействия с элементом. Таким образом передаются знания от одного разработчика другому.
<!-- Чтобы попап отображался необходимо добавить класс popup-active -->
<div class="popup popup-active">
<div class="popup__overlay"></div>
</div>
Правильно. Комментарий скрывает часть разметки, но при этом имеет пояснение, в каком случае эту часть нужно восстановить.
<div class="popup popup-active">
<div class="popup__overlay"></div>
<!-- Если в попапе есть карта, то добавить див и в него вложить карту
<div class="popup-map"></div>
-->
</div>
Правильн
Правильно. Комментарии поясняют структуру разметки, позволяя быстрее навигировать по файлу.
<!-- Header -->
<header class="header"></header>
<!-- Список пунктов -->
<ul>
<li>Пункт</li>
<li>Пункт</li>
</ul>
<!-- Price -->
<section class="price"></section>
<!-- Footer -->
<footer class="footer"></footer>
/* Header */
.header {
…
}
/* Footer */
.footer {
…
}
Неправильно. Код закомментирован и не имеет описания.
<!--
<div class="popup">
<div class="popup__overlay"></div>
<!–Разметка попапа–>
</div>
-->
Неправильно. Код закомментирован и имеет неосмысленное описание: комментарий не помогает понять, почему код закомментирован.
<!--TODO: Не забыть удалить
<div class="popup">
<div class="popup__overlay"></div>
<!–Разметка попапа–>
</div>
-->
Зачем нужен критерий. Большое количество закомментированного кода засоряет разметку, усложняет понимание и дальнейшую поддержку кода. Если фрагмент кода по какой-то причине должен быть закомментирован, то хорошие поясняющие комментарии помогут быстрее ознакомиться с его функциональностью.
PROJ-05. Неиспользуемые файлы
В проекте не должно быть неиспользуемых файлов:
Файлы, не подключённые на страницы.
Подключённые файлы, которые ничего не делают.
Файлы svg-изображений, которые заинлайнены в разметку, могут остаться в папке проекта.
Примеры и назначение критерия
Правильно. Файл slider.css
находится в папке проекта и подключен в разметке.
barbershop/
styles/
styles.css
slider.css
<head>
<link rel="stylesheet" href="styles/styles.css">
<link rel="stylesheet" href="styles/slider.css">
</head>
Неправильно. Файл slider.css
находится на файловой системе, но не подключен в проекте.
barbershop/
styles/
styles.css
slider.css // не подключён
<head>
<link rel="stylesheet" href="styles/styles.css">
</head>
Неправильно. Файл slider.css
подключен, но не влияет на стилизацию страницы.
barbershop/
styles/
styles.css
slider.css // подключен, но пустой
<head>
<link rel="stylesheet" href="styles/styles.css">
<link rel="stylesheet" href="styles/slider.css">
</head>
Зачем нужен критерий. Неиспользуемые файлы засоряют файловую структуру и усложняют поддержку сайта.
HTML-01. Ориентиры
На странице, при их наличии, должны быть обозначены структурные ориентиры:
<header>
для вводной части, повторяющейся на других страницах;<main>
для основного содержимого, не повторяющегося на других страницах;<nav>
для важных навигационных элементов по сайту;<aside>
для дополнительного содержимого;<footer>
для закрывающей, дополнительной информации о странице.
Ориентиры могут быть обёрнуты или вложены в другие теги, использоваться для стилизации или просто служить смысловыми обёртками.
Примеры и назначение критерия
Правильно. На странице используются структурные ориентиры. Тега <aside>
нет в структуре, так как такой элемент не предусмотрен дизайном проекта.
<body>
<header>
Лого
<nav>
Меню
</nav>
</header>
<main>
Страница
</main>
<footer>
Контакты
</footer>
</body>
Неправильно. На странице используется <div>
вместо структурных ориентиров.
<body>
<div>
Лого
<div>
Меню
</div>
</div>
<div>
Страница
</div>
<div>
Контакты
</div>
</body>
Зачем нужен критерий. Ориентиры — это элементы, группирующие контент, которые позволяют быстро перемещаться между группами, что важно при навигации по сайту с помощью скринридера.
HTML-02. Заголовки
На странице должен быть
<h1>
, который описывает содержимое страницы.Уровни заголовков должны идти последовательно от большего к меньшему без пропусков.
Исключения, касающиеся наличия одного <h1>
на странице или изменения сквозной структуры заголовков, возможны для тега <article>
, так как внутри него может находиться свой собственный <h1>
и собственная структура заголовков.
Примеры и назначение критерия
Правильно. На странице есть <h1>
, описывающий её содержимое. Заголовки применяются последовательно — от большего к меньшему, без пропусков.
<h1>Каталог</h1>
<section>
<h2>Товары</h2>
<article>
<h3>Товар</h3>
</article>
</section>
<section>
<h2>Доставка</h2>
</section>
Неправильно. На странице нет <h1>. Последовательность заголовков неупорядоченная.
<section>
<h5>Товары</h5>
<article>
<h1>Товар</h1>
</article>
</section>
<section>
<h3>Доставка</h3>
</section>
Правильно. На странице есть <h1>
, описывающий её содержимое, и несколько <article>
с собственными <h1>
. Иерархия заголовков при этом остаётся упорядоченной.
<h1>Каталог</h1>
<section>
<h2>Товары</h2>
<article>
<h3>Товар</h3>
</article>
</section>
<article>
<h1>Барбершоп сегодня закрыт.</h1>
</article>
<article>
<h1>Скидки на новые причёски.</h1>
</article>
Зачем нужен критерий. Иерархия заголовков важна, так как она определяет структуру контента, которую потом могут использовать сторонние программы, например, поисковые роботы или скринридер. Исключения, касающиеся использования <article>
допустимы, но лучше всё равно следовать общим правилам — один <h1>
и уровни заголовков без пропусков.
HTML-03. Кнопки и ссылки
Ссылки <a href>
должны использоваться для перехода между страницами, а кнопки <button>
должны использоваться только для действий на странице.
У ссылок должен быть атрибут
href
. Ссылки, которые ведут на самих себя, могут быть без атрибута.Для ссылок, адрес которых неизвестен, можно использовать атрибут
href
с решёткойhref="#"
.Адреса почты и телефоны должны быть размечены ссылками с соответствующими схемами внутри
href
.У кнопок должен быть явно указан тип действия в атрибуте
type
.
Примеры и назначение критерия
Правильно. Для элементов, предназначенных для перехода между страницами, использован тег <a>.
<!-- Страница catalog.html -->
<nav>
<ul>
<li><a href="#">Главная</a></li>
<li><a>Каталог</a> <!-- в ссылке на каталог не указан href, так как она ведёт на саму себя --></li>
<li><a href="#">Вопросы</a></li>
</ul>
</nav>
Неправильно. Для элементов, предназначенных для перехода между страницами, использован тег <button
>.
<nav>
<ul>
<li><button type="button">Главная</button></li>
<li><button type="button">Каталог</button></li>
<li><button type="button">Вопросы</button></li>
</ul>
</nav>
Правильно. Для почты и телефона использованы схемы mailto:
и tel:
.
<a href="mailto:email@example.com">email@example.com</a>
<a href="tel:+79876543210">+7 987 654-32-10</a>
Неправильно. Для почты и телефона не использован тег <a>
c схемами mailto:
и tel:
.
<span>email@example.com</span>
<p>+7 987 654-32-10</p>
Правильно. Для элемента действия использован тег <button>
.
<button type="button">Закрыть</button>
Зачем нужен критерий. Правильно размеченные ссылки и кнопки улучшают пользовательский опыт и помогают избегать ошибок в работе веб-страниц. Подробнее о том, чем отличаются ссылки и кнопки и какие проблемы могут возникнуть, если использовать неподходящий тег, можно почитать в блоге.
HTML-04. Работоспособные формы
Формы должны быть работоспособными и отправлять данные всех полей.
Поля формы должны находиться внутри тега
<form>
.У формы должен быть указан атрибут
action
.У обязательных полей должен быть атрибут
required
.
Для тестирования формы можно использовать адрес https://echo.htmlacademy.ru.
Примеры и назначение критерия
Правильно. Форма имеет атрибут action
. Все поля формы обёрнуты в тег <form>
.
<form action="https://echo.htmlacademy.ru">
<label>
Логин
<input type="text" name="user" required>
</label>
<label>
Пароль
<input type="password" name="password" required>
</label>
<button type="submit">Отправить</button>
</form>
<form action="https://echo.htmlacademy.ru">
<label>
Поиск
<input type="search" name="search" required>
</label>
<button type="submit">Найти</button>
</form>
Неправильно. У формы не указан атрибут action
.
<form>
<label>
Логин
<input type="text" name="login" required>
</label>
<label>
Пароль
<input type="text" name="password" required>
</label>
<button type="button">Отправить</button>
</form>
Неправильно. Форма поиска не обёрнута в тег <form>
.
<label>
Поиск
<input type="search" name="search" required>
</label>
<button type="submit">Найти</button>
Неправильно. У полей с обязательным заполнением нет атрибута required
.
<form action="https://echo.htmlacademy.ru">
<label>
Логин *
<input type="text" name="user"
</label>
<label>
Пароль *
<input type="password" name="password">
</label>
<button type="submit">Отправить</button>
</form>
Неправильно. У разных полей формы одинаковое значения для атрибута <name>
. В этом случае отправятся данные только одного поля.
<form action="https://echo.htmlacademy.ru">
<label>
Пароль
<input type="password" name="password" required>
</label>
<label>
Повторите пароль
<input type="password" name="password" required>
</label>
<button type="submit">Отправить</button>
</form>
Неправильно. Не указано значение у атрибута name
или отсутствует атрибут name
.
<form action="https://echo.htmlacademy.ru">
<label>
Пароль
<input type="password" name="" required>
</label>
<label>
Повторите пароль
<input type="password" required>
</label>
<button type="submit">Отправить</button>
</form>
Зачем нужен критерий. Формы — это критическая функциональность сайта, поэтому важно, чтобы они были работоспособны и отправляли введённые пользователем данные.
HTML-05. Подписи полей форм
Подписи полей форм должны быть привязаны к своим полям.
Примеры и назначение критерия
Правильно. Описание привязано к полю с помощью оборачивающего <label>.
<label>
Имя
<input type="text" name="text">
</label>
<label>
<input type="text" name="text">
Имя
</label>
Правильно. Описание привязано к полю с помощью атрибута for
у <label>
и id
у <input>
.
<label for="name">Имя</label>
<input type="text" id="name" name="text">
Неправильно. Описание никак не связано с полем формы.
Имя
<input type="text" name="name">
Неправильно. Поле имеет два описания.
<label for="email">Email</label>
<label>
<input id="email" type="email" name="email">
</label>
Зачем нужен критерий. Подписи полей форм отображаются в дереве доступности, что позволяет скринридерам правильно понимать и передавать смысл поля.
HTML-06. Лишние элементы
В разметке не должно быть лишних обёрток и элементов, которые используются для оформления и могут быть заменены на псевдоэлементы.
Примеры и назначение критерия
Правильно. Не используется лишняя обёртка, а для декоративного элемента нет дополнительного блока в разметке.
<div class="features clearfix">
<div class="features-item">
<h2>Быстро</h2>
<p>Мы делаем свою работу быстро!</p>
</div>
…
</div>
Правильно. Допускается использование тега <span>
для стилизации кастомных чекбоксов.
<label class="login-checkbox">
<input type="checkbox" name="remember" class="visually-hidden">
<span class="checkbox-indicator"></span>
Запомните меня
</label>
Неправильно. Используется лишняя обёртка, которую можно сократить, а для декоративного элемента использован тег <span>
, который можно заменить на псевдоэлемент.
<div class="features">
<div class="clearfix">
<div class="features-item">
<h2>Быстро</h2>
<span class="triangle"></span>
<p>Мы делаем свою работу быстро!</p>
</div>
</div>
...
</div>
Если в вёрстке осознанно и единообразно разделяются сеточные и смысловые блоки, это ошибкой не является.
Зачем нужен критерий. Лишние элементы не несут в себе функциональности, поэтому их нужно удалять для упрощения поддержки и переиспользования кода.
HTML-07. Валидация HTML
Разметка должна проходить валидацию в валидаторе W3C без ошибок (
error
).В проверке могут быть предупреждения (
warning
).
Назначение критерия
Главная задача валидатора — проверить, что код соответствует стандартам и спецификациям языка. Код, который не проходит валидацию, может быть неправильно отработан в браузере.
HTML-08. Фавиконки
К каждой странице должны быть подключены иконки с помощью <link rel="icon">
с указанием размера иконки.
В корне проекта должен быть файл
favicon.ico
, но подключать его к странице необязательно.Фавиконки должны быть в размере 32×32 и в формате PNG.
Примеры и назначение критерия
Правильно. Подключена favicon.ico
из корня проекта, а также иконка размером 32×32 в формате PNG
.
<head>
<link rel="icon" href="favicon.ico">
<link rel="icon" type="image/png" sizes="32x32" href="images/favicon-32.png">
</head>
Правильно. Подключена только иконка размером 32×32 в формате PNG
. favicon.ico не подключён к странице, но лежит в корне проекта.
<head>
<link rel="icon" type="image/png" sizes="32x32" href="images/favicon-32.png">
</head>
Неправильно. Подключена только favicon.ico без варианта иконки размером 32×32 в формате PNG.
<head>
<link rel="icon" href="favicon.ico">
</head>
Также ошибкой будет отсутствие favicon.ico в корне проекта.
Зачем нужен критерий. Фавиконки важны, так как они улучшают пользовательский опыт: помогают определить, какой сайт открыт на вкладке, или быстро найти нужный сайт в избранном.
CSS-01. Подключение стилей
Все стилевые файлы должны быть подключены с помощью тега
<link rel="stylesheet">
.Собственные стили проекта должны быть подключены одним файлом в
<head>
.Сторонние стили должны быть подключены в
<head>
отдельными файлами.Сторонние стили должны быть подключены до собственных стилей проекта.
В разметке не должно быть инлайновых стилей в атрибуте
style=""
или в теге<style>
.В разметке допускаются стили для демонстрации поведения JS.
Примеры и назначение критерия
Правильно. Все собственные стили подключены в одном файле в <head>.
<head>
<link rel="stylesheet" href="styles/styles.css">
</head>
Неправильно. Стили разбиты на несколько файлов.
<head>
<link rel="stylesheet" href="styles/header.css">
<link rel="stylesheet" href="styles/main.css">
<link rel="stylesheet" href="styles/footer.css">
</head>
Правильно. Сторонние стили подключены отдельно от собственных стилей.
<head>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@100&display=swap">
<link rel="stylesheet" href="styles/styles.css">
</head>
Неправильно. Сторонние стили добавлены к собственным стилям.
<!-- Файл index.html -->
<head>
<link rel="stylesheet" href="styles/styles.css">
</head>
/* Файл styles/styles.css */
@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@100&display=swap");
Правильно. Сторонние стили подключены до собственных стилей.
<head>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@100&display=swap">
<link rel="stylesheet" href="styles/normalize.css">
<link rel="stylesheet" href="styles/styles.css">
</head>
Неправильно. Собственные стили подключены до сторонних стилей.
<head>
<link rel="stylesheet" href="styles/styles.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@100&display=swap">
<link rel="stylesheet" href="styles/normalize.css">
</head>
Неправильно. Стили используются в разметке.
<html>
<head></head>
<body>
<h1>Барбершоп «Бородинский»</h1>
<style>
.features {
…
}
</style>
<section class="features">
…
</section>
</body>
</html>
<section class="features" style="background-image: url('images/hammer.jpg');">
…
</section>
Зачем нужен критерий. Правильно подключённые стили гарантируют, что сайт будет выглядеть так, как этого требует макет.
CSS-02. Глобальный селектор
Глобальные селекторы запрещены, кроме исключений, приведённых ниже.
Глобальный селектор — это селектор по типу элемента или универсальный селектор. Например:
* {}
body {}
img {}
:root {}
Исключения:
Универсальный селектор, используемый для изменения боксовой модели одновременно элементов и псевдоэлементов.
Нормализация тега
<img>
.Уникальные теги документа:
<html>
и<body>
.:root
, в котором использованы только кастомные свойства.
Примеры и назначение критерия
Правильно. Используется универсальный селектор одновременно с псевдоэлементами для изменения боксовой модели.
*,
*::before,
*::after {
box-sizing: border-box;
}
Неправильно. Использован универсальный селектор без псевдоэлементов и не для изменения боксовой модели.
* {
margin: 0;
padding: 0;
}
Правильно. Для нормализации тега <img>
использованы свойства max-width
и object-fit
.
img {
max-width: 100%;
object-fit: contain;
}
Неправильно. Для нормализации тега <img>
использовано свойство display
.
img {
max-width: 100%;
display: block;
}
Правильно. Использован уникальный тег <body>
.
body {
margin: 0;
}
Неправильно. Использованы селекторы по типу.
ul {
list-style: none;
}
p {
margin: 0;
}
Правильно. Селектор по типу вложен внутрь селектора по классу.
.content h1 {
font-size: 30px;
}
.content p {
font-size: 20px;
}
Правильно. Внутри :root
использованы только кастомные свойства.
:root {
--basic-extra-dark: #242424;
--basic-dark: #595959;
--basic-light: #e7e7e7;
--basic-extra-light: #f6f6f6;
}
Неправильно. :root
использован не для кастомных свойств.
:root {
font-size: 20px;
}
Зачем нужен критерий
В процессе обучения мы ограничиваем студентов в праве выбора глобальных селекторов. Это позволяет нам сконцентрировать студентов на тех селекторах, которые они точно будут применять в своих проектах. В материалах мы рассказали про другие возможные варианты использования глобальных селекторов.
Глобальные селекторы применяют стили ко всем элементам на странице, поэтому их использование может делать вёрстку менее контролируемой, а поведение элементов — непредсказуемым.
CSS-04. ID в селекторах
В селекторах не должно быть #id
.
Примеры и назначение критерия
Неправильно. Используется селектор по идентификатору.
#header {
background-color: #000000;
}
Зачем нужен критерий
Критерий рассматривает именно запрет на стилизацию через id
, но использовать этот атрибут для связывания <label>
и элементов форм не считается ошибкой.
Селекторы по идентификатору обладают большей специфичностью по сравнению с классом и добавляют непредсказуемости в код. Например, чтобы переопределить #id
, потребуется несколько селекторов по классу или !important
. Это делает код неконтролируемым и сложно читаемым.
CSS-05. Использование !important
Ключевое слово !important
не должно использоваться для борьбы со специфичностью.
Примеры и назначение критерия
Неправильно. Использован !important.
.content h1 {
font-size: 17px !important;
}
Зачем нужен критерий. Модификатор !important
даёт CSS-правилу наивысшую специфичность и нарушает этим каскад стилей. Это добавляет непредсказуемости в код, усложняет его поддержку и отладку. Существуют специфические задачи, в которых использование !important
может быть целесообразно, но в рамках курса таких задач нет, поэтому он запрещён.
CSS-06. Использование шрифтов
Начертания шрифтов, подключенных с помощью
@font-face
, должны меняться с помощьюfont-weight
иfont-style
и не должны меняться с помощью подключения отдельного семейства шрифтов.При указании шрифт должен дополняться общим семейством:
serif
,sans-serif
,monospace
и другие.
Примеры и назначение критерия
Правильно. Указано типовое семейство для шрифта sans-serif
, а начертание изменяется с помощью font-weight
.
@font-face {
font-family: "PT Sans";
src: url("/fonts/pt-sans.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Futura";
src: url("/fonts/futura-bold.woff2") format("woff2");
font-weight: 700;
font-style: normal;
font-display: swap;
}
.page {
font-family: "PT Sans", sans-serif;
}
.content h2 {
font-family: "Futura", sans-serif;
font-weight: 700;
}
Неправильно. Начертание семейства изменяется именем шрифта, а не свойствами font-weight
и font-style
.
@font-face {
font-family: "Futura Regular";
src: url("/fonts/futura-regular.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Futura Bold";
src: url("/fonts/futura-bold.woff2") format("woff2");
font-weight: 700;
font-style: normal;
font-display: swap;
}
.content {
font-family: "Futura Regular", sans-serif;
}
.content h2 {
font-family: "Futura Bold", sans-serif;
}
Неправильно. У шрифта не указано общее семейство serif,
sans-serif
или monospace
.
@font-face {
font-family: "PT Sans";
src: url("/fonts/pt-sans.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Futura";
src: url("/fonts/futura.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
}
.content {
font-family: "PT Sans";
}
.content h2 {
font-family: "Futura";
}
Зачем нужен критерий
Описанный подход к использованию шрифтов повышает гибкость и наглядность кода, так как мы отделяем описание шрифта от его использования: семейство шрифта достаточно будет указать только один раз — на body
, а дальше в любых селекторах прописывать только особенности начертания. На тех элементах, у которых по умолчанию есть тестовые стили, например <i>
или <b>
, начертание шрифта применится автоматически. Это позволяет легко менять шрифт и отслеживать все варианты его использования.
Тип семейства необходимо указывать, чтобы в случае отсутствия основного шрифта изменения внешнего вида шрифтов на странице были минимальны.
IMG-01. Контентная и декоративная графика
Контентная графика должна вставляться в разметке.
Декоративная графика должна вставляться в стилях.
Декоративная SVG-графика может использоваться в разметке, если её внешний вид нужно менять стилями.
О том, как различать декоративную и контентную графику, можно почитать в блоге.
Примеры и назначение критерия
![](https://habrastorage.org/getpro/habr/upload_files/baa/cdf/1ad/baacdf1add6780feba2c28705747adbe.png)
Правильно. Контентная графика использована в разметке.
<img src="images/hammer.jpg" width="640" height="320" alt="Мороженное сорта Хаммер со вкусом дубовой коры">
Неправильно. Контентная графика использована в стилях.
<div class="product">
…
</div>
.product {
background-image: url("images/hammer.jpg");
}
![](https://habrastorage.org/getpro/habr/upload_files/844/931/50a/84493150af9e9ce2b3a69f5a5544ae60.png)
Правильно. Декоративная графика использована в стилях.
<button class="button-icon">
<span class="visually-hidden">Перейти в Facebook.</span>
</button>
.button-icon {
background-image: url("images/icons/icon.svg");
}
![](https://habrastorage.org/getpro/habr/upload_files/102/27c/842/10227c84232b00c415004ebe08c931ea.png)
Правильно. Декоративная изменяемая графика использована в разметке.
<body>
<svg class="icon" width="11" height="10" viewBox="0 0 11 10" xmlns="http://www.w3.org/2000/svg">
<path d="M11 0L0 0L5.5 10L11 0Z" />
</svg>
</body>
.icon:hover {
fill: #ff0000;
}
![](https://habrastorage.org/getpro/habr/upload_files/2ec/a83/458/2eca8345896b05fa59feeb82c1210ec5.png)
Неправильно. Декоративная графика использована в разметке.
<img src="images/line.png" width="16" height="16" alt="">
Зачем нужен критерий
Контентная графика должна быть в разметке, так как она содержит в себе важную смысловую информацию и поэтому должна быть доступна пользователю даже в том случае, если стили по какой-то причине не загрузятся.
Декоративная графика должна быть в стилях, так как она не несёт смысловой нагрузки и её отсутствие в случае незагрузки стилевого файла не приведёт к потере важной информации. Использовать декоративную графику в разметке нежелательно, так как лишние элементы в разметке усложняют поддержку кода.
IMG-02. Форматы графики
Выбран подходящий формат изображений. Например:
JPEG для фотографий;
SVG для векторных изображений;
PNG для всех прочих.
Назначение критерия
Зачем нужен критерий. Использование подходящих форматов изображений важно для того, чтобы изображения отображались без погрешностей и имели оптимальный размер при загрузке.
IMG-03. Размеры графики в разметке
Для всех изображений, размеченных при помощи <img>
и <svg>
, размеры должны быть заданы с помощью атрибутов width
и height
.
Примеры и назначение критерия
Правильно
<img src="images/flower.jpg" width="390" height="250" alt="Нежные цветки сакуры на фоне голубого неба.">
<svg width="11" height="10" viewBox="0 0 11 10" xmlns="http://www.w3.org/2000/svg">
<path d="M11 0L0 0L5.5 10L11 0Z" />
</svg>
Зачем нужен критерий
Задавать размеры растровых изображений в разметке необходимо, чтобы не было скачков интерфейса при их загрузке, а векторных — чтобы изображение не увеличивалось бесконтрольно, если у него не заданы внутренние размеры.
Задавать размеры изображений в разметке необходимо для перестраховки. В этом случае вёрстка сайта не сломается, если изображение будет заменено на более большое или маленькое.
CONT-01. Текстовые переносы
Текст не должен переноситься с помощью двойного <br>
.
Примеры и назначение критерия
Правильно. Перенос для соответствия макету сделан с помощью одного тега <br>
.
<h1>Шампунь для <br>
мужчин Brews Daily</h1>
Неправильно. Перенос для соответствия макету сделан с помощью двух тегов <br>
.
<p>Заимствование, как бы это ни казалось парадоксальным, непрерывно.</p>
<br>
<br>
<p>Представленный лексико-семантический анализ является психолингвистическим в своей основе.</p>
Зачем нужен критерий. Использовать тег <br>
для создания отступов между блоками — это плохая практика, потому что такой код неудобно изменять и поддерживать.
ALLY-01. Описание графики
Контентная графика должна иметь описание.
Чтобы описание элемента попало в дерево доступности, нужно использовать один из способов:
добавить изображению
alt
;добавить скрытый текст с помощью
visually-hidden
;добавить атрибут
aria-label
.
Предпочтительно увеличивать доступность в первую очередь с помощью HTML и только потом — aria
-ролей.
Подпись в конце описания должна иметь точку. Точка нужна для интонационной паузы при чтении скринридером.
Примеры и назначение критерия
Контентная растровая графика
Теги <img>
должны иметь заполненный атрибут alt
с описанием изображения.
Исключение: если рядом с изображением есть сущность в которой уже описано содержимое картинки, то alt
можно оставлять пустым.
Правильно. У тега <img>
атрибут alt
содержит описание изображения.
<img src="images/hammer.jpg" width="640" height="320" alt="Винтажный молоток с рукояткой из массива дуба.">
Правильно. В карточке товара есть заголовок, описывающий товар. В этом случае alt
можно оставить пустым, иначе скринридер при чтении карточки повторит два раза название товара.
<li class="product-card">
<img src="images/shampoo.jpg" width="220" height="200" alt="">
<h3>Шампунь для мужчин Brews Daily</h3>
</li>
Неправильно. У тега <img>
не заполнен атрибут alt
.
<img src="images/hammer.jpg" width="640" height="320" alt>
Неправильно. В качестве значения атрибута alt
использован пробел.
<img src="images/hammer.jpg" width="640" height="320" alt=" "> <!--alt с пробелом-->
Контентная векторная графика
Контентная векторная графика в разметке должна иметь атрибут role="img"
и описание изображения в атрибуте aria-label
.
Правильно. Контентная векторная графика имеет role="img"
и aria-label
.
<svg
class="logo"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 140 18"
width="367"
height="152"
role="img"
aria-label="Барбершоп «Бородинский»">
<path d="M78.55 0h-2.8v15.78h2.8V0zM91.02z"/>
</svg>
Неправильно. У контентной векторной графики отсутствует role="img"
и aria-label
.
<svg class="logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 140 18" width="367" height="152">
<path d="M78.55 0h-2.8v15.78h2.8V0zM91.02z"/>
</svg>
Зачем нужен критерий. Атрибут alt
даёт альтернативное описание изображения для скринридеров и поисковиков. Правильное описание картинки добавляет смысл и ценность появления этой картинки для пользователя.
ALLY-02. Подписи интерактивных элементов
Интерактивные элементы должны быть подписаны. Подпись должна быть связана с элементом и отображаться в дереве доступности.
Предпочтительно реализовывать подпись с помощью HTML: тегом с классом visually-hidden
или атрибутом alt
у изображений, и только потом — aria
-атрибутами.
Подпись в конце описания должна иметь точку. Точка нужна для интонационной паузы при чтении скринридером.
Примеры и назначение критерия
Правильно. У ссылки есть описание, так как у изображения заполнен атрибут alt.
<a href="/">
<img src="images/logo.svg" width="64" height="32" alt="Барбершоп «Бородинский».">
</a>
Неправильно. У ссылки нет описания, так как у изображения не заполнен атрибут alt
.
<a href="/">
<img src="images/logo.svg" width="64" height="32" alt="">
</a>
Неправильно. У ссылки нет описания, так как внутри неё нет текстового содержимого.
<a href="https://twitter.com/htmlacademy_ru"></a>
Правильно. Описание у кнопки с иконкой реализовано при помощи текста, скрытого классом visually-hidden
.
<button class="fb-icon" type="button">
<span class="visually-hidden">Закрыть окно.</span>
</button>
.fb-icon {
content: url("images/fb.png");
}
Неправильно. Кнопка с иконкой не имеет описания.
<button class="fb-icon" type="button"></button>
.fb-icon {
content: url("images/fb.png");
}
Зачем нужен критерий. Текстовое описание интерактивных элементов поможет пользователям понять, что именно произойдёт в результате взаимодействия, в случае если они не видят элементы интерфейса. Это описание будет озвучено скринридером.
ALLY-03. Видимое состояние элементов
Все интерактивные элементы должны иметь видимое состояние фокуса.
Элементы должны иметь стандартный браузерный фокус, если это состояние не описано в дизайне.
Примеры и назначение критерия
Правильно. Интерактивный элемент имеет стандартный браузерный фокус.
<button class="button" type="button">Закрыть</button>
Неправильно. Вместо кнопки использован <div>
, стилизованный под кнопку, но не имеющий встроенной интерактивности.
<div class="button">Закрыть</div>
.button {
display: inline-block;
border: none;
height: 50px;
background-color: #eeeeee;
}
Правильно. Стандартный браузерный фокус заменён на фокус, описанный в макете.
<button class="button" type="button">Закрыть</button>
.button {
outline: none;
box-shadow: 0 0 1px rgba(255, 255, 0, 0.7);
}
Неправильно. Стандартная обводка отключена без замены на альтернативное состояние.
<button class="button" type="button">Закрыть</button>
.button {
outline: none;
}
* {
outline: none;
}
При проверке нужно убедиться, что в коде либо нет outline: none, либо взамен назначена подходящая замена.
Зачем нужен критерий. Видимое состояние интерактивных элементов позволяет передвигаться по ним с клавиатуры клавишей Tab и видеть каждый текущий элемент в активном состоянии.
ALLY-04. Области интерактивных элементов
Область интерактивных элементов должна включать тексты, иконки и другие связанные части. Она не должна накладываться на окружающие элементы.
Область клика у интерактивных элементов может быть больше, чем их контент, но область клика не должна накладываться на окружающие элементы.
Область клика можно определить из макета. Если в макете область клика не определена, то можно сделать её на своё усмотрение, руководствуюсь примерами ниже.
Примеры и назначение критерия
Область взаимодействия включает иконку и текст
![](https://habrastorage.org/getpro/habr/upload_files/b38/1a0/8ea/b381a08ea4e5a3f489e937b5f56eff39.png)
Область вокруг текста в навигации чувствительна к клику, а не только сам текст.
![](https://habrastorage.org/getpro/habr/upload_files/2cd/5dc/efd/2cd5dcefdd5248f7a8671238c0b55691.png)
Интерактивные элементы с иконкой имеют расширенную область клика.
![](https://habrastorage.org/getpro/habr/upload_files/64b/668/533/64b6685333840757d9ae718e6bdef1b2.png)
В пагинации цифры имеют расширенную область клика, а не по цифре.
![](https://habrastorage.org/getpro/habr/upload_files/afc/2b5/34d/afc2b534d878f9339099d99d92fdb18e.png)
Кнопка закрытия модального окна имеет расширенную область клика, а не равную размерам иконки.
![](https://habrastorage.org/getpro/habr/upload_files/c8a/d2e/599/c8ad2e5998b54c2eb9970d9969a96055.png)
В карточке товара кликабельным является не только название товара, но и изображение товара, а не только его название.
![](https://habrastorage.org/getpro/habr/upload_files/3a4/e8a/4a7/3a4e8a4a745dd8859cbc59725c150804.png)
Зачем нужен критерий. Правильные области важны для ускорения взаимодействия с интерактивными элементами интерфейса: чем меньше область клика, тем больше времени пользователь потратит на то, чтобы попасть в эту область.
ALLY-05. Фоновый цвет у фоновых картинок
Для блока, у которого есть текст с фоновым изображением, должен быть указан фоновый цвет, который соответствует преобладающему цвету изображения. Преобладающий цвет фоновой картинки должен быть контрастным.
Примеры и назначение критерия
Правильно. Указан цвет фона перед основным изображением.
body {
background: #000000 url("../img/background-body.jpg") no-repeat center top;
}
Результат: картинка не загрузилась, но при этом цвет фона остался тёмным.
![](https://habrastorage.org/getpro/habr/upload_files/741/add/b9b/741addb9bf96db31d7a38e2b671714ca.png)
Неправильно. Указано только основное изображение.
body {
background: url("../img/background-body.jpg") no-repeat center top;
}
Результат: картинка не загрузилась, а цвет фона стал белым.
![](https://habrastorage.org/getpro/habr/upload_files/159/e0a/e89/159e0ae89f1c7b3ace445896e801cd63.png)
Для блока с картой также следует указывать фоновый цвет.
Чтобы этот критерий был засчитан, необходимо не просто указать цвет фона, но и подобрать цвет, который преобладает в самом изображении.
Зачем нужен критерий. Такой метод используется для перестраховки. В этом случае, если фоновое изображение не загрузится, на заднем фоне останется преобладающий цвет.
ALLY-06*. Порядок фокуса
Порядок фокуса на интерактивных элементах не должен изменяться стилями.
Примеры и назначение критерия
Правильно
<nav class="menu">
<ul>
<li><a class="menu-item menu-item-current" href="#">Кроет</a></li>
<li><a class="menu-item" href="#">Буря</a></li
<li><a class="menu-item" href="#">Мглою</a></li>
<li><a class="menu-item" href="#">Небо</a></li>
</ul>
</nav>
.menu {
display: flex;
}
• Кроет
• Буря
• Мглою
• Небо
Неправильно
<nav class="menu">
<ul>
<li><a class="menu-item menu-item-current" href="#">Кроет</a></li>
<li><a class="menu-item" href="#">Буря</a></li
<li><a class="menu-item" href="#">Мглою</a></li>
<li><a class="menu-item" href="#">Небо</a></li>
</ul>
</nav>
.menu {
display: flex;
flex-direction: row-reverse;
}
• Небо
• Мглою
• Кроет
• Буря
Зачем нужен критерий. Переход между элементами на странице должен быть очевиден и предсказуем для пользователей, передвигающихся по сайту с клавиатуры.