Строки текста одинаковой ширины

Веб-функции: text-fit text-wrap: balance text-box

Блокировки в стиле плаката, где каждая строка масштабируется так, чтобы охватить всю ширину контейнера, могут создавать визуально яркие заголовки. При использовании text-fit браузер масштабирует каждую строку во время макета, поэтому она остается правильной при изменении размера, копировании изменений и загрузке шрифта.

Если в контейнере только одна строка (например, заголовок или цитата), примените text-fit непосредственно к этому элементу. В этом руководстве рассматриваются многострочные блоки.

Базовый вариант

Для принудительных строк:

  • Каждую строку нужно заключить в тег <span> с атрибутом display: block.
  • Примените white-space: nowrap к каждой принудительной строке <span>.

Рекомендации по реализации:

  • Используйте text-fit: grow per-line-all <percentage> в самом заголовке.
  • Используйте per-line-all, а не per-line. per-line пропускает последнюю строку и любую строку, заканчивающуюся принудительным разрывом, поэтому при одном блоке на строку ничего не масштабируется.
  • grow с shrink. Задайте для базового значения font-size максимум или минимум в зависимости от того, что лучше подходит в качестве резервного значения или проще рассчитывается, и установите для text-fit значение shrink или grow соответственно. Если у вас нет причин использовать shrink, лучше выбрать grow и установить минимальное значение font-size, так как в большинстве случаев это безопаснее.
  • Всегда ограничивайте рост или сокращение процентом (например, 300%) в качестве меры предосторожности.
  • Контейнеру нужен определенный встроенный размер. text-fit никогда не меняет внутренний размер, поэтому не влияет на ширину fit-content/max-content или элементы flex/grid, размер которых зависит от контента.
  • Обрежьте интерлиньяж над первой и под последней строкой. Подробнее о точном выравнивании текста…
  • Значение line-height должно быть небольшим, не более 1, иначе интервалы между строками с разным размером шрифта будут слишком большими.
  • ВАЖНО! Обратите внимание, что вычисленное значение font-size не меняется, поэтому интервал em не масштабируется.
  • Чтобы избежать случайного выделения висячих строк, используйте text-wrap: balance или text-wrap: pretty, если есть свободные строки.

Использование пробелов.

Если все строки принудительные, это позволяет лучше контролировать интервалы:

  • Примените text-box: trim-both cap alphabetic к каждому блоку строки, чтобы его поле охватывало его собственные глифы. Обрезает данные, используя масштабированные показатели. Подробнее о точном выравнивании текста…
  • Для создания интервалов между строками используйте Flexbox или Grid + gap в заголовке, а не line-height. В этом случае интервалы будут одинаковыми, а не увеличивающимися с размером шрифта каждой строки.

Если некоторые строки пустые, не используйте text-box: это свойство обрезает только первую и последнюю строки, поэтому внешние строки будут прилегать к глифам, а внутренние пробелы сохранят свой интерлиньяж. Пусть line-height управляет всеми интервалами.

Оформление

  • Логотипы с текстом выглядят лучше всего, когда размеры шрифтов в разных строках значительно отличаются. Не создавайте логотипы из текста с преимущественно одинаковыми строками, так как это приведет к тому, что размеры шрифтов не будут ни одинаковыми, ни достаточно разными, что нарушит принцип дизайна контраст. Чтобы этого избежать, используйте короткие строки: поместите слова, которые нужно выделить, в один блок, а остальные – в другой. Это особенно важно при сочетании с text-wrap: balance.
  • Для текстов на языках с латинским алфавитом рекомендуется использовать это значение вместе с text-transform: uppercase, поскольку верхние и нижние выносные элементы могут создавать замкнутые пространства и/или перекрывать соседние строки, что выглядит не очень эстетично.
  • Если вы хотите использовать короткие строки, выбирайте слова, которые подчеркнут смысл сообщения.
  • Ограничение. Увеличение текста также увеличит его оптический вес, а его штрихи будут восприниматься как более сильные. В настоящее время нет способа компенсировать это, например, уменьшив font-weight для более крупного текста, поскольку нет единицы измерения, которую можно было бы использовать в расчетах, так как масштабирование не влияет на единицы измерения, связанные со шрифтом, такие как em.

Резервные стратегии

Для text-box

Для text-box не требуется отдельный резервный вариант: используйте маленький значок line-height и в фиксированных логотипах. В text-box оно не работает, а там, где оно не поддерживается, сохраняет небольшие интервалы, которые масштабируются в зависимости от размера шрифта каждой строки.

Для text-wrap: balance

Для text-fit

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

@supports not (text-fit: grow) {
  .lockup > span {
    /* Shrink-wrap each line so its width is the text width */
    width: fit-content;
    /* --text-fit-scale is measured by the script; the cap mirrors the text-fit percentage */
    font-size: min(var(--text-fit-scale, 1) * 1em, 300%);
  }
}
if (!CSS.supports('text-fit', 'grow per-line-all')) {
  const fit = lockup => {
    const lines = [...lockup.querySelectorAll(':scope > span')];
    // Unscale first: on a refit, offsetWidth would otherwise include the previous scale
    for (const line of lines) line.style.removeProperty('--text-fit-scale');
    // MANDATORY: all reads, then all writes. Interleaving them (e.g. reading
    // lockup.clientWidth inside the write loop) forces one reflow per line.
    const scales = lines.map(line => lockup.clientWidth / line.offsetWidth);
    lines.forEach((line, i) => line.style.setProperty('--text-fit-scale', scales[i]));
  };
  // Refit on resize and font load
  for (const lockup of document.querySelectorAll('.lockup')) {
    new ResizeObserver(() => fit(lockup)).observe(lockup);
  }
}

Для свободных строк нет надежного резервного варианта (разрывы строк неизвестны до макета): прогрессивное улучшение до сбалансированного заголовка с гибким базовым размером, например clamp(2rem, 1rem + 5cqi, 5rem). В смешанной компоновке скрипт выше по-прежнему подходит для принудительных строк. Блок переноса измеряется по ширине контейнера, поэтому он сохраняет масштаб 1 и получает только базовый размер жидкости.

Если подгонка текста критически важна, используйте библиотеку JS (например, fitty), которая загружается только в том случае, если text-fit не поддерживается.