Как убрать лишнее пространство над текстом и под ним в CSS
Уберите лишнее пространство над и под текстом с помощью text-box-trim в CSS. Разберитесь с метриками шрифта и line-height, выберите text-box-edge и настройте поддержку старых браузеров.
Лишнее пространство над текстом и под ним возникает из двух источников: собственных вертикальных метрик шрифта и полуинтерлиньяжа (half-leading), который line-height добавляет (или отнимает) с каждой стороны строки. Нативное решение в CSS — text-box: trim-both cap alphabetic.
Вы задали line-height: 1.1, убрали все отступы, а заголовок всё равно находится в блоке, который выше самих букв. Тогда вы добавили отрицательный margin, подбирали его, пока не стало выглядеть нормально, и забыли об этом. А потом сменился фирменный шрифт.
В этой статье разберём, откуда берётся это пространство, почему отрицательные отступы не позволяют надёжно от него избавиться и как с помощью text-box-trim, text-box-edge и сокращённого свойства text-box обрезать его у заголовков и кнопок. В конце приведён вариант резервного решения для старых браузеров.
Ключевые выводы
- Лишнее пространство вокруг текста складывается из вертикального места, которое шрифт резервирует под самые высокие и самые глубокие глифы, и интерлиньяжа, который добавляет или отнимает
line-height. CSS делит его поровну над и под каждой строкой. text-box-trimопределяет, какие края обрезать (none,trim-start,trim-end,trim-both), аtext-box-edge— до какой линии обрезается каждый край.text-box: trim-both cap alphabeticобрезает верх до высоты прописных букв, а низ — до базовой линии, что соответствует тому, как в большинстве макетов измеряются отступы.text-box-edgeни на что не влияет, если дляtext-box-trimне задано значение, отличное отnone.text-box-trimне наследуется, поэтому объявляйте его для каждого элемента, который нужно обрезать, а не дляbody.
Симптом: зазор, который не объясняется внутренними отступами
У заголовка с нулевыми padding и margin и плотным line-height всё равно остаётся пустое пространство над прописными буквами и под базовой линией. DevTools показывает, что область содержимого (content box) выше видимых букв, и ничто в ваших стилях этой разницы не объясняет.
Обычная «заплатка» — отрицательный margin, подобранный методом проб и ошибок:
h1 {
line-height: 1.1;
/* Tuned by eye for one font; wrong for any other */
margin-block: -0.2em -0.15em;
}
Эти значения приведены лишь для иллюстрации. Они ни из чего не выводятся — в этом-то и проблема.
Откуда берётся лишнее пространство над текстом и под ним?
У лишнего пространства над текстом и под ним две причины — метрики шрифта и полуинтерлиньяж, и обе относятся к самому тексту, а не к блочной модели.
Во-первых, шрифт отводит вертикальное пространство под все свои глифы — от высоких прописных букв до хвостиков таких букв, как g и y. Объём этого пространства различается от гарнитуры к гарнитуре, как отмечается в справочнике MDN по text-box-trim, поэтому при одном и том же font-size строчный бокс (line box) получается выше или ниже в зависимости от шрифта.
Во-вторых, line-height добавляет интерлиньяж. Спецификация CSS 2.1 об интерлиньяже и полуинтерлиньяже определяет интерлиньяж как разницу между line-height и суммой верхнего и нижнего выносов шрифта (ascent и descent). Половина этой величины добавляется над глифами, половина — под ними. У многих шрифтов сумма ascent и descent превышает 1.1em, поэтому при line-height: 1.1 полуинтерлиньяж часто оказывается небольшим или даже отрицательным. В любом случае пустое пространство, которое оставляют собственные метрики шрифта над прописными буквами и под базовой линией, никуда не девается.
Каждая гарнитура резервирует разный объём вертикального пространства, поэтому отрицательный отступ, подобранный под один шрифт, не подходит для другого. Это касается и резервного шрифта, который отображается до загрузки веб-шрифта, — та же проблема вызывает и сдвиги макета, связанные со шрифтами. Если воспроизвести запись сессии, в которой веб-шрифт загружается с опозданием, можно увидеть кадр, где шрифт подменяется и заголовок с «магическим» отступом прыгает.
Как убрать зазор с помощью text-box-trim?
text-box-trim определяет, какие края текстового блока обрезаются, а text-box-edge — до какой линии обрезается каждый край. text-box-trim принимает четыре ключевых слова:
none: начальное значение. Ничего не обрезается.trim-start: обрезает верхний (over) край.trim-end: обрезает нижний (under) край.trim-both: обрезает оба края.
Вот тот же заголовок, где хак с отступом заменён:
h1 {
line-height: 1.1;
text-box-trim: trim-both;
text-box-edge: cap alphabetic;
}
После применения text-box-trim верхний край блока совпадает с верхом прописных букв, а нижний — с базовой линией. Лишнее пространство исчезает для любого шрифта, потому что браузер берёт нужные позиции из самого шрифта, а не из ваших догадок.
Сокращённое свойство text-box объединяет оба свойства в одном объявлении. Эти два правила эквивалентны:
h1 {
text-box: trim-both cap alphabetic;
}
/* Same result: an omitted trim keyword means trim-both */
h1 {
text-box: cap alphabetic;
}
Какие значения text-box-edge важны?
Для горизонтального текста почти все случаи покрывают две пары значений: cap alphabetic и ex alphabetic. text-box-edge принимает два ключевых слова: первое задаёт верхний край, второе — нижний.
| Ключевое слово | Край | До чего обрезает |
|---|---|---|
text | верхний или нижний | до текстового края шрифта (именно в это значение разрешается auto по умолчанию) |
cap | только верхний | до верха прописных букв |
ex | только верхний | до высоты строчных (x-height, верх коротких строчных букв) |
alphabetic | только нижний | до алфавитной базовой линии |
cap alphabetic соответствует тому, как дизайнеры обычно измеряют пространство вокруг заголовка или подписи: от высоты прописных до базовой линии. Используйте ex alphabetic, если текст набран в основном строчными буквами и визуальным верхом служит x-height:
.lowercase-label {
text-box: trim-both ex alphabetic;
}
На трёх правилах спотыкается большинство:
text-box-edgeсамо по себе ни на что не влияет. Ничего не обрезается, пока дляtext-box-trimне задано значение, отличное отnone.- В сокращённом свойстве
text-boxпропущенное ключевое слово обрезки означаетtrim-both, а пропущенный край —auto. Ключевое словоnormalэквивалентноnone auto. - Ни
text-box-trim, ниtext-box-edgeне наследуются. Если задать их дляbody, заголовки и кнопки внутри него обрезаны не будут. Объявляйте свойства для каждого элемента или в базовых стилях каждого компонента.
Центрирование подписи на кнопке с помощью text-box
На кнопке с одинаковыми внутренними отступами сверху и снизу подпись часто выглядит смещённой. Отступы равны, а вот внутреннее пространство шрифта над прописными буквами и под базовой линией — нет, и эта разница воспринимается как дополнительный отступ с одной стороны.
.button {
padding: 0.75rem 1.25rem;
}
Если обрезать блок подписи до высоты прописных и базовой линии, единственным пространством между текстом и краем кнопки останется padding:
.button--trimmed {
padding: 0.75rem 1.25rem;
text-box: trim-both cap alphabetic;
}
С подписью вроде «Submit» пространство над прописными буквами теперь выглядит так же, как пространство под базовой линией. Спецификация CSS Inline Layout допускает применение text-box-trim к блочным контейнерам, многоколоночным контейнерам и строчным боксам, однако браузеры ведут себя по-разному. Согласно намерению Mozilla выпустить функцию (intent to ship), Firefox и Safari обрезают строчные боксы, а Chromium — нет. Кроме того, обрезка не действует на flex- и grid-контейнеры, поэтому задайте кнопке display: inline-block или примените обрезку к элементу подписи внутри неё. Поскольку нижний край обрезается до базовой линии, нижние выносные элементы букв g, p и y заходят в область padding. Это ожидаемый с точки зрения типографики результат, а не ошибка.
Поддержка браузерами и резервное решение
MDN относит text-box к Baseline 2026 (newly available с августа 2026 года) и отмечает, что свойство может не работать на старых устройствах и в старых браузерах. Браузеры без поддержки игнорируют объявление и отображают текст с обычными шрифтовыми интервалами. Резервный вариант — макет без обрезки: он не сломан, просто менее точен. Если дизайн зависит от прежних компенсирующих отступов, оставьте их только для таких браузеров с помощью запроса поддержки функций @supports:
h1 {
text-box: trim-both cap alphabetic;
}
@supports not (text-box: trim-both cap alphabetic) {
h1 {
/* Old per-font patch, kept only where text-box is unsupported */
margin-block: -0.2em -0.15em;
}
}
Заключение
Зазор вокруг текста — это метрики шрифта плюс полуинтерлиньяж. Отрицательный отступ лишь маскирует его, да и то только для одной гарнитуры. Замените такие отступы на text-box: trim-both cap alphabetic в каждом компоненте заголовка и подписи, перенесите устаревшие отступы в блок @supports not и проверьте результат как с веб-шрифтом, так и с резервным шрифтом.
Часто задаваемые вопросы
Меняет ли text-box-trim расстояние между строками в многострочном абзаце?
Нет. В блочном контейнере text-box-trim затрагивает только верх первой строки и низ последней. Полуинтерлиньяж между переносимыми строками остаётся прежним, поэтому line-height по-прежнему управляет интервалами внутри абзаца. Смещаются только внешние края блока — до высоты прописных и базовой линии.
Почему бы просто не задать line-height: 1, чтобы убрать лишнее пространство?
line-height: 1 меняет только интерлиньяж. Собственное пространство шрифта над прописными буквами и под базовой линией остаётся, поэтому края блока всё равно не совпадают с высотой прописных и базовой линией. К тому же это уплотняет расстояние между переносимыми строками. text-box-trim обрезает по метрикам шрифта только внешние края, оставляя line-height свободным для управления удобочитаемостью.
Влияет ли обрезка с помощью text-box на расположение соседних элементов?
Да. text-box-trim смещает края содержимого элемента до выбранных метрик, поэтому элемент занимает меньше места по блочной оси. Отступы, промежутки (gap) во flex и grid, а также соседние элементы отсчитываются от обрезанного края, а не от зарезервированного шрифтом пространства. Именно поэтому после обрезки токены отступов визуально соответствуют макету — и поэтому важно убрать старые отрицательные отступы.
Как определить поддержку text-box в JavaScript?
Вызовите CSS.supports('text-box', 'trim-both cap alphabetic'). Метод возвращает true в браузерах, которые принимают это объявление, и false в остальных. Он выполняет ту же проверку, что и правило @supports в CSS, поэтому с его помощью можно во время выполнения решать, применять ли компенсирующие отступы, или логировать, какой вариант отрисовки получает пользователь.
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Star on GitHub12k