Чтобы сохранить отступы с обоих концов каждой строки перенесённой подсветки, примените box-decoration-break: clone к строчному элементу вместе с фоном и отступами. Добавьте объявление с префиксом WebKit для Safari. В MDN объясняется декорирование фрагментов.

Это руководство предназначено для тех, кто редактирует веб-страницу на Mac и хочет, чтобы выделенная фраза естественно переносилась внутри заголовка или абзаца. Задача — создать для каждой получившейся строки собственный фон с отступами, оставив перенос строк на усмотрение браузера.

Почему отступы исчезают в месте переноса выделения?

Начальное значение box-decoration-break — slice. Когда строчный блок переносится на следующую строку, это значение рассматривает его оформление как единый непрерывный блок, разделённый на фрагменты. Отступы не добавляются на границах переноса. При значении clone каждый фрагмент получает собственные отступы, рамку и оформление фона. W3C определяет оба способа фрагментации.

Этим объясняется распространённый результат: увеличение горизонтальных отступов делает свободнее начало и конец всей фразы, но края промежуточных строк всё ещё выглядят тесно. Отсутствует настройка, определяющая поведение на границах переноса; одно лишь увеличение отступов её не меняет.

Оставьте выделение строчным блоком. Фон блочного элемента оформляет содержащий его прямоугольник, а строчное выделение следует за потоком текста. MDN описывает различия в размерах и интервалах блочных, строчных и строчно-блочных элементов. См. руководство MDN по блочной модели.

Создайте полный пример на Mac

В редакторе кода создайте текстовый файл с именем wrapped-highlight.html, вставьте в него пример ниже и сохраните файл. Откройте его в браузере на компьютере. Устанавливать пакеты, подключать внешнюю таблицу стилей или использовать JavaScript не требуется.

Заголовок с фиктивным текстом изображает простое вступление страницы. Один элемент span охватывает всю оформляемую фразу. WHATWG определяет элемент span как универсальный текстовый контейнер без собственного смысла, поэтому он подходит для такого чисто визуального объединения. Прочитайте определение span в стандарте HTML.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Wrapped highlight example</title>
  <style>
    * {
      box-sizing: border-box;
    }

    body {
      margin: 0;
      padding: 2rem;
      background: #ffffff;
      color: #202020;
      font-family: system-ui, sans-serif;
    }

    .sample {
      max-width: 26rem;
      margin: 0 auto;
    }

    .sample-title {
      margin: 0;
      font-size: 2rem;
      font-weight: 600;
      line-height: 1.65;
    }

    .highlight {
      display: inline;
      background-color: #ffe6a6;
      padding: 0.08em 0.3em;
      border-radius: 0.15em;
      -webkit-box-decoration-break: clone;
      box-decoration-break: clone;
    }
  </style>
</head>
<body>
  <main class="sample">
    <h1 class="sample-title"><span class="highlight">Amber tiles and silver circles arranged across a sample page</span></h1>
  </main>
</body>
</html>

Сужайте окно браузера, пока заголовок не перенесётся, а затем снова расширьте его. Проверьте начало и конец каждой выделенной строки. В результате вокруг каждой строки должен появиться отдельный фрагмент фона с отступами, и такое оформление должно сохраняться при изменении переносов. В примерах MDN используются те же объявления с префиксом и без него. См. документацию по синтаксису и примерам.

Размеры в этом примере условны и выбраны для иллюстрации. Сначала измените горизонтальный отступ 0.3em, если края выглядят слишком тесными или просторными. Вертикальный отступ 0.08em меняйте отдельно. Во время настройки любого из значений проверяйте переносы.

Чтобы сравнить поведение, временно замените оба объявления оформления с clone на slice, сохраните файл и перезагрузите страницу. Затем верните обоим значения clone. Измените оба значения, чтобы результат сравнения не зависел от того, какое объявление распознаёт ваш браузер.

Какие особенности поддержки браузерами важны на Mac?

Оставьте в примере оба объявления. Согласно актуальным данным о совместимости MDN, стандартное свойство поддерживается начиная с Chrome 130 и Firefox 32. В Safari свойство поддерживается с префиксом -webkit-, причём эта реализация работает только со строчными элементами. Изучите данные MDN о совместимости браузеров.

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

Проверьте файл в браузерах на Mac, которые важны для вашей страницы. Используйте узкое и широкое окно, затем увеличьте размер текста страницы и повторите проверку. Считайте количество строк переменным: условие приёмки — единообразные отступы у фрагментов, которые создаёт каждый браузер.

