«Блочных и строчных элементов» в HTML больше нет
Для тех, кому лень читать всю статью: в современном HTML нет «блочных» и «строчных» элементов. Это деление — историческая ошибка, условность и анахронизм времен конца 90-х. Что во что можно вкладывать, а что нет, определяется не тем, как элементы выглядят, а тем, что они делают. А «блочностью», «инлайновостью», любыми их комбинациями и др. чисто внешними чертами заведует только CSS.
Остальное — для тех, кто до сих пор не верит или просто желает разобраться до конца.
Немало мифов ходит о «блочных» и «строчных» элементах. Даже верстальщики с опытом больше года порой верят в то, что «блочные элементы нельзя вкладывать в строчные, но можно в другие блочные» или что «с помощью CSS можно превратить одни в другие и наоборот». Некоторые, больше того, рассуждают о «блочных и строчных тегах». Как тут не запутаться новичку?
Так вот, на наш век выпала большая радость: «блочных» и «строчных» элементов в HTML больше нет. Теперь и формально. Актуальная спецификация HTML (она же «HTML5») классифицирует элементы HTML исключительно по их логической роли, по их смыслу.
Чтобы убедиться, что так и должно было быть, предлагаю немного оглянуться назад (в историю), в сторону (смежные технологии) и просто в объективную реальность.
Взгляд в прошлое
Откуда вообще пошли эти «блочные» и «строчные»? В самой первой версии HTML (1992) их не было. В первой версии, более-менее похожей на стандарт (HTML 2.0, 1995) появляются «Block structuring elements» (абзацы, списки, листинги кода и т.п.) и «Phrase elements» (выделения в тексте идиоматических выражений, ссылок и т.п.), различия между ними сугубо семантические (характерно, что заголовки стоят особняком от этого деления, причем «блочным структурным элементам» явно запрещается содержать заголовки!). Так что нынешние «фразовый» и «потоковый» контент — не что-то новое, а скорее «возврат к истокам».
В HTML 3.2, утвержденном в начале 1997 г. — уже после первых «столкновений» в «браузерной войне» Нетскейпа с IE — деление элементов на блочные и текстовые (!) стало более явным:
Большинство элементов, которые могут находиться в теле документа, попадают в одну из двух групп: элементы уровня блока, которые вызывают разрыв абзаца, и элементы уровня текста, которые этого не делают. Основные элементы уровня блока включают H1 — H6 (заголовки), P (абзацы) LI (пункты списка) и HR (горизонтальные черты). Основные элементы уровня текста включают EM , I , B и FONT (акцент на символах), A (гипертекстовые ссылки), IMG и APPLET (внедрение объектов) и BR (разрыв строки). Заметьте, что блочные элементы обычно выступают как контейнеры для элементов уровня текста и других элементов уровня блока (исключая заголовки и элемент address), тогда как элементы уровня текста могут содержать лишь другие элементы уровня текста. Точная модель зависит от конкретного элемента.
Как видно, наплыв презентационного (оформительского) подхода к разметке дал свои плоды: одним из критериев классификации стало то, вызывает ли элемент «разрыв абзаца» (и по этому критерию заголовки стали блочными). Но логика элемента, его структурная роль, пока на первом месте (причем подчеркивается, что эта роль, а значит, и возможное содержимое, у разных элементов может различаться).
В 1998 г. появляется HTML 4.0, который (в виде HTML 4.01 — результата мелких правок в 1999-м, и XHTML 1.0 — результата перевода той же семантики на др. синтаксис в 2000-м) становится де-факто единственным языком веб-разметки на целое десятилетие с лишком. Именно он принес то деление элементов на блочные и «инлайновые» (вместе с самим этим термином), к которому мы привыкли. С этого момента критериев такого деления три (они же в переводе):
- Модель содержимого (блочные могут содержать и инлайны, и другие блоки, а инлайны — только другие инлайны, т.е. блоки — это более крупные структурные единицы);
- Форматирование по умолчанию (блоки начинаются с новой строки, инлайны — нет);
- Особенности наследования направления текста в двунаправленном письме.
Чем плоха эта классификация? Во-первых, она неполна: как минимум два элемента — INS и DEL — были «хамелеонами», попадающими то в одну, то в другую категорию в зависимости от их собственного содержимого. Во-вторых, она никак не объясняет, почему часть «блочных» элементов может содержать другие блоки (как DIV , LI и DD ), а часть — нет (как заголовки, P и DT ). И главное: ее второй пункт, форматирование (пусть и по умолчанию) явно зависит от другой технологии — CSS.
Вот ведь ирония судьбы: HTML 4.0 как раз пытался вернуть разметке семантическую чистоту, избавиться от презентационных пережитков — а в самых основах породил такую путаницу между семантикой и оформлением, какая и не снилась предшественникам!
Взгляд в CSSторону
Первая спецификация CSS была утверждена в конце 1996 г. — чуть раньше HTML 4. Так что само понятие «блочных» и «инлайновых» элементов тянется именно из CSS. В нем изначально «блочными» считались элементы с display:block или list-item, которые форматируются как единый неделимый прямоугольник и занимают всё доступное пространство контейнера по горизонтали (кроме float-элементов, те особый случай), а «инлайновыми» — все остальные, которые делят место в строке с соседями и могут разрываться на несколько прямоугольников при переносе строки. Для элемента BR пришлось прописывать отдельное исключение: описать его поведение в терминах CSS1 было невозможно (в строку он не вписывался, но и блок не создавал), так что и эта классификация была неполной.
Почти одновременно с HTML4, в том же 1998-м, начал свой долгий и непростой путь CSS2, лишь к июню 2011-го дозревший до стандарта CSS2.1. Все эти годы он продолжает традицию деления визуальной модели на «блочные» и «инлайновые»… но уже не элементы, а специально придуманные штуковины — управляющие боксы (прямоугольники). Между «боксом» и элементом больше нет однозначной связи: один элемент может порождать несколько боксов, может не порождать ни одного (при display: none), и больше того — бокс может возникать сам собой, без всякого элемента (безымянные, или анонимные, боксы — об этих «мистических» незнакомцах стоит рассказать отдельно). Хотя формулировки в спецификации остались изрядно запутанными, основная суть тут достаточно проста.
Вся страница «набирается» из прямоугольников. Каждая строка текста заключается в особый виртуальный прямоугольник, охватывающий всё ее содержимое (в т.ч. картинки и т.п.) по габаритам — контейнер строки (line box). То, что встраивается внутрь этого контейнера строки — это in-line (т.е. буквально «в-строке», «внутристрочные», они же «встроенные») боксы. А контейнеры, в которые «упакованы» сами line box-ы, их «подшитые вместе стопки» — это блоки строк, блочные боксы. Эти контейнеры могут сами дополнительно «паковаться» в другие блоки, покрупнее.
Заметьте, что «line box» и «inline» («внутристрочные») боксы в CSS — не синонимы, а принципиально разные вещи!
На первый взгляд структура та же, что в HTML-документе: крупные структурные блоки, в них структурные блоки помельче, а уже в них — текст и его отдельные выделенные фрагменты. Так-то оно так, но в HTML описывается логическая структура, а в CSS — чисто визуальная. И элементы с «блочной» моделью содержимого больше не обязаны иметь блочное отображение, и наоборот. Да и сами способы отображения не ограничиваются блочностью и строчностью — есть еще таблицы, позже к ним добавятся флексбоксы и гриды…
Неспроста в HTML4 визуальный критерий «блочности» и «неблочности» уточнялся оговоркой «по умолчанию». Долгое время браузеры, действительно, были солидарны в отображении «блочных» элементов HTML 4/XHTML 1 блочными же CSS-боксами, а «инлайновых» (текстовых) элементов — инлайновыми боксами (именно такие значения были «зашиты» во встроенный браузерный CSS, который и используется для отображения страниц при отсутствии/отключении авторских стилей). Но с приходом HTML5 это стало не всегда так. Особенно явно это стало с приходом кастомных элементов (веб-компоненты) — их роль в структуре компонента может быть любой, в т.ч. и контейнером целого блока, но браузеры по умолчанию отображают их все как «инлайновые».
Так нужно ли вообще любой ценой увязывать модель содержимого и дефолтное отображение?
Взгляд в реальность
Итак, давайте запомним несколько простых фактов (и вытекающих из них правил):
- В HTML никаких «блочных» и «строчных» элементов нет. И не нужно. От этого искусственного деления было больше путаницы, чем пользы.
- Модель содержимого у разных HTML-элементов разная, и (как правило) явно диктуется их логическим, структурным предназначением. Не всегда она сводится к делению «блок/текст» (например, та же ссылка в HTML5 может содержать практически любые структурные элементы — но не другие ссылки). Если есть сомнение, можно ли вкладывать что-то во что-то или нет, лучше свериться со спецификацией.
- Визуальная структура оформления, в которой есть «блочные», «строчные» и «внутристрочные» (инлайновые) боксы, относится исключительно к CSS! Не надо путать отображение и разметку созвучными терминами.
CSS действительно может изменить представление элемента до неузнаваемости, но повлиять на модель содержимого он не может. Ведь CSS применяется к элементам DOM, построенной из уже распарсенной разметки. А модель содержимого важна как раз при построении этой DOM, самому парсеру, до вступления CSS в игру.
Кстати, выражение «блочные и строчные теги» — бессмыслица вдвойне. Потому что «блочное» и «инлайновое» — это CSS, который применяется к DOM, а не к разметке. DOM может быть построена вообще не тегами в разметке, а скриптом (document.createElement и т.п.). Теги же разбирает парсер — ничего не знающий о CSS, но имеющий представление о допустимой модели содержимого. Например, о том, что внутри абзаца текста не может быть ни заголовка, ни списка. Интересно, что в вышеупомянутых первых двух версиях HTML закрывающий тег для абзаца вообще не предполагался — авторам HTML и в голову не приходило, что абзац может закончиться где-то еще, кроме начала следующего абзаца или др. блока. Тег нового абзаца рассматривался как своего рода знак пунктуации — символ «красной строки» (он же ^p или ¶ в MS Word). Лишь с приходом XML, с его обязательным явным закрытием всего, абзац начали рассматривать как контейнер (и сразу стали появляться вопросы, почему этот контейнер «не хочет» содержать то да сё).
Вообще, на мой взгляд, при работе со страницей полезно думать именно о DOM-структуре — логична она или нелогична. А не о тегах — «блочные» они или «строчные», «закрыты» ли они и т.п. Именно с DOM-структурой работают и оформление, и скрипты. А теги могут быть любыми, разрешенными спецификацией — главное, чтобы они были одинаково понятны и разработчику, и парсеру. И имели для них обоих (ну и для поисковиков, конечно) один и тот же смысл.
Актуальная спецификация, судя по всему, тоже придерживается такого взгляда.
Взгляд в будущее (вместо заключения)
Кому-то может показаться, что уход в историю деления HTML-элементов по дефолтному отображению усложнит жизнь верстальщика. Мол, раньше было простое правило «блочное в строчное не пихай», а теперь «по каждому поводу надо в спецификацию лазить». Но мы ведь только что увидели, что простота этого «правила» и раньше была обманчивой. Так что, на мой взгляд, жизнь стала наоборот проще: исчез избыточный уровень обобщения, улучшилось разделение ответственности (визуальная модель — только CSS, а HTML — только логическая структура), термины стали определенными и однозначными: «блочными» и «инлайновыми» отныне бывают только CSS-боксы, и ничто иное. Но проще — не значит скучнее! Структура HTML за 20 лет его истории закономерно усложнилась, типов содержимого в нем уже не 2-3, а целых 7, и логика взаимоотношений между ними не всегда очевидна с первого взгляда. Да и новые модули CSS вот-вот порадуют нас новыми типами CSS-боксов. Поэтому учиться чему-то новому нам придется обязательно, и еще не раз. Но разве это — не неизбежный спутник любого прогресса, в любой сфере? И, в конце концов, узнавать что-то новое — жутко интересно, само по себе, не правда ли?