Разрушение блоков с помощью фрагментации CSS
Опубликовано: 2022-03-10В этой статье я познакомлю вас со спецификацией фрагментации CSS. Вы, возможно, никогда не слышали об этом, однако, если вы когда-либо создавали таблицу стилей печати и хотели контролировать, где содержимое разрывается между страницами, или макет с несколькими столбцами и хотели, чтобы фигура не разрывалась между столбцами, вы столкнулись с этим.
Я обнаружил, что довольно часто люди сообщают о проблемах с multicol, которые на самом деле связаны с поддержкой браузерами фрагментации. После краткого изложения свойств, содержащихся в этой спецификации, я объясню текущее состояние поддержки браузеров и некоторые вещи, которые вы можете сделать, чтобы заставить их работать так же хорошо, как в ваших многоцветных проектах и проектах печати.
Что такое фрагментация?
Фрагментация в CSS описывает процесс, посредством которого контент разбивается на разные блоки. В настоящее время у нас есть два места, в которых мы можем столкнуться с фрагментацией в Интернете: когда мы печатаем документ и если мы используем макет с несколькими столбцами. Эти две вещи по сути одинаковы. Когда вы печатаете (или сохраняете в формате PDF) веб-страницу, содержимое фрагментируется на столько страниц, сколько необходимо для печати вашего содержимого.
При использовании multicol содержимое фрагментируется на столбцы. Каждое поле столбца похоже на страницу в постраничном контексте. Если вы думаете о наборе столбцов как о наборе страниц, это может быть полезным способом подумать о множестве столбцов и о том, как в нем работает фрагментация.
Если вы посмотрите на спецификацию фрагментации CSS, вы увидите упомянутый третий фрагментированный контекст — это регионы. Поскольку в настоящее время нет пригодных для использования реализаций регионов, мы не будем рассматривать их в этой статье, а вместо этого рассмотрим два контекста, с которыми вы можете столкнуться в своей работе.
Блочные и встроенные блоки
В этой статье я буду много упоминать блок-боксы. Каждый элемент вашей страницы имеет поле. Некоторые из этих полей расположены в виде блоков: абзацы, элементы списка, заголовки. Говорят, что они участвуют в контексте форматирования блока. Другие являются встроенными, например слова в абзаце, интервалы и элементы привязки. Они участвуют во встроенном контексте форматирования. Проще говоря, когда я говорю о блочном блоке, я имею в виду блоки вокруг таких вещей, как абзацы. Имея дело с фрагментацией, важно знать, с каким типом ящика вы имеете дело.
Для получения дополнительной информации о блочном и встроенном макете см. статью MDN «Блочный и встроенный макет в обычном потоке». Это одна из тех вещей, которые мы, вероятно, все понимаем на каком-то уровне, но, возможно, раньше не сталкивались с терминологией.
Контроль перерывов
Независимо от того, создаете ли вы таблицу стилей печати, используете определенный пользовательский агент печати для создания PDF-файла или используете многоцветность, вы иногда сталкиваетесь с проблемами, которые выглядят примерно так.
В приведенном ниже примере с несколькими столбцами у меня есть некоторый контент, который я отображаю в виде трех столбцов. В середине содержимого находится выделенная область, разбитая на две колонки. Я не хочу такого поведения — я бы хотел, чтобы коробка оставалась вместе.
Чтобы исправить это, я добавляю в поле свойство break-inside: avoid
. Свойство break-inside
управляет разрывами внутри элементов, когда они находятся в фрагментированном контексте. В браузере, который поддерживает это свойство, поле теперь останется в одном из столбцов. Однако столбцы будут выглядеть менее сбалансированными, что, как правило, лучше, чем в конечном итоге с разделением рамки между столбцами.
Свойство break-inside
— это одно из свойств, подробно описанных в спецификации фрагментации. Полный список свойств выглядит следующим образом:
-
break-before
-
break-after
-
break-inside
-
orphans
-
widows
-
box-decoration-break
Давайте посмотрим, как они должны работать, прежде чем мы перейдем к тому, что на самом деле происходит в браузерах.
Свойства break-before
и break-after
Есть два свойства, которые управляют разрывами между блоками уровня блока: break-before
и break-after
. Если у вас есть h2
, за которым следуют два абзаца <p>
, у вас есть три блочных блока, и вы должны использовать эти свойства для управления разрывами между заголовком и первым абзацем или между двумя абзацами.
Свойства используются в селекторах, которые нацелены на элемент, который вы хотите разбить до или после.
Например, вы можете захотеть, чтобы ваша таблица стилей печати разбивалась на новую страницу каждый раз, когда появляется заголовок 2-го уровня. В этом случае вы должны использовать break-before: page
для элемента h2
. Это контролирует фрагментацию и гарантирует, что перед блоком элемента h2
всегда есть разрыв.
h2 { break-before: page; }
Другим распространенным требованием является предотвращение того, чтобы заголовки оказывались последними на странице или в столбце. В этом случае вы можете использовать break-after
со значением avoid
. Это должно предотвратить разрыв сразу после блока элемента:
h1, h2, h3, h4 { break-after: avoid; }
Фрагменты внутри фрагментов
Возможно, у вас может быть фрагментированный элемент, вложенный в другой. Например, наличие multicol внутри чего-то, что выгружается. В этом случае вы можете захотеть контролировать разрывы для страниц, но не для столбцов, или наоборот. Вот почему у нас есть такие значения, как page
, которые всегда вызывают разрыв до или после элемента, но только тогда, когда фрагмент является страницей. Или avoid-page
, которая позволит избежать разрыва до или после элемента только для постраничных контекстов.
То же самое относится и к столбцам. Если вы используете column
значений, это всегда приводит к разрыву до или после этого элемента, но только для контекстов с несколькими столбцами. Значение avoid-column
предотвратило бы разрыв в контекстах с несколькими столбцами.
В спецификации уровня 4 always
есть значение, указывающее, что вы хотите разбить все — страницу или столбец. Однако, как недавнее дополнение к спецификации, в настоящее время оно нам не нужно.
Дополнительные значения для выгружаемых носителей
Если вы создаете книгу или журнал, у вас есть левая и правая страницы. Возможно, вы захотите контролировать разбиение, чтобы принудительно разместить что-либо на левой или правой странице разворота. Следовательно, при использовании следующего будет вставлен один или два разрыва страницы перед h2
, чтобы гарантировать, что он отформатирован как правильная страница.
h2 { break-before: right; }
Существуют также значения лицевой и оборотной сторон, которые относятся к последовательности страниц , поскольку книги, написанные на вертикальном языке или языке справа налево, имеют другую последовательность страниц, чем книги, написанные на английском языке. Я не буду подробно рассматривать эти значения в этой статье, так как на этот раз меня в первую очередь интересует то, что возможно из браузера.
break-inside
Мы уже видели пример свойства break-inside
. Это свойство управляет разрывом внутри блочных блоков, например, внутри абзаца, заголовка или блока div.
Вещи, которые вы, возможно, не хотите разбивать, могут включать в себя рамку, как описано выше: рисунки, на которых вы не хотите, чтобы заголовок был отделен от изображения, таблицы, списки и т. д. Добавьте break-inside: avoid
к любому контейнеру, который вы не хотите ломать в любом контексте фрагментации. Если вы хотите избежать разрывов только между столбцами, используйте break-inside: avoid-column
и между страницами break-inside: avoid-page
.
orphans
и widows
Недвижимость
Свойства orphans
и widows
определяют, сколько строк должно оставаться до или после разрыва (вызванного столбцом или новой страницей). Например, если я хочу, чтобы в конце столбца не оставалось ни одной строки, я бы использовал свойство orphans
, как в типографике, сирота — это первая строка абзаца, которая появляется одна внизу страницы с остальная часть абзаца разбита на другую страницу. Свойство должно быть добавлено к тому же элементу, который фрагментируется (в нашем случае — контейнеру multicol).
.container { column-count: 3; orphans: 2; }
Чтобы контролировать, сколько строк должно быть вверху столбца или страницы после разрыва, используйте widows
:
.container { column-count: 3; widows: 2; }
Эти свойства относятся к разрывам между встроенными блоками, такими как строки слов внутри абзаца. Поэтому они не помогают в ситуации, когда заголовок или другой блочный элемент находится в одиночестве внизу столбца или страницы, для этого вам понадобятся свойства разрыва, рассмотренные выше.
Украшение коробки
Последнее свойство, которое может представлять интерес, — это свойство box-decoration-break
. Это контролирует ситуацию, когда у вас есть поле с разорванной границей между двумя столбцами или страницами. Вы хотите, чтобы граница была разрезана пополам? Или вы хотите, чтобы каждая из двух половинок коробки была полностью обернута рамкой?
Первый сценарий используется по умолчанию и выглядит так, как если бы вы установили свойство box-decoration-break
на slice
блока.
.box { box-decoration-break: slice; }
Чтобы получить второе поведение, установите box-decoration-break
значение clone.
.box { box-decoration-break: clone; }
Браузерная поддержка фрагментации
Теперь мы подошли к причине, по которой у меня нет кучи приведенных выше примеров CodePen, чтобы продемонстрировать вам все это, и к основной причине написания этой статьи. Браузерная поддержка этих свойств невелика.
Если вы работаете в Paged Media с определенным пользовательским агентом, таким как Prince, вы можете наслаждаться действительно хорошей поддержкой фрагментации и, вероятно, сочтете эти свойства очень полезными. Если вы работаете с веб-браузером, либо в многоцветном режиме, создавая таблицы стилей для печати, либо используете что-то вроде Headless Chrome для создания PDF-файлов, поддержка несколько неоднородна. Вы обнаружите, что браузер с лучшей поддержкой — это Edge, пока он все равно не перейдет на Chromium!
Can I Use не слишком полезен для объяснения поддержки из-за смешивания свойств фрагментации с multicol, а затем наличия некоторых отдельных данных для устаревших свойств. Итак, в рамках работы, которую я выполнял для MDN по документированию свойств и их поддержки, я начал тестировать реальную поддержку браузера. Далее следует несколько советов, основанных на этом тестировании.
Устаревшие свойства и свойства с префиксами поставщиков
Я не могу идти дальше без урока истории. Если вы обнаружите, что вам действительно нужна поддержка фрагментации, вы можете найти некоторое облегчение в устаревших свойствах, которые изначально были частью CSS2 (или в некоторых существующих префиксных свойствах).
В CSS2 были свойства для управления разрывом страницы. В то время Multicol не существовало, поэтому единственным фрагментированным контекстом был постраничный контекст. Это означало, что были введены три конкретных свойства разрыва страницы:
-
page-break-before
-
page-break-after
-
page-break-inside
Они работают аналогично более общим свойствам без префикса page-
, контролируя разрывы до, после и внутри блоков. Для таблиц стилей печати вы обнаружите, что некоторые старые браузеры, которые не поддерживают новые свойства break-
, поддерживают эти свойства префикса страницы. Свойства рассматриваются как псевдонимы для новых свойств.
В рабочем черновике спецификации multicol от 2005 года подробно описаны свойства разрыва для multicol — с использованием свойств с префиксом column-
(т. е. column-break-before
, column-break-after
и column-break-inside
). К 2009 году они исчезли, и черновик был в спецификации multicol для свойств разрыва без префикса, которые в конечном итоге попали в спецификацию фрагментации CSS.
Однако некоторые свойства столбца с префиксом поставщика были реализованы на основе этих свойств. Эти:
-
-webkit-column-break-before
-
-webkit-column-break-after
-
-webkit-column-break-inside
Поддержка фрагментации в Multicol
Следующее основано на тестировании этих функций в многоцветных контекстах. Я попытался объяснить, что возможно, но взгляните на CodePens в любом доступном браузере.
Многоцветный и break-inside
Поддержка в multicol лучше всего подходит для свойства break-inside
. Все последние версии Chrome, Firefox, Edge и Safari поддерживают break-inside: avoid
. Таким образом, вы должны обнаружить, что вы можете предотвратить разрыв блоков между столбцами при использовании multicol.
Некоторые браузеры, за исключением Firefox, поддерживают -webkit-column-break-inside
, его можно использовать со значением Avoid и avoid
разрыв блоков между столбцами, которые не поддерживают break-inside
.
Firefox поддерживает page-break-inside: avoid
использования нескольких столбцов. Следовательно, использование этого свойства предотвратит разрывы внутри полей в браузерах Firefox до Firefox 65.
Это означает, что если вы хотите предотвратить разрывы между блоками в многоцветном коде, использование следующего CSS будет охватывать как можно больше браузеров, насколько это возможно.
.box { -webkit-column-break-inside: avoid; page-break-inside: avoid; break-inside: avoid; }
Что касается значения column
, явное указание, что вы хотите избежать разрывов только между столбцами, а не страницами, работает во всех браузерах, кроме Firefox.
CodePen ниже объединяет некоторые из этих тестов в несколько столбцов, чтобы вы могли попробовать их сами.
Мультикол и break-before
Чтобы предотвратить разрывы перед элементом, вы должны иметь возможность использовать break-before: avoid
или break-before: avoid-column
. Свойство избежать не поддерживается браузером.
Edge поддерживает break-before: column
чтобы всегда принудительно устанавливать разрыв перед блоком элемента.
Safari, Chrome и Edge также поддерживают -webkit-column-break-before: always
, что приводит к разрыву перед блоком элемента. Поэтому, если вы хотите сделать разрыв перед блоком элемента, вы должны использовать:
.box { -webkit-column-break-before: always; break-before: column; }
Предотвращение разрыва перед штрафной в настоящее время является невыполнимой задачей. Вы можете поиграть с некоторыми примерами этих свойств ниже:
Мультикол и break-after
Чтобы предотвратить разрывы после элемента, чтобы он не стал последним в нижней части столбца, вы должны иметь возможность использовать break-after: avoid
и break-after: avoid-column
. Единственный браузер, поддерживающий их, — Edge.
Edge также поддерживает принудительные разрывы после элемента с помощью break-after: column
, Chrome поддерживает break-after: column
а также -webkit-column-break-after: always
.
Firefox не поддерживает break-after
или какие-либо префиксные свойства, чтобы принудительно или разрешить разрывы после блока.
Поэтому, кроме Edge, вы действительно не можете избежать разрывов после коробки. Если вы хотите принудительно их использовать, вы получите результаты в некоторых браузерах, используя следующий CSS:
.box { -webkit-break-after: always; break-after: column; }
Поддержка при печати из браузера
Независимо от того, печатаете ли вы прямо из браузера на рабочем столе или создаете PDF-файлы с помощью Chrome без заголовка или какого-либо другого решения, зависящего от технологии браузера, не имеет никакого значения. Вы зависите от поддержки браузером свойств фрагментации.
Если вы создадите таблицу стилей печати, вы обнаружите ту же поддержку свойств разрыва, что и для multicol; однако для поддержки старых браузеров вы должны удвоить свойства, чтобы использовать свойства с page-
.
Таблицы стилей печати и break-inside
В современных браузерах свойство break-inside
можно использовать для предотвращения разрывов внутри блоков, добавьте свойство page-break-inside
, чтобы добавить поддержку старых браузеров.
.box { page-break-inside: avoid; break-inside: avoid; }
Таблицы стилей печати и break-before
Чтобы сделать разрыв перед блоком, используйте break-before:page
вместе с page-break-before: always
.
.box { page-break-before: always; break-before: page; }
Чтобы избежать разрывов перед блоком, используйте break-before: avoid-page
вместе с page-break-before: avoid
.
.box { page-break-before: avoid; break-before: avoid-page; }
Существует лучшая поддержка значений page
и avoid-page
, чем мы видим для эквивалентных значений multicol. Большинство современных браузеров имеют поддержку.
Таблицы стилей печати и break-before
Чтобы сделать разрывы после блока, используйте break-after: page
вместе с page-break-after: always
.
.box { page-break-after: always; break-after: page; }
Чтобы предотвратить разрывы после блока, используйте break-after: avoid-page
вместе с page-break-after: avoid
.
.box { page-break-after: avoid; break-after: avoid-page; }
Вдовы и сироты
Свойства widows
и orphans
имеют хорошую кросс-браузерную поддержку — единственным браузером без реализации является Firefox. Я бы предложил использовать их при создании многоцветного макета или таблицы стилей печати. Если они по какой-то причине не работают, вы получите вдов и сирот, что не идеально, но и не является катастрофой. Если они действительно работают, ваша типографика будет выглядеть еще лучше.
коробка-украшение-брейк
Последнее свойство box-decoration-break
имеет поддержку multicol и print в Firefox. Safari, Chrome и другие браузеры на основе Chromium поддерживают -webkit-box-decoration-break
, но только для встроенных элементов. Таким образом, вы можете клонировать границы вокруг строк предложения, например; у них нет поддержки в контексте, который мы рассматриваем.
В CodePen ниже вы можете видеть, что проверка -webkit-box-decoration-break: clone
с запросами функций возвращает true; однако это свойство не влияет на границу поля в контексте с несколькими столбцами.
Использование фрагментации
Как видите, текущее состояние фрагментации в браузерах несколько фрагментировано! Тем не менее, есть разумная сумма, которую вы можете достичь, а там, где это не удается, результат, как правило, неоптимальный, но не катастрофический. А значит стоит попробовать.
Стоит отметить, что чрезмерное усердие с этими свойствами может привести к чему-то другому, чем вы надеялись. Если вы работаете в Интернете, а не печатаете и принудительно разрываете столбцы после каждого абзаца, то в конечном итоге у вас будет больше абзацев, чем места для столбцов, многоколонка в конечном итоге переполнится в направлении строки. У него закончатся столбцы для размещения дополнительных абзацев. Поэтому даже там, где есть поддержка, вам все равно нужно тщательно тестировать и помнить, что во многих случаях чем меньше, тем лучше.
Дополнительные ресурсы
Чтобы узнать больше о свойствах, перейдите на MDN, я недавно обновил там страницы, а также стараюсь обновлять данные совместимости браузера. Главная страница CSS-фрагментации содержит ссылки на отдельные страницы свойств, на которых есть дополнительные примеры, данные о совместимости браузеров и другая информация об использовании этих свойств.