Если среда не распознаёт ни одно из объявлений, улучшение с копированием оформления для каждой строки будет недоступно. Сделайте так, чтобы текст и фон оставались читаемыми, или выберите блочный элемент с отступами, если требованиям дизайна соответствует единый прямоугольный фон. Это изменит внешний вид, поэтому такое решение должно быть осознанным.

Как избежать наложения фонов и неудобных переносов?

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

Одновременно настройте line-height заголовка и вертикальные отступы выделения. В примере намеренно задано просторное исходное значение 1.65. Если интервалы кажутся слишком большими, постепенно уменьшайте его, каждый раз проверяя самую узкую вёрстку. Универсального значения межстрочного интервала для всех шрифтов и вариантов оформления нет.

Перед тем как менять другие CSS-свойства, используйте эту последовательность для диагностики причины:

Что вы видите Что проверить в первую очередь Следующее действие
Отступы есть только по краям всей фразы Поведение оформления Примените оба объявления clone к строчному элементу с выделением.
Один большой прямоугольник фона Какой элемент задаёт фон Поместите фон и отступы во внутренний строчный элемент span.
Выделенные строки соприкасаются по вертикали Вертикальные отступы и межстрочный интервал родителя Уменьшите вертикальные отступы или увеличьте межстрочный интервал.
Длинная метка выходит за границы контейнера Возможности переноса Рассмотрите приведённое ниже необязательное правило для длинных фрагментов без пробелов.
Только в Safari нет нужных отступов по краям Объявление с префиксом Убедитесь, что -webkit-box-decoration-break: clone осталось в таблице стилей.

Для фиктивной метки без возможных мест переноса, например AmberTileSequenceAmberTileSequence, можно добавить overflow-wrap: anywhere в .sample-title. Это необязательный фрагмент CSS, который нужно добавить в существующее правило; остальная часть примера не меняется.

/* Optional addition inside the existing .sample-title rule */
overflow-wrap: anywhere;

Это позволяет переносить строку без возможных точек переноса, когда иначе она выйдет за границы контейнера, и при этом не добавляет дефис. Правило определяет возможности переноса; отступы оно не создаёт. Для обычных фраз с пробелами оно может не понадобиться. MDN описывает условия применения overflow-wrap.

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

Сохраняйте естественный поток текста и границы формирования глифов

Используйте один контейнер для всей нужной фразы, а не создавайте отдельные контейнеры для строк, видимых сейчас. Так разметка не будет зависеть от текущей ширины окна и выбранного шрифта.

Не разбивайте слово на отдельные символы в элементах span с отступами, чтобы имитировать этот эффект. Спецификация CSS Text требует, чтобы формирование глифов разбивалось на границах строчных элементов, если соседние типографические единицы символов разделены ненулевыми отступами, рамками или полями вдоль строчной оси. Поэтому граница с отступом внутри слова может повлиять на формирование глифов. См. правила W3C о формировании глифов на границах элементов.

В этом заголовке разместите контейнер на границах фразы, оставив внутренний текст непрерывным. Это позволит не добавлять новые границы с отступами внутри фразы. Это не гарантирует одинаковые глифы или переносы строк в разных браузерах и шрифтах; проверьте фактическое отображение, которое собираетесь использовать.

Что делать, если в проекте используется Tailwind CSS?

В существующем проекте Tailwind добавьте box-decoration-clone к строчному элементу, которому уже заданы фон и отступы выделения. В актуальной документации Tailwind эта утилита соответствует box-decoration-break: clone. Утилита box-decoration-slice выбирает другое поведение. См. утилиты Tailwind для box-decoration-break.

Сохраните требования к браузерам из примера на обычном CSS: если нужна поддержка Safari, проверьте сгенерированную таблицу стилей на наличие объявления с префиксом и при его отсутствии добавьте его через пользовательский CSS проекта. Утилита задаёт поведение оформления, но не устраняет ограничения реализации браузера.

Добавлять Tailwind только ради этого эффекта не нужно. Полный локальный пример уже содержит необходимый CSS.

Можно ли задать такие же отступы пользовательскому выделению?

Диапазон CSS Custom Highlight API, оформленный с помощью ::highlight(), имеет другие возможности, чем стилизованный строчный элемент. MDN перечисляет разрешённые свойства, включая цвет текста, цвет фона и оформление текста. Отступы и box-decoration-break в этот набор не входят. Прочитайте описание ограничений оформления пользовательского выделения.

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

Для заголовка страницы или фразы с переносами используйте один строчный контейнер, задайте ему фон и отступы и примените оба объявления clone. В завершение проверьте разные ширины и вертикальные интервалы. Это покажет, работает ли выделение при фактическом потоке текста, а не только при удобном размере окна.

Источники