Макет в стиле журнала для веб-страниц с регионами и исключениями CSS

Введение

Интернет – это мощная платформа для работы с текстом, а у Adobe огромный опыт в этой области. Поэтому, когда Adobe искала способы помочь продвинуть Интернет вперед, дальнейшее развитие текстовых возможностей Интернета показалось нам очевидным местом для начала. В интернете текст обычно размещается в один столбец и ориентирован вертикально. Хотя с помощью CSS можно обтекать текстом графические объекты и даже разбивать его на несколько столбцов, добиться по-настоящему журнальной верстки в интернете по-прежнему очень сложно. С помощью регионов CSS и исключений CSS Adobe стремится внедрить возможности настольных издательских систем в современные браузеры. Например, на скриншоте ниже исключения CSS используются для того, чтобы текст обтекал контур горы:

Пример исключения CSS в действии
Пример использования исключений ССЦ

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

Пример использования регионов CSS
Пример использования CSS Regions

Регионы ССЦ

Прежде чем перейти к подробному описанию регионов CSS, я хотел бы рассказать, как включить регионы в Google Chrome. После включения регионов CSS вы можете попробовать некоторые из примеров, упомянутых в этой статье, и создать свои собственные.

Как включить регионы CSS в Google Chrome

Начиная с версии 20 (а точнее, 20.0.1132.57), в Chrome можно включить поддержку регионов CSS на странице chrome://flags. Чтобы включить регионы CSS, выполните следующие действия:

  1. Откройте новое окно или вкладку в Chrome.
  2. В адресной строке введите chrome://flags.
  3. Используйте поиск по странице (Ctrl + F или Cmd + F), чтобы найти раздел Experimental Web Platform features (Экспериментальные функции веб-платформы).
  4. Нажмите на ссылку Включить.
  5. Нажмите кнопку Перезапустить внизу.

Подробнее об экспериментальных параметрах Chrome…

После перезапуска браузера вы сможете начать экспериментировать с регионами CSS.

Обзор регионов CSS

Регионы CSS позволяют автоматически размещать блок семантически размеченного текста в "контейнерах" (в настоящее время – элементах). На схеме ниже показано разделение текста (потока) и блоков (областей, в которые перетекает текст):

Контент перетекает в заданные области
Контент размещается в определенных регионах

Давайте рассмотрим реальный пример использования регионов CSS. Я не только разработчик в Adobe, но и писатель-фантаст. Я часто публикую свои работы в интернете по лицензии Creative Commons. Чтобы они работали на максимальном количестве устройств и в разных браузерах, я использую очень простой формат, похожий на этот:

Пример проекта Human Legacy без стилей
Пример проекта Human Legacy без стилей

Используя CSS Regions, я смог создать интерфейс, который не только визуально интереснее, но и гораздо более функционален, поскольку в нем легче ориентироваться и удобнее читать:

Проект "Наследие человечества" с указанием региона
Проект Human Legacy Project with Regions.

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

Проект "Наследие человечества" с регионами
Проект Human Legacy Project с регионами

Вы можете поэкспериментировать с этим прототипом (а также посмотреть исходный код) здесь. Для навигации используйте клавиши со стрелками, а чтобы показать регионы, нажмите Esc. Более ранние прототипы доступны здесь.

Создание именованного потока

CSS-код, необходимый для того, чтобы блок текста перетекал по регионам, чрезвычайно прост. В приведенном ниже фрагменте кода именованный поток article назначается элементу div с идентификатором content, а также всем элементам с классом region. В результате текст, содержащийся в элементе content, будет автоматически перетекать в любой элемент с классом region.

<!DOCTYPE html>
<html>
<head>
    <style>
    #content {
        { % mixin flow-into: article; % }
    }

    .region {
        { % mixin flow-from: article; % }
        box-sizing: border-box;
        position: absolute;
        width: 200px;
        height: 200px;
        padding: 10px;
    }

    #box-a {
        border: 1px solid red;
        top: 10px;
        left: 10px;
    }

    #box-b {
        border: 1px solid green;
        top: 210px;
        left: 210px;
    }

    #box-c {
        border: 1px solid blue;
        top: 410px;
        left: 410px;
    }
    </style>
</head>
<body>
    <div id="box-a" class="region"></div>
    <div id="box-b" class="region"></div>
    <div id="box-c" class="region"></div>
    <div id="content">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent eleifend dapibus felis, a consectetur nisl aliquam at. Aliquam quam augue, molestie a scelerisque nec, accumsan non metus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin cursus euismod nisi, a egestas sem rhoncus eget. Mauris non tortor arcu. Pellentesque in odio at leo volutpat consequat....
    </div>
</body>
</html>

Результат выглядит так:

Результат выполнения кода выше
Результат выполнения кода

Обратите внимание, что текст внутри div-контейнера content не содержит информации о том, как он должен быть представлен. Другими словами, он может оставаться полностью семантически нетронутым, даже когда он проходит через различные регионы. Кроме того, поскольку регионы являются элементами, их положение и размер задаются с помощью CSS, как и для любого другого элемента, и поэтому они полностью совместимы с принципами адаптивного дизайна. Если вы укажете, что элементы являются частью именованного потока, то текст будет автоматически перетекать из одного элемента в другой.

