CSS-live.ru

Введение в инлайновый контекст форматирования (ИКФ): основные понятия (1-я публикация цикла «Тайны CSS2.1»)

В основе этой статьи лежит перепевка спецификации CSS 2.1 по телефону Рабиновичем SelenIT-ом. Если что-то вышло криво — я не виноват, это всё он. Конструктивная критика и предложения по улучшению материала приветствуются!

Перед тем как погрузиться в мир инлайнового контекста, мне  казалось, что это не очень сложная тема, и что понять её будет не трудно. Но, чем больше я углублялся в процесс изучения, тем больше понимал, что это далеко не простая и  даже очень обширная и сложная тема для понимания.

Ещё больше я боялся за то, что не смогу передать на бумаге все тонкости и особенности построения этого механизма нашим читателям. Поэтому каждую статью цикла я буду стараться писать так, чтобы каждая её деталь была написана на доступном и понятном языке.

Ну, как говорится — с Богом!

Лайн-бокс

Зачем вообще нужен лайн-бокс?

Говоря простым языком, лайн-бокс — это удобный виртуальный контейнер, от которого «пляшут» элементы строки (инлайн-боксы). Дело в том, что при построении строки рендерер (механизм отрисовки страниц в браузерах и построения DOM-дерева) должен как-то узнать, какую Y-координату дать следующей порции инлайнового контента (тексту, картинкам и т.п.). Можно сказать, что лайн-бокс — это способ учёта пространства по вертикали, занимаемого инлайном.

Построение лайн-бокса

В инлайновом контексте форматирования инлайн-боксы выкладываются друг за другом горизонтально, начиная от верха контейнера и заполняются слева направо (или справа налево у евреев и арабов). Горизонтальные marginborder и padding между инлайн-боксами учитываются. Инлайн-боксы могут выравниваться по вертикали по-разному: по верхней либо нижней границе, или по базовым линиям текста в них. Прямоугольная область, содержащая инлайн-боксы из одной строки, называется лайн-боксом.

Так, стоп. Понимаю, что многие из вас уже запутались и потеряли нить. Поэтому теперь предлагаю чуть помедленнее, с кодом и картинками.

Вначале рассмотрим простой пример. Код будет таким:

<p> один <em> два </em> три </p>

Вроде бы всё просто, обычный блочный элемент (<p>), содержащий в себе одну строку, в которой есть текст и инлайн-элемент (<em>). Но на самом деле в подноготной самой строки произошёл следующий эффект:

 

На картинке мы можем видеть параграф, генерирующий блочный бокс, в котором и должны находится лайн-боксы. Этот блочный элемент содержит в себе один лайн-бокс (1), три инлайн-бокса (2a, 2n, 2a), в одном из которых (2n) находится просто текст.  А теперь разберём более детально.

Под цифрой "1" изображён лайн-бокс, сгенерированный сразу же после генерации блочного бокса (параграфа). Так как у нас одна строка, то лайн-бокс соответственно тоже один (о двух-строчных чуть позже). 
Под цифрами 2a, 2n, 2a находятся инлайн-боксы. На рисунке их ровно три. Они очень похожи друг на друга, но, несмотря на это, между некоторыми из них есть одно важное отличие. Два боковых илайн-бокса (2a) на самом деле являются анонимными, в отличии от среднего (2n), "натурального". Что это значит? 

Анонимный инлайн-бокс

Анонимными инлайн-боксами называются те боксы, которые находятся непосредственно в самом лайн-боксе. Те, которые являются его ближайшими текстовыми потомками, не обёрнутыми  ни в один инлайн-элемент.

Для чего это нужно? Давайте представим себе ситуацию. Есть такой html:

<p> red <em>green <span>blue</span></em></p>

И вот такие вот стили:

p { color: red }
em {color: green }
span { color: blue }

