Перенос контента по настраиваемым контурам
Долгое время веб-дизайнеры были вынуждены создавать сайты в рамках прямоугольника. Большинство контента в интернете по-прежнему заключено в простые прямоугольные блоки, потому что попытки создать непрямоугольный макет часто заканчиваются неудачей. Но с появлением CSS Shapes в Chrome 37 все изменится. Фигуры CSS позволяют веб-дизайнерам размещать контент по произвольным контурам, например кругам, эллипсам и многоугольникам, не ограничиваясь прямоугольниками.
Формы можно задавать вручную или определять по изображениям.
Рассмотрим простой пример.
Возможно, вы были так же наивны, как и я, когда впервые разместили изображение с прозрачными частями, ожидая, что контент будет обтекать и заполнять пробелы, но были разочарованы прямоугольной формой обтекания, сохраняющейся вокруг элемента. Решить эту проблему можно с помощью CSS Shapes.
<img class="element" src="image.png" />
<p>Lorem ipsum…</p>
<style>
.element{
shape-outside: url(image.png);
shape-image-threshold: 0.5;
float: left;
}
</style>
Объявление CSS shape-outside: url(image.png) указывает браузеру, что нужно извлечь фигуру из изображения.
Свойство shape-image-threshold определяет минимальный уровень прозрачности пикселей, которые будут использоваться для создания фигуры. Значение должно быть в диапазоне от 0.0 (полностью прозрачный) до 1.0 (полностью непрозрачный). Таким образом, shape-image-threshold: 0.5 означает, что для создания формы будут использоваться только пиксели с непрозрачностью 50% и выше.
В этом случае ключевым является свойство float. Свойство shape-outside определяет форму области, вокруг которой будет обтекать контент, но без float вы не увидите эффекта формы.
У элементов есть плавающая область на стороне, противоположной значению float. Например, если элемент с изображением кофейной чашки плавает слева, то плавающая область будет создана справа от чашки. Даже если вы создадите изображение с пробелами с обеих сторон, контент будет обтекать фигуру только с противоположной стороны, указанной свойством float, слева или справа, но никогда не с обеих сторон.
В будущем, когда будут введены исключения CSS, свойство shape-outside можно будет использовать для элементов, которые не являются плавающими.
Создание фигур вручную
Помимо извлечения фигур из изображений, вы также можете кодировать их вручную. Для создания фигур можно выбрать одно из нескольких функциональных значений: circle(), ellipse(), inset() и polygon(). Каждая функция формы принимает набор координат и связана с контрольным полем, которое устанавливает систему координат. Подробнее о полях ссылок чуть позже.
Функция circle()
Полная запись значения для круга выглядит так: circle(r at cx cy), где r – радиус круга, а cx и cy – координаты центра круга по осям X и Y. Координаты центра круга указывать необязательно. Если вы не укажете их, по умолчанию будет использоваться центр элемента (пересечение его диагоналей).
.element{
shape-outside: circle(50%);
width: 300px;
height: 300px;
float: left;
}
В примере выше контент будет обтекать круглый контур. Единственный аргумент 50% задает радиус окружности, который в данном случае равен половине ширины или высоты элемента. Изменение размеров элемента повлияет на радиус круга. Это простой пример того, как фигуры CSS могут быть адаптивными.
Прежде чем двигаться дальше, небольшое отступление: важно помнить, что CSS Shapes влияют только на форму плавающей области вокруг элемента. Если у элемента есть фон, он не будет обрезан по форме. Чтобы добиться такого эффекта, необходимо использовать свойства из маски CSS – clip-path или mask-image. Свойство clip-path очень удобно, поскольку в нем используется та же нотация, что и в CSS Shapes, поэтому вы можете повторно использовать значения.
На иллюстрациях в этом документе используется обрезка, чтобы подчеркнуть форму и помочь вам понять эффекты.
Вернемся к кругу.
Если радиус круга задан в процентах, то значение вычисляется по более сложной формуле: sqrt(width^2 + height^2) / sqrt(2). Это полезно знать, чтобы представлять, как будет выглядеть круг, если размеры элемента не равны.
В координатах функций фигур можно использовать все типы единиц CSS: px, em, rem, vw, vh и т. д. Вы можете выбрать тот, который достаточно гибок или жестк для ваших нужд.
Вы можете изменить положение круга, задав точные значения координат его центра.
.element{
shape-outside: circle(50% at 0 0);
}
Это поместит центр круга в начало системы координат. Что такое система координат? Здесь мы вводим справочные поля.
Ограничивающие рамки для фигур CSS
Опорный блок – это виртуальный блок вокруг элемента, который устанавливает систему координат, используемую для рисования и позиционирования фигуры. Начало системы координат находится в левом верхнем углу, ось X направлена вправо, а ось Y – вниз.
Помните, что shape-outside изменяет форму плавающей области, вокруг которой будет обтекать контент. Область плавающего элемента расширяется до внешних краев поля, заданного свойством margin. Она называется margin-box и используется по умолчанию, если не указана другая.
Две следующие декларации CSS дают одинаковый результат:
.element{
shape-outside: circle(50% at 0 0);
/* identical to: */
shape-outside: circle(50% at 0 0) margin-box;
}
Мы ещё не задали поле для элемента. В этом случае можно предположить, что начало системы координат и центр круга находятся в левом верхнем углу области контента элемента. Если вы зададите маржу, то:
.element{
shape-outside: circle(50% at 0 0) margin-box;
margin: 100px;
}
Начало системы координат теперь находится за пределами области контента элемента (на 100 пикселей выше и на 100 пикселей левее), как и центр круга. Вычисленное значение радиуса круга также увеличивается, чтобы учесть увеличенную поверхность системы координат, установленной ограничительной рамкой margin-box.
В декларации shape-outside можно использовать только одно поле. Каждый из них по-разному влияет на форму, и иногда это влияние едва заметно. В другой статье подробно рассказывается о том, как работают ограничивающие рамки для фигур CSS.
Функция ellipse()
Эллипсы похожи на сплющенные круги. Они задаются в формате ellipse(rx ry at cx cy), где rx и ry – радиусы эллипса по осям X и Y, а cx и cy – координаты центра эллипса.
.element{
shape-outside: ellipse(150px 300px at 50% 50%);
width: 300px;
height: 600px;
}
Процентные значения будут вычисляться на основе размеров системы координат. Никаких сложных вычислений. Координаты центра эллипса можно не указывать, и тогда они будут выведены из центра системы координат.
Радиусы по осям X и Y также можно задать с помощью ключевых слов: farthest-side дает радиус, равный расстоянию между центром эллипса и стороной ограничительной рамки, наиболее удаленной от него, а closest-side означает прямо противоположное – использовать кратчайшее расстояние между центром и стороной.
.element{
shape-outside: ellipse(closest-side farthest-side at 50% 50%);
/* identical to: */
shape-outside: ellipse(150px 300px at 50% 50%);
width: 300px;
height: 600px;
}
Это может быть полезно, если размеры элемента (или контрольного поля) могут меняться непредсказуемым образом, но вы хотите, чтобы форма эллипса адаптировалась.
Те же ключевые слова farthest-side и closest-side можно использовать для радиуса в функции формы circle().
Функция polygon()
Если кругов и эллипсов недостаточно, можно использовать функцию многоугольника. Формат: polygon(x1 y1, x2 y2, ...), где вы указываете пары координат x и y для каждой вершины (точки) многоугольника. Минимальное количество пар для указания многоугольника – три (треугольник).
.element{
shape-outside: polygon(0 0, 0 300px, 300px 600px);
width: 300px;
height: 600px;
}
Вершины размещены в системе координат. Для адаптивных многоугольников можно использовать процентные значения для некоторых или всех координат.
.element{
/* polygon responsive to font-size*/
shape-outside: polygon(0 0, 0 100%, 100% 100%);
width: 20em;
height: 40em;
}
Необязательный параметр fill-rule, импортированный из SVG, указывает браузеру, как определять внутреннюю область многоугольника в случае самопересекающихся путей или замкнутых фигур. Джони Тритхолл (Joni Trythall) подробно объясняет, как работает свойство fill-rule в SVG. Если значение не задано, по умолчанию используется fill-rule nonzero.
.element{
shape-outside: polygon(0 0, 0 100%, 100% 100%);
/* identical to: */
shape-outside: polygon(nonzero, 0 0, 0 100%, 100% 100%);
}
Функция inset()
Функция inset() позволяет создавать прямоугольные фигуры, вокруг которых можно размещать контент. Это может показаться нелогичным, учитывая первоначальную предпосылку о том, что CSS Shapes освобождает веб-контент от простых блоков. Вполне возможно. Я ещё не нашел ни одного случая использования inset(), который нельзя было бы реализовать с помощью floats и margins или с помощью polygon(). Хотя inset() дает более читаемое выражение для прямоугольных форм, чем polygon().
Полная запись функции inset shape выглядит так: inset(top right bottom left border-radius). Первые четыре аргумента позиции – это смещения внутрь от краев элемента. Последний аргумент – радиус границы прямоугольника. Это необязательное поле, поэтому вы можете оставить его пустым. Он соответствует сокращенной записи border-radius, которую вы уже используете в CSS.
.element{
shape-outside: inset(100px 100px 100px 100px);
/* yields a rectangular shape which is 100px inset on all sides */
float: left;
}
Создание фигур из контрольных полей
Если вы не укажете функцию формы для свойства shape-outside, браузер может определить форму на основе ограничительной рамки элемента. По умолчанию используется margin-box. Ничего экзотического, так уже работают числа с плавающей запятой. Но, применив этот метод, вы можете повторно использовать геометрию элемента. Рассмотрим свойство border-radius.
Если вы используете его, чтобы скруглить углы плавающего элемента, вы получите эффект обрезки, но плавающая область останется прямоугольной. Добавьте shape-outside: border-box, чтобы обернуть контур, созданный border-radius.
.element{
border-radius: 50%;
shape-outside: border-box;
float: left;
}
Конечно, вы можете использовать все контрольные поля таким образом. Вот ещё один пример использования производных фигур – смещённые цитаты.
Эффект смещенной цитаты можно получить, используя только свойства float и margin. Но для этого вам нужно разместить элемент цитаты в дереве HTML в том месте, где вы хотите его отобразить.
Вот как добиться того же эффекта смещения цитаты с дополнительной гибкостью:
.pull-quote{
shape-outside: content-box;
margin-top: 200px;
float: left;
}
Мы явно задаем контрольный блок content-box для системы координат фигуры. В этом случае объем контента в цитате определяет форму, вокруг которой будет обтекать внешний контент. Свойство margin-top используется для позиционирования (смещения) цитаты независимо от ее положения в дереве HTML.
Поля фигуры
Вы заметите, что при обтекании контента вокруг фигуры он может слишком близко прилегать к элементу. Вы можете добавить отступы вокруг фигуры с помощью свойства shape-margin.
.element{
shape-outside: circle(40%);
shape-margin: 1em;
float: left;
}
Эффект аналогичен тому, который вы получаете при использовании обычного свойства margin, но shape-margin влияет только на пространство вокруг значения shape-outside. Отступ будет добавлен, только если для него есть место в системе координат. Поэтому в примере выше радиус круга равен 40%, а не 50%. Если бы радиус был равен 50%, круг занял бы все пространство в системе координат, не оставив места для эффекта shape-margin. Помните, что форма в конечном итоге ограничена margin-box элемента (элемент плюс окружающий его margin). Если форма больше и переполняется, она будет обрезана до margin-box, и вы получите прямоугольную форму.
Важно понимать, что shape-margin принимает только одно положительное значение. У него нет длинной записи. Что такое shape-margin-top для круга?
Анимация фигур
Фигуры CSS можно сочетать со многими другими функциями CSS, такими как переходы и анимация. Однако я должен подчеркнуть, что пользователей очень раздражает, когда макет текста меняется во время чтения. Если вы все же решите использовать анимированные фигуры, уделите особое внимание тому, как они будут выглядеть.
Вы можете анимировать радиусы и центры фигур circle() и ellipse(), если они определены в значениях, которые браузер может интерполировать. Переход с circle(30%) на circle(50%) возможен. Однако анимация между circle(closest-side) и circle(farthest-side) будет тормозить браузер.
.element{
shape-outside: circle(30%);
transition: shape-outside 1s;
float: left;
}
.element:hover{
shape-outside: circle(50%);
}
Более интересные эффекты можно получить при анимации фигур polygon(). Важно, чтобы многоугольник имел одинаковое количество вершин в обоих состояниях анимации. Браузер не сможет выполнить интерполяцию, если вы добавите или удалите вершины.
Один из способов – добавить максимальное количество вершин и сгруппировать их в том состоянии анимации, где нужно уменьшить количество видимых граней.
.element{
/* four vertices (looks like rectangle) */
shape-outside: polygon(0 0, 100% 0, 100% 100%, 0 100%);
transition: shape-outside 1s;
}
.element:hover{
/* four vertices, but second and third overlap (looks like triangle) */
shape-outside: polygon(0 0, 100% 50%, 100% 50%, 0 100%);
}
Перенос текста внутри фигуры
Первоначальный проект спецификации CSS Shapes включал свойство shape-inside, которое позволяло обертывать контент внутри фигуры. Некоторое время он даже поддерживался в Chrome и Webkit. Но чтобы обернуть контент, расположенный произвольно, в пользовательский путь, потребуется гораздо больше усилий и исследований, чтобы охватить все возможные сценарии и избежать ошибок. Поэтому свойство shape-inside было перенесено в CSS Shapes Level 2, а его реализации были отозваны.
Однако, приложив некоторые усилия и пойдя на компромисс, вы все же можете добиться эффекта обтекания контента внутри пользовательской фигуры. Для этого нужно использовать два плавающих элемента с shape-outside, расположенных на противоположных сторонах контейнера. Компромисс заключается в том, что вам нужно использовать один или два пустых элемента, которые не имеют семантического значения, но служат распорками для создания иллюзии формы внутри.
<div>
<div class='left-shape'></div>
<div class='right-shape'></div>
Lorem ipsum...
</div>
Расположение элементов .left-shape и .right-shape в верхней части контейнера имеет большое значение, поскольку они будут перемещены влево и вправо, чтобы обрамлять контент.
.left-shape{
shape-outside: polygon(0 0, ...);
float: left;
width: 50%;
height: 100%;
}
.right-shape{
shape-outside: polygon(50% 0, ...);
float: right;
width: 50%;
height: 100%;
}
В результате два плавающих элемента занимают все пространство внутри элемента, но свойства shape-outside освобождают место для остального контента.
Если браузер не поддерживает CSS Shapes, то весь контент будет сдвинут вниз, что выглядит некрасиво. Поэтому важно использовать эту функцию в режиме прогрессивного улучшения.
В предыдущих примерах анимации фигур вы могли заметить, что сдвиг текста может мешать. Анимированные фигуры подходят не для всех случаев. Но вы можете анимировать другие свойства, которые взаимодействуют с фигурами CSS, чтобы добавить эффект там, где это имеет смысл.
В демонстрации фигур CSS Алиса в Стране чудес мы использовали положение прокрутки, чтобы изменить верхнее поле контента. Текст зажат между двумя плавающими элементами. По мере перемещения вниз он должен перекомпоновываться в соответствии с shape-outside двух плавающих элементов. Это создает впечатление, что текст уходит в кроличью нору, и добавляет истории глубины. Спорный контент, добавленный без необходимости? Возможно. Но выглядит круто.
Поскольку макет текста создается браузером, производительность выше, чем при использовании JavaScript. Однако изменение верхнего поля при прокрутке вызывает множество событий перекомпоновки и отрисовки, что может заметно снизить производительность. Используйте с осторожностью! Однако использование CSS Shapes без анимации не приводит к заметному снижению производительности.
Прогрессивное улучшение
Начните с предположения, что браузер не поддерживает CSS Shapes, и создайте резервный вариант на случай, если функция не будет обнаружена. Для этого хорошо подходит библиотека Modernizr. В разделе Non-core detects (Неосновные проверки) есть тест для CSS Shapes.
Некоторые браузеры поддерживают определение функций в CSS с помощью правила @supports без использования внешних библиотек. Браузер Google Chrome, который также поддерживает CSS Shapes, понимает правило @supports. Вот как использовать его для прогрессивного улучшения:
.element{
/* styles for all browsers */
}
@supports (shape-outside: circle(50%)){
/* styles only for browsers which support CSS Shapes */
.element{
shape-outside: circle(50%);
}
}
Леа Веру (Lea Verou) написала статью о том, как использовать правило @supports в CSS.
Устранение неоднозначности в исключениях CSS
То, что мы сегодня знаем как CSS Shapes, в первые дни спецификации называлось CSS Exclusions and Shapes. Переключение в именовании может показаться нюансом, но на самом деле это очень важно. Исключения CSS, которые теперь являются отдельной спецификацией, позволяют обтекать контент вокруг элементов, расположенных произвольно, без необходимости использования свойства float. Представьте, что вы оборачиваете контент вокруг элемента с абсолютным позиционированием. Это один из вариантов использования исключений CSS. Фигуры CSS определяют только контур, по которому будет обтекаться контент.
Таким образом, фигуры и исключения – это не одно и то же, но они дополняют друг друга. Фигуры CSS уже поддерживаются в браузерах, а исключения CSS пока не работают с фигурами.
Инструменты для работы с фигурами CSS
Вы можете создавать контуры в классических инструментах для работы с изображениями, но ни один из них на момент написания этой статьи не экспортирует синтаксис, необходимый для значений CSS Shapes. Даже если бы они это сделали, работать так было бы не слишком практично.
Фигуры CSS предназначены для использования в браузере, где они реагируют на другие элементы страницы. Это очень полезно для визуализации эффектов редактирования формы на контенте, который ее окружает. Для этого можно использовать следующие инструменты:
Brackets. Расширение CSS Shapes Editor для Brackets использует режим предварительного просмотра редактора кода, чтобы накладывать интерактивный редактор для изменения значений фигур.
Google Chrome. Расширение CSS Shapes Editor для Google Chrome добавляет в инструменты разработчика элементы управления для создания и редактирования фигур. Над выбранным элементом появится интерактивный редактор.
В инспекторе Google Chrome есть встроенная поддержка выделения фигур. Наведите указатель мыши на элемент со свойством shape-outside, и он будет подсвечен, чтобы показать форму.
Фигуры из изображений. Если вы предпочитаете генерировать изображения и извлекать из них фигуры с помощью браузера, ознакомьтесь с руководством по Photoshop, которое написала Ребекка Хаук (Rebecca Hauck).
Полифил. Google Chrome – первый крупный браузер, в котором реализована поддержка CSS Shapes. В ближайшее время планируется добавить поддержку этой функции в Apple iOS 8 и Safari 8. Другие поставщики браузеров могут рассмотреть его в будущем. До тех пор вы можете использовать полифил CSS Shapes, чтобы обеспечить базовую поддержку.
Заключение
В интернете контент обычно размещается в простых прямоугольных блоках. С помощью CSS-фигур можно создавать выразительные макеты, которые по качеству не уступают печатным материалам. Конечно, фигурами можно злоупотреблять и создавать отвлекающие факторы. Но если использовать их со вкусом и умом, они могут улучшить представление контента и привлечь внимание пользователя уникальным образом.
В заключение предлагаю вам ознакомиться с коллекцией работ других авторов, в основном из печатных изданий, в которых демонстрируются интересные варианты использования непрямоугольных макетов. Надеемся, что эта статья вдохновит вас попробовать CSS Shapes и поэкспериментировать с новыми идеями дизайна.
Большое спасибо Перл Чен, Алану Стернсу и Золтану Хорвату за рецензирование этой статьи и предоставление ценной информации.