Объектная модель CSS

Объектная модель CSS (CSSOM) определяет API JavaScript для работы с CSS. Ниже приведен список новых API, связанных с регионами CSS:

  • document.webkitGetNamedFlows(): функция, которая возвращает коллекцию именованных потоков, доступных в документе.
  • document.webkitGetNamedFlows().namedItem("article") – функция, которая возвращает ссылку на определенный именованный поток. Аргумент соответствует названию, указанному в качестве значения свойств CSS flow-into и from-from. Чтобы получить ссылку на именованный поток, указанный в приведенном выше фрагменте кода, необходимо передать строку "article".
  • WebKitNamedFlow – объектное представление именованной льдины со следующими свойствами и функциями:
    • firstEmptyRegionIndex – целое число, указывающее на индекс первой пустой области, связанной с именованным потоком. Чтобы узнать, как получить коллекцию регионов, ознакомьтесь с разделом getRegions() ниже.
    • name – строковое значение с названием потока.
    • overset – логическое свойство, которое:
      • false, если контент именованного потока помещается в связанных регионах.
      • true, если контент не помещается и для него требуется больше регионов.
    • getContent() – функция, которая возвращает коллекцию со ссылками на узлы, входящие в именованный поток.
    • getRegions() – функция, которая возвращает коллекцию со ссылками на регионы, содержащие контент именованного потока.
    • getRegionsByContentNode(node) – функция, которая возвращает ссылку на регион, содержащий указанный узел. Это особенно полезно для поиска областей, содержащих такие элементы, как именованные якоря.
  • webkitregionoversetchange событие. Это событие активируется в WebkitNamedFlow, когда макет связанного контента меняется по любой причине (контент добавляется или удаляется, меняется размер шрифта, форма области и т. д.) и вызывает изменение свойства webkitRegionOverset области. Это событие полезно для отслеживания изменений в макете. Это указывает на то, что произошло что-то важное и макет может требовать внимания, например требуется больше регионов, некоторые регионы могут быть пустыми и т. д.
  • webkitregionfragmentchange событие. На момент редактирования не реализовано. Это событие активируется в WebkitNamedFlow, когда макет связанного контента меняется по любой причине. Оно похоже на webkitregionoversetchange, но не зависит от изменений в свойствах webkitRegionOverset. Это событие полезно для отслеживания незначительных изменений макета, которые не обязательно влияют на весь макет именованного потока, например: контент перемещается из одного региона в другой, но общий контент по-прежнему помещается во всех регионах.
  • Element.webkitRegionOverset: элементы становятся областями, когда им назначается свойство CSS flow-from. У этих элементов есть свойство webkitRegionOverset, которое указывает, выходит ли контент за пределы региона, если он является частью именованного потока. Возможные значения webkitRegionOverset:
    • overflow, если контента больше, чем может вместить область;
    • fit, если контент заканчивается до конца области;
    • "empty", если контент не достиг региона.

Одна из основных задач CSSOM – отслеживать события webkitregionoversetchange и динамически добавлять или удалять области, чтобы разместить текст разного объема. Например, если объем текста, который нужно отформатировать, непредсказуем (например, он создан пользователем), если размер окна браузера изменен или если размер шрифта изменен, может потребоваться добавить или удалить регионы, чтобы приспособиться к изменению потока. Кроме того, если вы хотите разбить контент на страницы, вам потребуется механизм для динамического изменения DOM и регионов.

В следующем фрагменте кода JavaScript показано, как использовать CSSOM для динамического добавления регионов. Обратите внимание, что в целях упрощения в нем не обрабатывается удаление регионов и не определяются их размеры и позиции.

var flow = document.webkitGetNamedFlows().namedItem("article")
flow.addEventListener("webkitregionoversetchange", onLayoutUpdate);

function onLayoutUpdate(event) {
    var flow = event.target;
    
    // The content does not fit
    if (flow.overset === true) {
    addRegion();
    } else {
    regionLayoutComplete();
    }
}

function addRegion() {
    var region = document.createElement("div");
    region.style = "flow-from: article";
    document.body.appendChild(region);
}

function regionLayoutComplete() {
    // Finish up your layout.
}

Другие демонстрации доступны на странице примеров регионов CSS.

Шаблоны страниц ССЦ

Использование CSSOM – это, пожалуй, самый мощный и гибкий способ реализации таких вещей, как разбиение на страницы и адаптивный макет, но Adobe достаточно долго работает с текстом и инструментами настольных издательских систем, чтобы знать, что дизайнеры и разработчики также захотят более простой способ получить относительно общие возможности разбиения на страницы. Поэтому мы работаем над предложением под названием "Шаблоны страниц CSS", которое позволяет полностью декларативно определять поведение разбиения на страницы.