В этом примере есть три инлайн-бокса разного цвета. Со вторым и третьим понятно, а что "красит" первый? Лайн-бокс взять на себя работу по его "покраске" не может, он нужен для других вещей, которые я описывал выше. Лайн-бокс — не "физический объект", а скорее геометрическая условность, он является всего лишь "счетчиком", передавая главному "штабу" информацию о своих координатах. В связи с этим нужен тот, кто сможет взять на себя стили, доставшиеся по наследству от блочного родителя, и "распорядиться этим наследством" как следует. И этим "кем-то" является анонимный инлайн-бокс, к которому и применяется CSS.

Да, стоит уточнить, что в строчном контексте форматирования CSS применяется именно к инлайн-боксам, будь то они анонимные или "натуральные". Ну, и конечно же то, что в самих инлайн-боксах не бывает анонимных инлайн-боксов, они существуют только на верхнем уровне, как я и говорил выше. В самих инлайн-боксах текст является просто текстом.

"Натуральный" инлайн-бокс (т.е. не анонимный)

"Натуральным" инлайн-боксом можно назвать тот бокс, который генерируется самим инлайн-элементом, в нашем случае это элемент <em>. Так же существует ещё ряд "натуральных" инлайн-боксов, таких как картинки, инлайн-блоки и т.д. В общем, все "живые" инлайн-сущности, которые мы можем видеть в структуре, превращаются в инлайн-боксы.

Ну, и чтобы совсем уж было понятно, я попытаюсь изобразить дерево данной структуры.

  • * Block (p)
    • * line box
      • anonymous inline box (текст: "один")
      • * inline box (em)
      • anonymous inline box (текст: "три")

Это был самый лёгкий пример, но, пожалуй, рассмотрим более сложную ситуацию, где структура будет такой:

<p> один <em> два <i> три </i> четыре </em> пять
шесть <span> семь <i> восемь </i> девять </span></p>

В 99% случаев текст в документе состоит из двух и более строк. Что же происходит в таком случае с лайн-боксом? Нет, он не разрывается, вместо этого у нас появляется уже два лайн-бокса! Да, именно так. В этой ситуации рендерер заканчивает с первой строкой и начинает ренредить новую. Причём рендерер производит абсолютно такую же операцию над следующей строкой, как и с предыдущей, т.е. начинает выкладывать в ней новые кирпичи один за другим, заново.

Структура в таком случае выглядит так:

На рисунке я постарался отметить каждую детальку, обозначив их цифрами. Как можно увидеть, строк стало две, а следовательно, и лайн-боксов на рисунке образовалось ровно два! Но всё-таки, давайте по порядку.

Как и на предыдущем рисунке, под цифрами "1" находятся лайн-боксы, на изображении они отмечены жёлтым цветом. Самое интересное, несмотря на то что контейнер у нас один (<p>), лайн-боксы в нём абсолютно независимы друг от друга. Когда закончилось построение первого, то на "поле"  сразу же появился второй лайн-бокс, с новыми координатами по оси Y. Первый закончил своё построение по той причине, что боксы внутри него попросту заняли всё доступное в нём пространство, а последнему не хватило в лайн-боксе места, и он вынужден был переместиться на новую строку.  А раз новая строка – значит новый лайн-бокс. Это железное правило и о нём нужно помнить!

Далее идут уже знакомые вам цифры: "2a" и "2n" обозначают анонимные инлайн-боксы () и соответственно "натуральные"  (2n). Их отличие я уже объяснял в первом примере, поэтому единственное, что хочу тут отметить, это то, что теперь у нас в структуре появились составные инлайн-боксы.

Составной инлайн-бокс

Если в инлайн-боксе находится от двух и более инлайн-боксов или, например, текст и инлайн-боксы, то такой инлайн-бокс считается составным, потому что состоит из нескольких частей. В нашем случае мы имеем два составных инлайн-бокса, один из них — элемент <em> в первом лайн-боксе, а другой <span> во втором. Например, <em> состоит из трёх частей: текст ("два"), инлайн-бокс (<i>) и за ним снова текст ("четыре"). 

Ну, и последнее, на чём стоит заострить наше внимание, это цифры "3", которые указывают на обычный текст в инлайн-боксах. Стоит заметить, что инлайн-боксом для такого текста является их контейнер, а сами они ничего не генерируют, в отличие, например, от текста в самих лайн-боксах (). Дело в том, что внутри инлайн-боксов текст является просто текстом, ему нет смысла генерировать лишние инлайн-боксы, так как CSS стили ему может передать его собственный контейнер. 

