Вступление
Привет хабр! Меня зовут Николай и я Frontend-разработчик в логистическом стартапе Relog. Хочу рассказать о самых распространённых ошибках в вёрстке современных проектов.
В этой статье мы говорим о вложении тегов друг в друга, так как это один из неочевидных моментов, в котором многие новички часто делают ошибки.
Также я расскажу о работе со спецификацией HTML — какие разделы важны для нас, как для верстальщиков и как искать там информацию.
Содержание
Как правильно вкладывать теги друг в друга
Работа с медиаконтентом
Пишем таблицы на HTML правильно
a
илиbutton
? Работа с интерактивными элементами и как выбрать правильный тегРазличный теги для медиа-контента
Прекратите писать велосипеды! Как мы можем стилизовать дефолтные HTML-элементы
Пишем доступные формы
Избыточная вёрстка. Как облегчить разметку
Современные фишки HTML и CSS способные облегчить нам жизнь
Экспериментальные технологии, входящие в стандарт
Как правильно вкладывать теги друг в друга
Что значит правильно? Что является источником истины при работе с HTML? Конечно же это специфиакция! В данный момент существует так называемый «живой стандарт» пятой версии HTML. Это значит, что у него нет мажорных версий и он обновляется регулярно. Посмотреть последнее обновление спецификации можно здесь.
Спецификация HTML — это увесистый документ с кучей разделов. Она существует как для разработчиков браузеров, так и для нас — верстальщиков. Конкретно нас интересуют третий и четвёрный раздел (Semantics, structure, and APIs of HTML documents и The elements of HTML). Эти разделы описывают, как теги можно вкладывать друг в друга и что обозначает каждый тег.
Описание элемента
Каждый элемент имеет метаинформацию и описание.
Сверху размещены метаданные, куда включна следующая информация:
куда можно вкладывать тег;
какие теги можно вкладывать внутрь этого тега;
перечень аттрибутов тега (глобальные, дополнительные и ARIA);
информация о доступности;
вспомогательные данные.
Далее размещено описание тега — что он обозначает и как его можно использовать.
![Спецификация элемента на примере тега <p> Спецификация элемента на примере тега <p>](https://habrastorage.org/getpro/habr/upload_files/a18/38d/79d/a1838d79d3826d18973cb5a2c3b47409.png)
Метаданные тега
![Метаданные тега <p> Метаданные тега <p>](https://habrastorage.org/getpro/habr/upload_files/164/d5d/11c/164d5d11c89382a2533812165d6dcad7.png)
Метаинформация о теге включает в себя несколько пунктов:
Категории — обозначает, к каким типам тегов относится элемент, могут быть следующие типы:
Metadata content (например
<meta>
и<title>
) — метаданные страницы, обозначающие представление или поведение содержимого, или отношение к другим документам;Flow content (например
<article>
,<span>
,<p>
) — это все теги, используемые в<body>
, то есть почти все в целом, за исключением некоторых мета-тегов;Sectioning content (например
<section>
) — какие-либо большие секции, как правило имеющие конкретную структуру и заголовок;Heading content (все заголовки
<h1>
–<h6>
, а также тег, про который я забыл рассказать в прошлой статье —<hgroup>
) — определяет заголовок секции, обозначенной явно, либо<body>
.Phrasing content (например
<a>
,<span>
,<strong>
) — различный, в основном текстовый контент, но включающий также некоторые элементы, которые позволяют размечать текст на уровне параграфов;Embedded content (например
<iframe>
,<canvas>
,<video>
) — контент, встраиваемый извне (другие сайты, файлы, скрипты);Interactive content (например
<a>
,<button>
,<input>
) — теги, с которыми пользователь может взаимодействовать;
Контекст использования элемента — где мы можем размещать элемент.
Контентная модель — важная для этой статьи часть! Это как раз то, что мы можем размещать внутри тега.
Tag omission — возможные сценарии, когда закрывающую часть тега можно опустить. Рекомендую не обращать внимания на этот раздел вообще, так как в современном вебе нормальной практикой является закрытие всех парных тегов.
Доступные аттрибуты тега.
Раздел, касающийся доступности. Надеюсь когда-нибудь дойдут руки написать о работе с доступностью в рамках спецификации.
DOM Interface — раздел, необходимый для JavaScript-разработчиков, подробно на нём останавливаться не будем.
И всё же, как правильно вкладывать теги друг в друга?
![Категории элементов по HTML-спецификации Категории элементов по HTML-спецификации](https://habrastorage.org/getpro/habr/upload_files/4ce/cfd/0cb/4cecfd0cbc8438285201777396a09429.png)
Две основные категории тегов — это Metadata (метаданные) и Flow (поточные теги). Метаданные — это то что в основном входит в <head>
, а Flow — то что можно положить в <body>
. Однако, некоторые мета-теги мы можем разместить в <body>
, поэтому они заходят на Flow-контент (например это <noscript>
, <script>
и <style>
).
Внутри потоковых тегов находятся все остальные категории.
Heading — это просто залоговки всех уровней, а также тег <hgroup>
.
Sectioning — это большие смысловые части документа, секции.
Phrasing — небольшие слова или словосочетания, фразы. В основном это строчные элементы (по крайней мере они такими являлись в спецификации HTML4). Все остальные теги, не имеющие категории Phrasing, как правило являются блочными.
Embedded — как уже писал выше, контент, имеющий внешний источник данных, то есть не имеющий прямое отношение к HTML-документу.
Interactive — категория, пересекающаяся с Flow, Phrasing и Embedded, обозначающая все элементы, с которыми пользователь может взаимодействовать.
Проверять возможность вкладывания тегов друг в друга можено по следующему алгоритму:
Смотрим на контентную модель тега, в который вкладываем.
Смотрим на категории тега, который вкладываем.
Если видим, что категория нам подходит и нет ограничений, то вкладываем, если нет, то вложение запрещено.
Давайте разберёмся на примере. Есть тег <section>
и мы хотим вложить в него тег <b>
: у секции контентая модель Flow, у <b> категории Flow, Phrasing и Palpable. Соответственно вложение допустимо.
Другой пример:
<label>
<p>Имя:</p>
<input type="text" name="name">
</label>
Частая задача, когда нам нужно внутри лейбла держать и инпут и его описание. Проверям:
Для лейбла контентной моделью является Phrasing Content, но без вложения других лейблов.
<p>
не имеет категории Phrasing, поэтому вкладывать<p>
в<label>
нельзя!<input>
имеет категорию Phrasing, поэтому мы можем вложить его в<label>
.
Если сильно упрощать, то во Flow мы можем вкладывать и Flow, и Phrasing, а во Phrasing только Phrasing.
Заключение части 2
Но всю эту простыню можно было не читать, а просто воспользоваться сервисом https://caninclude.glitch.me, написанным Александром Вишняковым и скрин которого я разместил в шапке поста. Там по аналогии с Can I Use, можно проверить, вкладывается ли один тег в другой или нет.
Ну и не забывайте валидировать код с помощью W3C Validator, который тоже сможет подсказать, правильно ли вы вкладывали теги, или нет.