Рассмотрим пример использования шаблонов страниц CSS. В приведенном ниже фрагменте кода показано, как с помощью CSS создать два именованных потока: article-flow и timeline-flow. Кроме того, в нем определяется третий селектор combined-articles, в котором будут содержаться оба потока. Простое включение свойства overflow-style в селектор combined-articles указывает, что контент должен автоматически разбиваться на страницы по оси X, то есть по горизонтали:

<style>
    #article {
    { % mixin flow-into: article-flow; % }
    }

    #timeline {
    { % mixin flow-into: timeline-flow; % }
    }

    #combined-articles {
    overflow-style: paged-x;
    }
</style>

Теперь, когда мы определили потоки и задали желаемое поведение при переполнении, можно создать сам шаблон страницы:

@template {
    @slot left {
    width: 35%;
    float: left;
    { % mixin flow-from: article-flow; % }
    }

    @slot time {
    width: 25%;
    float: left;
    { % mixin flow-from: timeline-flow; % }
    }

    @slot right {
    width: 35%;
    float: left;
    { % mixin flow-from: article-flow; % }
    }
}

Шаблоны страниц определяются с помощью нового синтаксиса "at". В приведенном выше фрагменте кода мы определяем три рекламных места, каждое из которых соответствует столбцу. Текст из article-flow будет размещен в левом и правом столбцах, а текст из timeline-flow – в среднем. Результат может выглядеть примерно так:

Пример шаблона страниц
Пример шаблонов страниц

Обратите внимание, что текст статьи (в левом и правом столбцах) написан на английском языке, а хронология в центре – на немецком. Кроме того, документ разбивается на страницы по горизонтали без использования кода JavaScript. Все было сделано полностью декларативно в CSS.

Шаблоны страниц CSS пока находятся на стадии предложения, но у нас есть прототип, в котором используется JavaScript-заглушка (polyfill), позволяющая экспериментировать с ними уже сейчас.

Подробную информацию о регионах CSS можно найти на сайте html.adobe.com.

Исключения CSS

Чтобы добиться настоящего журнального макета, недостаточно просто иметь возможность переносить текст по областям. Важным элементом качественной и визуально интересной настольной публикации является возможность заставить текст обтекать или находиться внутри неправильной графики и фигур. Исключения ССЦ позволяют добиться такого же качества в интернете.

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

Пример исключения CSS в действии
Пример использования исключений ССЦ

На следующем скриншоте показан обратный пример – текст, размещенный внутри многоугольников неправильной формы.

Текст, перетекающий в многоугольники неправильной формы.
Текст, перетекающий в многоугольники неправильной формы

Первым шагом к тому, чтобы текст мог обтекать произвольные фигуры или находиться внутри них, является разработка и оптимизация необходимых алгоритмов. В настоящее время Adobe работает над реализациями, которые будут добавлены непосредственно в WebKit. После оптимизации этих алгоритмов они станут основой, на которой будут построены остальные исключения CSS.

Дополнительную информацию об исключениях CSS можно найти на странице исключений CSS на сайте html.adobe.com. Более подробные сведения о работе Adobe над базовой технологией исключений CSS можно найти в записи блога Ханса Мюллера (Hans Muller) под названием Horizontal Box: Polygon Intersection for CSS Exclusions.

Состояние регионов CSS и исключений CSS (2012 г.)

Впервые я публично рассказал о регионах CSS и исключениях CSS на Adobe Developer Pod на Google I/O 2011. В то время я показывал демоверсии в нашем собственном прототипе браузера. Презентация была встречена с большим энтузиазмом, но когда зрители узнали, что ни одна из показанных мной функций пока не доступна ни в одном из основных браузеров, они были заметно разочарованы.

В этом году (2012) я снова посетил Google I/O, но на этот раз в качестве докладчика вместе с моим коллегой Винсентом Харди (Vincent Hardy) и Алексом Данило (Alex Danilo) из Google (посмотреть презентацию можно здесь). Всего через год около 80 % спецификации CSS Regions было реализовано в WebKit и уже доступно в последней версии Google Chrome (обратите внимание, что в настоящее время CSS Regions необходимо включить через chrome://flags). Предварительная поддержка CSS Regions даже появилась в Chrome для Android:

Регионы в Chrome для Android
Регионы в Chrome для Android

Кроме того, обе спецификации реализованы в предварительной версии Internet Explorer 10 и включены в план развития Firefox на 2012 год. Следующая основная версия Safari должна поддерживать большую часть спецификации CSS Regions, а последующие обновления должны включать остальное.

Ниже приведена подробная хронология развития CSS Regions и CSS Exclusions с момента нашего первого предложения в W3C в апреле 2011 года:

Прогресс по регионам и исключениям
Регион и ход исключения

Заключение

Adobe имеет огромный опыт работы с текстом, шрифтами и настольными издательскими системами в целом благодаря таким инструментам, как InDesign. Хотя интернет уже является очень мощной платформой для работы с текстом, мы хотим использовать наши знания и опыт, чтобы сделать представление текста ещё лучше. Регионы и исключения CSS позволяют сохранить семантическую структуру контента и при этом создать макет, похожий на журнальный, что делает веб-страницы более выразительными.