Дерево такой структуры будет выглядеть так:

  • * Block (p)
    • * line box
      • anonymous inline box (текст: "один")
      • * inline box (em)
        • * текст: "два"
        • * inline box (i)
        • * текст: "четыре"
      • anonymous inline box (текст: "пять")
    • * line box
      • anonymous inline box (текст: "шесть")
      • * inline box (span)
        • * текст: "семь"
        • * inline box (i)
        • * текст: "девять"

Кстати, обратите внимание на один интересный момент. А именно, на анонимные инлайн-боксы в конце первого лайн-бокса и в начале второго. Оба они являются анонимными, потому что их родителями, по факту, являются лайн-боксы. А если бы, например структура выглядела бы так:

<p> один <em> два <i> три </i> четыре </em><i> пять
шесть </i><span> семь <i> восемь </i> девять </span></p>

То дерево было бы уже таковым:

  • * Block (p)
    • * line box
      • anonymous inline box (текст: "один")
      • * inline box (em)
        • * текст: "два"
        • * inline box (i)
        • * текст: "четыре"
      • * inline box (i)
    • * line box
      • * inline box (i)
      • * inline box (span)
        • * текст: "семь"
        • * inline box (i)
        • * текст: "девять"

В этом примере элемент <i> как бы разрывается на две части и образует два инлайн-бокса — в двух строках. Часть содержимого элемента <i>, которой хватило места в первом лайн-боксе, образовала первый инлайн-бокс, а сам факт переноса привел к появлению нового лайн-бокса (новой строки), в начале которой разместился второй инлайн-бокс с остатком содержимого элемента.

Пробел — как анонимный инлайн-бокс или текст

Ещё один важный момент в этой части рассказа, который стоило бы разобрать, это пробелы между инлайн-боксами, которые могут превратиться в анонимные инлайн-боксы или в обычный текст. Чтобы было понятно о чём идёт речь, сразу же приведу наглядный пример.

<p> один <em> два <i> три </i> <i> четыре </i> пять </em> <span> шесть </span></p>

Ну и конечно же изображение:

Я не стал расписывать эту структуру по всем частям, здесь суть не в этом. Я лишь прошу вас обратить внимание на два выделенных места, которые помечены цифрами "1" и "2". Дело в том, что это один из важных моментов при строчном форматировании, о котором следует знать. Суть в самих пробелах. Пробелах между инлайн-элементами или попросту "натуральными" инлайн-боксамиВыяснилось, что эти, как мне до этого казалось, обычные "сдвиги координат", могут генерировать анонимные инлайн-боксы, точнее не все из них, а только пробелы верхнего уровня, находящиеся непосредственно в самом лайн-боксе. В нашем случае такой пробел (сгенерированый анонимный инлайн-бокс) пробел находится между элементами <em></em> и <span></span> и обозначается цифрой "2" .

А вот пробелы, которые находятся между инлайн-элементами в самих инлайн-боксах, тоже не пропадают зря, а становятся обычным текстом, как и любой другой текст в инлайн-боксах. Такой пробел вы можете наблюдать под цифрой "1" в нашем примере.

Я полагаю, что это логично, так как пробел всё же тоже является символом, а значит так же, как и другие символы, имеет право на собственный контейнер, не так ли?

Продолжение:

2. Введение в инлайновый контекст форматирования (ИКФ): основные понятия (2-я публикация цикла “Тайны CSS2.1″).

3ИКФ: высота строки, часть 1 (3-я публикация цикла “Тайны CSS2.1″).

4ИКФ: высота строки, часть 2 (4-я публикация цикла “Тайны CSS2.1″).

5ИКФ: высота строки, часть 3 (5-я публикация цикла “Тайны CSS2.1″).

6. ИКФ: высота строки, часть 4 (6-я публикация цикла “Тайны CSS2.1″).

7ИКФ: высота строки, часть 5 (7-я публикация цикла “Тайны CSS2.1″).

