Вступление
Меня зовут Николай и я Frontend-разработчик. Хочу рассказать о самых распространённых ошибках в вёрстке современных проектов.
Дело в том, что лишь малая часть современных фронтендеров обращает внимание на работу с HTML и CSS, предпочитая готовые решения, вроде UI-библиотек и систем сеток. Но эти решения неидеальные и приходится дописывать обёртки вокруг них, видоизменять код, переписывать стили и совершать прочие действия для соответствия требованиям проекта. Тут-то и начинаются проблемы: вёрстка местами становится избыточной, стили переназначются через important и с каждым релизом проект всё сложней поддерживать. Я уже не говорю об удобстве использования и доступности. Об этом думают вообще в последнюю очередь.
В этой статье я расскажу лишь о небольшой части проблем, которые можно достаточно быстро решить, не прибегая к радикальному переписыванию больших частей проекта.
Содержание
Используйте правильные теги.
Как правильно вкладывать теги друг в друга.
Работа с медиаконтентом.
Пишем таблицы на HTML правильно.
a
или button
? Работа с интерактивными элементами и как выбрать правильный тег.
Различный теги для медиа-контента.
Прекратите писать велосипеды! Как мы можем стилизовать дефолтные HTML-элементы.
Пишем доступные формы.
Избыточная вёрстка. Как облегчить разметку.
Современные фишки HTML и CSS способные облегчить нам жизнь.
Экспериментальные технологии, входящие в стандарт.
Используйте правильные теги
Исторически так сложилось, что HTML служит для описания документов. То есть язык гипертекстовой разметки был придуман для обмена документами (в основном научного характера) и не предназначался для построения сложных веб-приложений и сайтов. Благодаря развитию стандарта стало полегче, но большинство современных разработчиков всё ещё предпочитают <div>
в качестве главного тега и засовывают в него любой контент, вплоть до изображений (через background-image). И я прекрасно их понимаю, <div>
— очень удобный тег: у него нет встроенных стилей, его можно вкалывать в другие дивы. Чем не кандидат на лучший тег. Но при таком использовании тегов мы теряем главные преимущества HTML:
семантику — чёткую структуру контента, где каждый тег говорит о том, зачем он здесь и что ожидается внутри;
доступность — HTML может рендериться не только браузером, но и другими инструментами, вроде скрин-ридеров, роботов-поисковиков и т.д. И в наших силах упростить для них парсинг страниц.
Про какие теги нам следует стоит помнить?
Структурные теги документа
Почти любой сайт или приложение можно разбить на 3 большие части: <header>
, <main>
и <footer>
. Сейчас это стало неким стандартом в дизайне. Некоторые части приложения повторяются от страницы к странице, и мы можем выделить их в отдельные части (шапку и подвал).
Шапка — это контент вверху страницы. Там обычно размещается логотип, навигационное меню и другие элементы, которые должны быть доступны пользователю с любой страницы. Тег <header>
не обязательно один на странице, он может озаглавливать любую независимую часть (например, быть частью модального окна).
Подвал — нижняя часть сайта, где обычно дублируется навигация и располагаются контакты компании. Также, как и шапка, <footer>
может быть не один и использоваться для других независимых частей, помимо страницы.
Тег <main>
обычно обозначает место для основного контента, который не повторяется от страницы к странице.
Плохо
<body>
<div class="header">
...
</div>
<div class="main">
...
</div>
<div class="footer">
...
</div>
</body>
Хорошо
<body>
<header>
...
</header>
<main>
...
</main>
<footer>
...
</footer>
</body>
Помимо трёх базовых семантических тегов существует ряд других. Разберём их ниже.
<article>
Это независимый блок на странице, который без внешнего контекста может существовать в рамках других сайтов и сервисов. Это может быть статья в блоге, твит, виджет VK, коментарий к публикации и т.д. Желательно, чтобы у этого блока был заголовок.
<section>
Неотделяемая от основного контента секция на странице. Например, это может быть блок на лендинге. Чаще всего имеет заголовок.
<aside>
Побочный, косвенный контент на странице, находящийся в стороне. Может иметь заголовок и быть не в одном экземпляре. Главная ошибка — использовать его только для боковой панели. Этот тег многогранен и может использоваться для любых блоков, не имеющих основное значение.
<nav>
Блок навигации с ссылками на другие страницы или разделы текущей страницы. Может использоваться только для основной навигации, а не для каждой группы ссылок. Например навигацию в <footer>
не имеет смысла упаковывать в <nav>
, так как подвал сам по себе предполагает присутствие навигационных элементов. И этот тег не обязательно должен включать в себя список ссылок. Туда может входить навигация любого типа, главное, чтобы она считалась основной.
<address>
В этот тег нужно вкладывать контактные данные. У него по-особенному работает «область видимости» — контактные данные в <address>
относятся к ближайшему родительскому блоку <article>
, либо к <body>
, если он находится вне <article>
.
Заголовки
Как и в любом документе на HTML-странице могут содержаться заголовки. По стандарту мы обязаны всегда указывать заголовок первого уровня <h1>
. Остальные уровни опциональны, но они должны быть в иерархической последовательности! Это значит, что мы не можем <h3>
поставить после <h1>
. Чтобы лучше это понять, посмотрим код ниже:
<body>
<header>
...
</header>
<main>
<h1> Наша кондитерская самая кондитерская из всех кондитерских </h1>
...
<section>
<h2> Почему наши булочки лучшие? </h2>
...
<h3> Мука высочайшего сорта </h3>
...
<h3> Много корицы </h3>
...
<h4> Корица со Шри-Ланки</h4>
...
<h3> Минимум сахара </h3>
...
<h4>
</section>
</main>
<footer>
...
</footer>
</body>
Как вы видите, заголовки выстраиваются в иерархию и идут один за одним, формируя логичную структуру.
По поводу использования нескольких заголовков <h1>
: вы МОЖЕТЕ использовать несколько заголовков первого уровня, если это требуется на странице. Когда-то давно некоторые злые SEO-специалисты настоятельно не рекомендовали так делать, хотя спецификация ничего не говорит на этот счёт. Сейчас мы, конечно, не узнаем действительно ли поисковики снижали сайт в выдаче за использование двух и более заголовков первого уровня, но уже даже многие SEOшники признали, что этот фактор малозначителен при ранжировании сайтов.
Блочные теги
<p>
Простой тег для абзацев, именно для разделения текстовых частей. Не используйте <p> для коротких фраз внутри интерфейса. С точки зрения доступности, этот тег очень крут, дает пользователям с ограниченными возможностями «прыгать» между ними с помощью шорткатов.
<figure>
и <figcaption>
Это иллюстрация с необязательной подписью. Во многих книгах изображения подписываются как «Рис. 1 — такой-то объект». Вот это и есть <figure>
. Но в рамках HTML назначение этого тега гораздо шире. Мы можем разместить внутри цитату (см. ниже), фрагмент кода, какую-нибудь диаграмму. В общем <figure>
— это любой объект с подписью. Подпись размещается внутри тега <figcaption>
, который, в свою очередь, вкладывается в <figure>
.
<figure>
<img src="https://example.com/cat.jpg" alt="Сердитый кот">
<figcaption>Кот, который зол на своего хозяина</figcaption>
</figure>
<blockquote>
Тег для вставки длинных цитат. Может иметь аттрибут cite
, в котором указывается URL на источник цитаты, а также хорошо совместим с тегом <figure>
, где в <figcaption>
можно указать автора и название источника.
<figure>
<blockquoute cite="https://www.youtube.com/watch?v=ZXsQAXx_ao0">
Just Do It!
</blockquote>
<figcaption>
Shia LaBeouf, <cite>Motivational Speech</cite>
</figcaption>
</figure>
<hr>
Одиночный тег для разделения контента. Про него забывают и заменяют на border-bottom
, но помимо визуального отображения этот тег несёт семантический смысл — тематическое разделение абзацев.
<pre>
Тег для вывода предварительно отформатированного текста. Имеет ограниченную область использования — ASCII-арт, вывод программного кода. Не рекомендую использовать для других задач, так как тег довольно ненадёжен и непредсказуем. Например, мы потеряем всё форматирование, если сборщик проекта минифицирует HTML.
Списки
Списки в вебе просто везде! Но очень редко их верстают как списки. Например, преимущества компании на лендинге это что? Правильно, список. Они бывают двух видов: упорядоченные и неупорядоченные. Я в этот раздел также добавил список описаний Description list.
<ul>
Неупорядоченный список применяется в том случае, если мы безболезненно можем поменять порядок элементов. Примеры:
cписок ингредиентов для рецепта;
преимущества компании;
партнёры компании.
<ul>
<li>Удобная оплата</li>
<li>Быстрая доставка</li>
<li>Гарантия в 1 год</li>
</ul>
<ol>
Упорядоченный список применяется тогда, когда нам важен порядок элементов. Например:
пошаговая инструкция;
этапы работы.
<ol>
<li>Оформляете заявку</li>
<li>С вами связывается менеджер для уточнения деталей</li>
<li>Совершаете оплату</li>
<li>Ожидаете доставку</li>
</ol>
<dl>
, <dd>
, <dt>
Списки описаний применяются для формирования списков терминов.
<dl>
<dt>HTML</dt>
<dd>Язык разметки гипертекста, с помощью которого формируют контент веб-страницы</dd>
<dt>CSS</dt>
<dd>Язык для описания стилей веб-страницы</dd>
<dt>JS</dt>
<dd>Язык программирования, часто применяемый для написания веб-приложений</dd>
</dl>
Строчные теги
<b>
, <i>
, <u>
, <s>
Чудесные теги, которые чаще всего используют не по назначению. Они несут исключительно визуальное выделение текста. Если вы сбросите их стили, то они ничем не будут отличаться от обычного текста. В данный момент их можно использовать как теги для дополнительного выделения текста, которое вы оформите с помощью CSS. И да, тег <i> НЕ предназначен для иконок.
<em>
Как и <i>
выделяет текст курсивом. Но зачем нам два тега для одного и того же? В том то и дело, что они разные. <i>
, как говорилось выше, не несёт никакого семантического смысла, это просто визуальное выделение, а <em>
делает акцент на обёрнутом им тексте, который меняет смысл всего предложения. Например:
Я <em>просто обожаю </em>, когда верстальщики используют только дивы.
<strong>
Браузер выделяет текст обёрнутый тегом <strong>
полужирным. Но помимо визуального выделения, текст обретает семантический смысл — большую важность по сравнению с остальным текстом вокруг.
<cite>
и <q>
Оба тега связаны с цитирований, но применяются в разных случаях. <cite>
— тег, в который мы оборачиваем текст, который отсылается к другому документу/произведению/etc.
Больше информации вы сможете найти в стандарте <cite>[ISO-0000]</cite>
<q>
похож на <blockquote>
, разница лишь в том, что <q>
применяется для строчных цитат.
<q cite="https://russian.rt.com/business/news/966657-rubl-dollar-evro">
Рубль растёт к доллару и евро
</q> — сообщает RT со ссылкой на ФАН.
<code>
Применяется для оформления программного кода внутри текста. Если требуется вывести многострочный блок кода, то лучше использовать <code>
в связке с тегом <pre>
.
<time>
Тег для обозначения даты и времени. У него может быть атрибут datetime, куда необходимо передать дату и время в формате ISO.
<time datetime="1995-11-24">24 ноября 1995 года</time>
<sub>
и <sup>
Используются для добавления в текст индексов и степеней. Удобны для описания формул.
x<sub>1</sub> + x<sub>2</sub> = y<sup>2</sup>
<!-- Икс первый плюс икс второй равно игрек в квадрате -->
<del>
и <ins>
Нужны, чтобы показать, что из текста было что-то удалено или добавлено. При этом они также обозначают факт изменения текста семантически, а не только визуально.
Вася пришёл домой в
<del><time>19:00</time></del>
<ins><time>23:00</time></ins>
<br>
Простой тег для переноса строки, думаю, все про него знают, потому что альтернативы нет.
Интерактивные элементы
<details>
Нативный дропдаун прямо в HTML! На самом деле не совсем так. <details>
применяется, чтобы скрыть часть информации, которую можно получить, кликнув по кнопке, описанной во внутреннем теге <summary>
.
Рубль растет на фоне заявлений Запада о введении санкций против России
<details>
<summary>Подробнее</summary>
Согласно данным валютных торгов на Московской бирже, по состоянию
на 22.40 мск курс доллара находился на уровне 78,7 рубля (-1,6%),
курс евро снижался до 89,3 рубля (-0,9%).
</details>
Внимание! Данный тег не поддерживается IE и старыми версиями основных браузеров.
Другие интересные теги
<abbr>
Тег для аббревиатур.
<abbr title="HyperText Markup Language">HTML</abbr> — основной язык разметки веб-приложений
<dfn>
Тег для выделения термина. Элемент<p>
, пара <dt>
/<dd>
или <section>
, который является ближайшим предком <dfn>
считается определением термина.
<p>
<dfn>JavaScript</dfn> — язык программирования,
используемый в основных веб-браузерах.
</p>
<kbd>
Используется для выделения названия клавиш в клавиатурных сочетаниях.
Чтобы открыть диспечер задач, нажмите сочетание клавиш
<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>Esc</kbd>.
<samp>
Тег для обозначения вывода компьютерной программы. По-умолчанию выводится моноширинным шрифтом.
<p>
Приложение упало с ошибкой:<br>
<samp>404 Неизвестный ресурс</samp>
<var>
Элемент для вывода математических переменных
Для рассчёта расстояния <var>S</var>, необходимо
перемножить скорость <var>V</var> на время <var>t</var>.
<bdi>
и <bdo>
Теги, связанные с направлением текста ltr и rtl. Необходимы, когда мы встраиваем в текст, написанный языком в одном направлении, фразу или предложение написанное в другом.
<bdi>
изолирует от окружающего текста фрагмент, который может поменять направление (но не обязательно поменяет).
<bdo>
в свою очередь, переопределяет направление текста так, что текст внутри тега отображается в другом направлении, нежели чем окружающий.
<p dir="ltr">
Это <bdi>арабское слово</bdi> будет перевёрнуто.
</p>
<!--
Это оволс еоксбара будет перевёрнуто.
-->
<mark>
Элемент, выделенный по причине его актуальности в определённом контексте. Чаще всего используется для выделения ключевых фраз, введенных пользователем, в результатах поиска. По умолчанию, на текст внутри этого тега применяется жёлтый фон.
<meter>
Современный компонет, который может показывать шкалу с наполнением разного цвета, в зависимости от указанных значений. Используется преимущественно для отображения числовых значений, например, количества результатов поиска, объема жидкости, давления и др.
Имеет следующие аттрибуты:
min
— минимальное значение шкалы;max
— максимальное значение шкалы;low
— предел, при достижении которого, значение считается низким;optimum
— предел, при достижении которого, значение считается оптимальным;high
— предел, при достижении которого, значение считается высоким;value
— собственно само значение.
<p>Температура воды</p>
<meter value="0" max="100" low="10" high="60">Низкая</meter>
<meter value="30" max="100" low="10" high="60">Нормальная</meter>
<meter value="80" max="100" low="10" high="60">Горячая</meter>
<meter value="100" max="100">Кипяток</meter>
Текст внутри является фолбэком для браузеров, которые не поддерживают этот тег.
<progress>
Тег для отображения индикатора, показывающего ход выполнения задачи. По простому — прогресс-бар.
<progress max="100" value="70">70%</progress>
<wbr>
Одиночный тег, указывающий, в каком месте можно переносить цельную строку. Является аналогом символа ­
, с той лишь разницей, что не добавляет символ переноса в конце строки.
<ruby>
, <rt>
, <rp>
Теги, в основном используемые для иероглифов. Не вижу смысла подробно их разбирать. Если интересно, можно почитать здесь.
<big>, <small>, <tt> и прочая эзотерика
Просто забудьте об этих тегах. Стандарт говорит, что они больше не поддерживаются и не рекомендует их использовать. Полный список здесь.
Заключение части 1
В этой статье ничего не сказано про элементы форм, таблицы, всякий медиа-контент, а также теги <a>
и <button>
. Об этом в следующих публикациях.
Также, я ничего не сказал по <div>
и <span>
, которые являются базовыми элементами для вёрстки. Их стоит использовать только в том случае, когда ничто из вышеперечисленного не подошло.
Комментарии (32)
AlexElkin
10.03.2022 19:20Автор не знает как работают скриниридеры...
gBACTAKAHA
10.03.2022 21:00+2Расскажите, я у автора не нашел к чему придраться, кроме того что он забыл рассказать про а и буттон
Clickrouc Автор
11.03.2022 09:13Про a и button будет отдельная статья. Я намерено не расказывал о них в этой части.
jesaiah4
10.03.2022 19:46Подскажите нормальную статьи или видео на русском , про то как считаются все эти max-height , min-height от родителей если у тех например только max-height ,а ты для детей ставишь процентные соотношение и т.д.
gBACTAKAHA
10.03.2022 21:05Что может быть проще?
Все что max-*/min-* это про максимальное/минимальное значение. На родителей и их значения пофиг. Главное чтобы значение не было указано больше/меньше (если min). То что у вас пересчитается, если было задано в процентах или иных не постоянных величинах, в пиксели в итоге вы можете увидеть в девтулс во вкладке computed. Просто сами попробуйте и все увидите.
jesaiah4
10.03.2022 21:31ну это же не так
вот документация http://www.w3.org/TR/CSS21/visudet.html#min-max-heights
в ней говорится "max-height on a child, it is a percentage of the parent's actual height"
Вот вам пример когда ребенок превышает max-height родителя , даже имея min-height:0; (в режиме flex)
sandbox: (красный прямоугольник это как раз ребенок который неверно считается)
https://play.tailwindcss.com/bvfy0kF5Nz
Не всё так просто как вы думаете.
Luciusegorov
11.03.2022 08:50+5Мне лично очень не хватило примеров того, во что примеры HTML отрисуются. Если я не знаю некоторые теги - было бы здорово визуально сразу увидеть результат их применения, без этого статья "для чтения" не пдоходит, скорее это больше похоже на "учебник на метаните"
Clickrouc Автор
11.03.2022 09:14+1Отредактирую позже, сделаю визуализацию. Спасибо за обратную связь!
AlexElkin
11.03.2022 09:59Довольно странный комментарий, во первых большинство тэгов отрисуется так как вы в стилях укажите. Во вторых, аы же читаете в браузере откройте отладчик/песочницу и поиграйтесь.
domix32
11.03.2022 12:12+1В таком случае собранные в песочницах примеры прилинковать - тоже неплохой план.
Luciusegorov
11.03.2022 14:15+11) В таком случае можно все верстать дивами+css, думаю
2) Читал утром с мобильного телефона
AlexElkin
11.03.2022 15:34Ну если вы используете тэги только для внешнего вида, то возможно так даже лучше.
Уж лучше дивы сем адова структура заголовков потому что в макете буковки жирные и разного размера.
jesaiah4
11.03.2022 10:12а мне лично не хватает аналога p тега , чтобы он не имел отступы маргены , так же только для текста и имел 100% ширины.
SkyHobbit
11.03.2022 11:13Тэг <p> и так имеет 100% ширины и отступы сверху и снизу. Или вам нужны отступы по бокам, но зачем? Может быть подойдут <blockquote> или <pre> ?
jesaiah4
11.03.2022 11:26как раз P для обзацев т.к. имеет отстоп.
а нужен клон P , но без отступов
Clickrouc Автор
11.03.2022 12:05+1Ну так заведите класс. Будет что-то вроде
<p class="without-margins">
А в стилях укажите
.without-margins { margin: 0; }
Бессмысленно плодить теги для одного и тоже с разными стилями, для этого и был придуман CSS.
jesaiah4
11.03.2022 10:13+1По статьи мне кажется вы очень плохо раскрыли section article где когда испльзовать, ком в ком может быть
Clickrouc Автор
11.03.2022 12:06Спасибо за адекватную критику! Есть уже пара задач по доработке материала (либо раскрытие этих тем в следующих).
superoleg111
12.03.2022 19:34Ещё тег aside мне показался не раскрытым, говорится что он может использоваться не только для боковой панели, но и для других целей. Но каких?
А так в целом статья понравилась, я относительно новичок в этом деле, поэтому помогла устаканить некоторые вещи в голове
Dron007
12.03.2022 23:39К сожалению, дизайнерам обычно очень не нравятся всякие нативные браузерные элементы типа <progress>, т.к. они в каждом браузере выглядят по-своему и не так, как задумано. Так что приходится реализовывать своё.
lesskop
Как правильно верстать кликабельное содержание статьи на Хабре в 2022 году?
Clickrouc Автор
Так остальных статей пока нет. Буду изменять содержание по мере готовности материалов.