Битва за базову лінію
Колись найкращим рішенням для інлайнових блоків були, ну, інлайн-блоки. Мені вони дуже подобаються за те, що з їх допомогою можна вирішити безліч завдань. Але і вони не всемогутні. Вони не вміють правильно працювати з вертикальним вирівнюванням тексту по базовій лінії шрифту. Причому проблема випливає вже з специфікації (Див. Останній абзац):
Для багаторядкових інлайн-блоків базової лінією є базова лінія останнього сатиричного боксу в звичайному потоці.
Якщо всередині інлайн-блоку немає боксів звичайного потоку, або ж у інлайн-блоку варто overflow відмінний від visible, то базовою лінією стає нижня межа блоку.
Через ці проблем вийде вирівняти по базовій лінії тільки однорядкові блоки без заданого overflow, тоді як в будь-яких більш складних випадках вийде зовсім не те, що може бути потрібно.
Ось приклад: все три блоку мають display: inline-block. Перший - звичайний однорядковий і з великим паддінгом, другий - багаторядковий, але з меншим розміром шрифту, третій - однорядковий, але з overflow: auto.
I'm an inline-block
I'm an inline-block
With a second line
I'm an inline-block with an overflow auto
На цьому прикладі добре видно , Де у якого блоку знаходиться базова лінія.
inline-table
В CSS було одне місце, де вертикальне вирівнювання працювало * правильно * - display: inline-table. Замінюємо інлайн-блоки на нього і отримуємо, здавалося б, то, що потрібно:
I'm an inline-table
I'm an inline-table
With a second line
I'm an inline-table with an overflow auto
Але тут відразу видно: не працює overflow: auto. До того ж такого блоку потрібно задавати table-layout: fixed. Виходить ідеально, якщо не потрібен overflow: auto.
П робу флексбокси
Чи можна зробити блок з скроллбар, який буде правильно вирівнюватися? Тут на допомогу поспішають флексбокси, точніше, display: inline-flex. В теорії вони також мають правильне положення базової лінії, але що ми отримуємо на практиці?
I'm an inline-flex
I'm an inline-flex
With a second line
I'm an inline-flex with an overflow auto
Якщо ви подивіться на цей приклад в будь-якому браузері крім Firefox (так, навіть в IE 10 і 12-й Опері), то ви бачите ідельно вирівняні блоки.
Але в Fx блок з overflow: auto, раптово, працює аналогічно інлайн-блоку: втрачає базову лінію. Смуток, печаль, розчарування, чекаємо виправлення свежезарепорченного бага .
А якщо інакше?
Дуже здорово, що inline-flex сам по собі правильно вирівнюється щодо інших блоків, і, якби не баг Fx, все було б зовсім чудово. Але що якщо ми спробуємо вирівнювати не різні inline-flex відносно один одного, а елементи всередині флексбокса?
I'm an inline-flex
I'm an inline-flex
With a second line
I'm an inline-flex with an overflow auto
Оп! Все працює! Ось тільки ... Якщо окремі блоки з inline-flex самі по собі переносяться на новий рядок, то для елементів всередині флексбокса нам треба було б застосовувати flex-wrap. Але Firefox його не підтримував до версії 28.0.
Всі разом
Так! Але ж якщо inline-flex прокидає свою базову лінію нагору, а внутрішній блок з overflow: auto також має правильне вирівнювання навіть в Firefox, то можна ж поєднати! Додамо в кожен блок по додатковому елементу, нехай буде він ставити паддінгі і overflow вже на них:
I'm an inline-flex
With a second line
I'm an inline-flex with an overflow auto
У нормальних браузерах нічого не змінилося, тепер подивимося на Firefox ... Так, блок вже вирівнюється не по нижній межі, але і не по базовій лінії. Хоча, виміряємо різницю: 10 пікселів. Це ж наш паддінг! Прибираємо паддінгі по черзі - все вирівнюється правильно, коли верхній паддінг стає дорівнює нулю. Ага, значить Fx в цьому випадку все робить майже вірно, ось тільки сплив новий баг. Поки ми чекаємо його виправлення , Позбудемося-ка від паддінга, замінивши його на псевдо-елемент:
I'm an inline-flex
With a second line
I'm an inline-flex with an overflow auto
Ідеально!
П оследніе штрихи
Ну ладно, не ідеально. Залишається пара дрібниць, які можуть проявитися в десятому IE і в дванадцятій Опері.
В IE при заданій ширині флексбокса текст всередині нього не буде врапаться, навіть якщо не буде стояти white-space: nowrap. Досить дивний баг, обходиться або додаванням внутрішнього блоку явною ширини в 100%, або, що правильніше, -ms-flex-negative: 1.
В Опері дуже схожий баг - внутрішній блок не реагує на задану ширину, через що в блоці немає переносів. Єдиний спосіб це виправити, який я знайшов: додати батькові flex-direction: column - так як у нас завжди тільки один внутрішній елемент, це ні на що не вплине.
тепер ідеально . Ось останній приклад з різними варіантами, які переносяться з рядка на рядок:
Just some inline text
I'm an inline-flex
With a second line
I'm an inline-flex with an overflow auto
I'm an inline-flex with the text wrapped on the next lines
I'm just another inline-flex block with a lot of content and overflow: auto.
Код виходить таким:
.flex {display: -ms-inline-flexbox; display: -webkit-inline-flex; display: inline-flex; / * Fixing Opera issue * / flex-direction: column; vertical-align: baseline; } .Flex-content {padding: 0 10px 10px; border: 1px solid lime; / * Fixing IE issue * / -ms-flex-negative: 1; } / * Fixing Fx issue * / .flex-content: before {content: ""; display: block; padding-top: 10px; }
І того
Ох вже цей Firefox! Якби не його баги (і один баг десятого IE), то ми могли б обійтися одним елементом для кожного інлайнового блоку, який ми хочемо вирівняти по базовій лінії. А якщо вам не потрібен overflow відмінний від visible, і ви не боїтеся таблиць, то можна спробувати використовувати display: inline-table.
Так, чи інакше, ми перемогли. Тепер можна вирівнювати блоки по їх базових ліній незалежно від їх складності, ура! Якщо ви хочете застосовувати цю техніку без зайвих блоків, настійно раджу піти і проголосувати за виправлення відповідних багів в багзілле.
А якщо інакше?Але що якщо ми спробуємо вирівнювати не різні inline-flex відносно один одного, а елементи всередині флексбокса?