8ИКФ: Вертикальное выравнивание в строке, часть 1 (8-я публикация цикла “Тайны CSS2.1″).

9ИКФ: Вертикальное выравнивание в строке, часть 2 (9-я публикация цикла “Тайны CSS2.1″).

10. ИКФ: Вертикальное выравнивание в строке, часть 3 (10-я публикация цикла “Тайны CSS2.1″).

11ИКФ: Горизонтальное выравнивание, часть 1 (11-я публикация цикла “Тайны CSS2.1″).

12ИКФ: Горизонтальное выравнивание, часть 2 (12-я публикация цикла “Тайны CSS2.1″).

P.S. Это тоже может быть интересно:

34 комментария

  1. А какие выводы из всего этого? Где-то в стандартах описаны лайн-боксы? Могут ли у верстальщика возникнуть проблемы, например, с бэкграундом, если он случайно сделает анонимный инлайн-бокс?

    1. Этот цикл статей — как раз вольный пересказ стандарта CSS2.1 (который является единственным действующим стандартом для визуальной модели, пока не будет утвержден CSS3 Box).

      Понимать механизмы визуализации текста полезно, чтобы знать, кто из браузеров прав в случае разногласий, а кому слать багрепорт :). В этом примере фон :first-line все браузеры, кроме Оперы, применяют к анонимному инлайн-боксу, поэтому слово, прижатое к низу лайн-бокса, оказывается написано белым на белом, без знания «анатомии» инлайнового контекста в подобной ситуации можно запутаться и потерять много времени на отладку.

          1. Я там еще вот что нашел: «In CSS a ::first-line pseudo-element is similar to an inline-level element if its ‘float’ property is ‘none’; otherwise, it is similar to a floated element» (раздел 7.2.1). Не пойму, то ли это баг в спеке, то ли какая-то мудреная фича.

            1. Круто, реально опечатка в спеке :). По контексту понятно, что речь про ::first-letter, но да, редакторы лажанулись знатно…

      1. SelenIT,  спасибо за пример.  Вот.. хотелось бы так же развернуто  про вертикальную "анатомию" инлайн бокса. :)
        Кстати, тебе отдельное спасибо за комментарий оставленное на Хабре вот тут http://habrahabr.ru/post/117109/,  это для меня было открытием. :)

        1. > хотелось бы так же развернуто  про вертикальную "анатомию" инлайн бокса
          Всё будет. В ближайших публикациях этого цикла! :)

        2. Вот.. хотелось бы так же развернуто  про вертикальную "анатомию" инлайн бокса. :)

          Да, это очень интересная и познавательная тема, спору нет, но всему своё время, потерпите, скоро всё будет!smiley

  2. поясните мне пожалуйста вторую картинку. «пять» находится в первом лайн-боксе, «шесть» — во втором. как я понял, это обусловлено только тем, что из-за ширины родительского для P блока перенос строки произошёл именно в этом месте. если бы всё, что находится в P на экране располагалась бы в одну строку, то каким бы образом произошло разбиение лайн-боксов?

    1. Да, второй лайн-бокс появился именно из-за переполнения ширины. Если бы всё влезло в одну строку, лайн-бокс был бы единственным.

  3. Макс, хотелось бы в конце статьи небольшой — Итого.
    Итог, я сделала из статьи:
    1. Лайн-бокс- виртуальный контейнер, который нужен для расчета Y координаты.
    2. Инлайн бокс — может быть анонимным и «натуральным».
    3. Анонимный бокс — гененируется текстом, а «натуральный» инлайн-бокc инлайн тегом?
    4. Каждая новая строка — новый лайн бокс.
    5. Пробел в самом лайн боксе — анонимный бокс, а на уровне инлайн-боксов — текст.

    Вопросы:
    1. Кто знает про анонимный бокс? родитель? можно ли к нему обратится? аноноимный бокс- это интерфейс или также виртуальный бокс?
    2. Базовая линия не зависимо от количество инлайн-боксов одна на одну строку. Какой инлайн бокс влияет на её формирование?

    1. 3. Анонимный бокс – гененируется текстом…

      Правильнее было бы сказать так. Анонимный инлайн-бокс геренируется текстом или пробелом, которые находятся непосредственно в лайн-боксе, т.е. являются его дочерним потомком, так сказать.

      а “натуральный” инлайн-бокc инлайн тегом?

      Не совсем. Правильнее было бы сказать, любым элементом (НЕ тегом!) с display: inline. Это может быть <div>, может быть и <span> :) 

      Пробел в самом лайн боксе – анонимный бокс

      И не только пробел, текст тоже. Читайте предыдущий ответ.

      Кто знает про анонимный бокс?

      Эта статья и мы чуть-чуть)))

      родитель?

      Родителем анонимного инлайн-бокса является лайн-бокс.

      можно ли к нему обратится?

      Прочитайте внимательно вот эти темы и эти посты плз.

      аноноимный бокс- это интерфейс или также виртуальный бокс?

      Все они… виртуальные, гады)

      Базовая линия не зависимо от количество инлайн-боксов одна на одну строку. Какой инлайн бокс влияет на её формирование?

      Вот здесь я вам рекомендую не торопить события. Это материал наших следующих статей. Пока переварите эти :)

       

  4. что-то как то запутано:

    Под цифрами 2a, 2n, 2a находятся инлайн-боксы.

    и тут же почти:

    Два боковых лайн-бокса (2a)

    Может всё таки 2а инлайн боксы?

      1. и вот это тоже с толку сбивает

        Те, которые являются его ближайшим текстовым потомком, не обёрнутыми  ни в один инлайн-элемент. Для чего это нужно? Давате представим себе ситуацию. Есть такой html:
        Вопрос: Кто расскажет про цвет текста "red" (первый дочерний текст у параграфа)? Сам блок (p) не может этого сделать, он находится слишком далеко по структуре. А если так, то как же управлять  ::first-line?

        Вроде бы начинеатся разъяснение ананимного инлайн-бокса, но тут же обрывается мысль и сразу же заводится речь о ::first-line.

        1. Вот тут я считаю, что всё верно. Сначала объясняется, что представляет из себя анонимный инлайн-бокс, а далее для чего он собственно нужен. Но всё равно подправил для ясности. Спасибо!

          Мы бы были вам очень признательны, если бы прочитали все части нашего цикла и выписали все недочёты нам на почту. psywalker@css-live.ru

  5. долго думал над "Горизонтальные: margin, border и padding между инлайн-боксами учитываются". может удачнее будет "боковые" ?

    1. Имхо, "Горизонтальные" подходят намного лучше. А вообще, странно, что это вас смутило, т.к, я, например, не представляю, как Горизонт может быть иным или непонятным. Может что-то конкретнее есть, что мы не понимаем?

    2. Допустим. А как тогда удачнее назвать вертикальные margin'ы, border'ы и padding'и с Вашей точки зрения?
      Лично я не вижу ничего необычного в слове "горизонтальные", более того, считаю, что использование этого термина наиболее удачно вписывается в данный контекст, поскольку в самой спецификации в данном контексте используется именно термин "горизонтальные".

  6. Можно ли считать Вашу последнюю мысль про анонимные пробелы, воспринимать так: «Наиболее правильно, внутри блочного элемента, создавать строчный, и уже в нём писать текст»?

  7. Какой кошмар! Почему нилзья просто взять и написать вещи своими именами ? inline-block например ? Зачем переводить названия свойств ? Кошмар.

    1. Потому что, во-первых, inline-block — не свойство, а значение. Во-вторых, в статье не переводятся названия свойств. В третьих, понятия line box и inline box, о которых идет речь в статье и без которых невозможно понять многие «странности» поведения текста в CSS, не имеют отношения к термину «inline-block» от слова «совсем». И одной из целей статьи было как раз предотвратить эту путаницу.

      Ну и статья написана 6 лет назад, когда русская терминология по строчному форматированию в CSS еще не устоялась. Но у нас есть на эту тему и материал поновее.

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Получать новые комментарии по электронной почте. Вы можете подписаться без комментирования.