line-height
и vertical-align
— это простые свойства CSS. Настолько простые, что большинство из нас уверены, что понимают, как они работают и как их использовать. К сожалению, это не так — на самом деле они, пожалуй, являются самыми сложными свойствами, поскольку играют важную роль в создании малоизвестной особенности CSS под названием «строчный контекст форматирования» (inline formatting context).
Например, line-height
можно задать в виде длины или безразмерного значения, но его значение по умолчанию — normal
(стандартное). Хорошо, но что значит «стандартное»? Зачастую пишут, что это (как правило) 1, или, может быть, 1,2. Даже в спецификации CSS нет четкого ответа на данный вопрос.
Нам известно, что безразмерное значение line-height зависит от значения font-size
, но проблема в том, что font-size: 100px
выглядит по-разному для разных гарнитур. В связи с этим возникает вопрос: всегда ли line-height
будет одинаковым или может различаться? Действительно ли это значение находится в промежутке от 1 до 1,2? А как vertical-align
влияет на line-height
?
Давайте углубимся в не самый простой механизм CSS…
p
, содержащим три элемента span
, каждый из которых со своим font-family
:<p>
<span class="a">Ba</span>
<span class="b">Ba</span>
<span class="c">Ba</span>
</p>
p { font-size: 100px }
.a { font-family: Helvetica }
.b { font-family: Gruppo }
.c { font-family: Catamaran }
font-size
в разных гарнитурах высота получается различной:font-size: 100px
не создает элементы высотой 100px? Я измерил эти значения: Helvetica — 115px, Gruppo — 97px и Catamaran — 164px.font-size
.background
.font-size
, а не от вычисленной высоты).p
при отображении на экране может состоять из нескольких строк с соответствующей шириной. Каждая строка состоит из одного или нескольких строчных элементов (inline elements)(HTML-тегов или анонимных строчных элементов для текстового содержимого) и называется контейнером строки (line-box). Высота контейнера строки зависит от высот его дочерних элементов. То есть браузер вычисляет высоту каждого строчного элемента, а по ней — высоту контейнера строки (от самой верхней до самой нижней точки ее дочерних элементов). В результате высоты контейнера строки всегда достаточно, чтобы вместить все его дочерние элементы (по умолчанию).Каждый HTML-элемент на самом деле представляет собой стопку контейнеров строки. Если вам известна высота всех контейнеров строки, то известна и высота элемента.
<p>
Good design will be better.
<span class="a">Ba</span>
<span class="b">Ba</span>
<span class="c">Ba</span>
We get to make a consequence.
</p>
span
.::first-line
не помогает отобразить высоту первого контейнера строки.line-height
, и это — высота, которая используется для вычисления высоты контейнера строки.line-height
— это расстояние между базовыми линиями (baseline). В CSS это не так.line-height
(виртуальная область) может быть равной, больше или меньше области содержимого. Если виртуальная область меньше, то значение интерлиньяжа отрицательное и контейнер строки визуально меньше своих дочерних элементов по высоте.img
, input
, svg
и т. д.);inline-block
и все элементы типа inline-*
;height
, margin
и border
. Если для height
указано значение auto
, то применяется line-height
, и высота области содержимого равна line-height
.line-height
? Ответ на этот вопрос, как и в случае вычисления области содержимого, нужно искать среди метрик шрифта. Итак, вернемся к FontForge. Размер em-квадрата для Catamaran равняется 1000, но мы наблюдаем много значений для верхних и нижних выносных элементов:line-height: normal
, данное значение прибавляется к метрикам Ascent/Descent (таблица «hhea»).line-height: normal
будет равняться области содержимого, которая составляет 1640 единиц или 1,64.font-size: 100px
область содержимого составит 112px (1117 единиц), а значение line-height: norma
l — 115px (1150 единиц или 1,15). Все эти метрики индивидуальны для каждого шрифта и задаются дизайнером шрифта.line-height: 1
неэффективно. Напомню вам, что безразмерные значения зависят от font-size
, а не от области содержимого, а то, что размер области содержимого превышает размер виртуальной области, является причиной множества наших проблем.line-height: 1
. Если уж на то пошло, из 1117 шрифтов, установленных на моем компьютере (да, я установил все шрифты из Google Web Fonts), у 1059 шрифтов, то есть в 95%, вычисленный показатель line-height
больше 1. Вообще, их вычисленный показатель line-height
варьируется от 0,618 до 3,378. (Вам не показалось — 3,378!)line-box
:margin-top
и margin-bottom
нет никакого эффекта.inline-block
и блокофицированных строчных элементов — padding
, margin
и border
увеличивают height
и, следовательно, высоту области содержимого и контейнера строки.vertical-align
может играть ведущую роль в строчном контексте форматирования.baseline
. Помните такие метрики шрифта, как высота верхнего и нижнего выносных элементов (ascender/descender)? Эти значения определяют, где находится базовая линия и, следовательно, соотношение между верхней и нижней частями. Поскольку соотношение между верхним и нижним выносными элементами редко бывает 50/50, это может приводить к неожиданным результатам, например с элементами того же уровня.<p>
<span>Ba</span>
<span>Ba</span>
</p>
p {
font-family: Catamaran;
font-size: 100px;
line-height: 200px;
}
p
с двумя одноуровневыми элементами span
, наследующими font-family
, font-size
и фиксированную line-height
. Базовые линии совпадают, и высота контейнера строки равна их line-height
.font-size
будет меньше?span:last-child {
font-size: 50px;
}
line-height
, но иногда требуются фиксированные значения для создания идеального вертикального ритма. Честно говоря, независимо от того, что вы выберете, у вас всегда будут проблемы с выравниванием строки.p
с line-height: 200px
, который содержит один единственный span
, наследующий его line-height
<p>
<span>Ba</span>
</p>
p {
line-height: 200px;
}
span {
font-family: Catamaran;
font-size: 100px;
}
p
есть свое собственное, отличающееся значение font-family
(по умолчанию это serif). Базовые линии тега p
и span
, по всей вероятности, находятся на разной высоте, и поэтому высота контейнера строки больше, чем предполагалось. Это вызвано тем, что браузеры производят вычисление, считая, что каждый контейнер строки начинается с символа нулевой ширины, который в спецификации называется «strut».vertical-align: middle
? Как сказано в спецификации, middle
«выравнивает контейнер по вертикальной средней точке (midpoint) с базовой линией родительского контейнера плюс половина x-высоты первичного элемента». Соотношение базовых линий, равно как и x-высот (x-height), может быть различным, поэтому на выравнивание по middle
тоже нельзя положиться. А хуже всего тот факт, что в большинстве сценариев middle
никогда не бывает по-настоящему «по центру». На это влияет слишком много факторов, которые нельзя задать через CSS (x-высота, соотношение верхнего и нижнего выносных элементов и др.).vertical-align: top / bottom
— выравнивание по верхней или нижней границе контейнера строки;vertical-align: text-top / text-bottom
— выравнивание по верхней или нижней границе области содержимого.vertical-align: top
. Невидимая line-height
может давать странный, но ожидаемый результат.vertical-align
также принимает числовые значения, которые смещают контейнер выше или ниже относительно базовой линии. Этот последний вариант может пригодиться.line-height
и vertical-align
, но сейчас вопрос в том, можно ли управлять метриками шрифта через CSS? Если кратко, то нет. Хотя я бы этого очень хотел. В любом случае, думаю, настало время немного развлечься. Метрики шрифта являются постоянными величинами, поэтому хоть что-то у нас должно получиться.font-size
, при котором высота прописных букв будет равняться 100px.p {
/* метрики шрифта */
--font: Catamaran;
--fm-capitalHeight: 0.68;
--fm-descender: 0.54;
--fm-ascender: 1.1;
--fm-linegap: 0;
/* необходимый размер шрифта для высоты прописных букв */
--capital-height: 100;
/* применить font-family */
font-family: var(--font);
/* рассчитать размер шрифта для получения высоты прописных букв, равной необходимому размеру шрифта */
--computedFontSize: (var(--capital-height) / var(--fm-capitalHeight));
font-size: calc(var(--computedFontSize) * 1px);
}
vertical-align
на основании соотношения между верхним и нижним выносными элементами.line-height: normal
и высоту области содержимого:p {
…
--lineheightNormal: (var(--fm-ascender) + var(--fm-descender) + var(--fm-linegap));
--contentArea: (var(--lineheightNormal) * var(--computedFontSize));
}
p {
…
--distanceBottom: (var(--fm-descender));
--distanceTop: (var(--fm-ascender) - var(--fm-capitalHeight));
}
vertical-align
как разницу между этими расстояниями, умноженную на вычисленное значение font-size
(Это значение нужно применить к строчному дочернему элементу).p {
…
--valign: ((var(--distanceBottom) - var(--distanceTop)) * var(--computedFontSize));
}
span {
vertical-align: calc(var(--valign) * -1px);
}
line-height
и вычисляем его, сохраняя вертикальное выравнивание:p {
…
/* необходимая высота строки */
--line-height: 3;
line-height: calc(((var(--line-height) * var(--capital-height)) - var(--valign)) * 1px);
}
span::before {
content: '';
display: inline-block;
width: calc(1px * var(--capital-height));
height: calc(1px * var(--capital-height));
margin-right: 10px;
background: url('https://cdn.pbrd.co/images/yBAKn5bbv.png');
background-size: cover;
}
line-height
);line-height: normal
зависит от метрик шрифта.line-height: n
виртуальная область может стать меньше области содержимого.vertical-align
особо полагаться не стоит.line-height
и vertical-align
его дочерних элементов.К сожалению, не доступен сервер mySQL