CSS Shapes
Прямоугольники внутри прямоугольников: это то, из чего состоят веб-страницы. Мы долго пытались вырваться из этих ограничений с помощью CSS для создания геометрических фигур, но форма этих фигур никогда не влияла на форму укладки контента внутри элемента, или на то, как элемент соотносится с другими элементами страницы.
Новая спецификация CSS Shapes меняет такое положение вещей. Представленная в середине 2012 года компанией Adobe, она имеет своей целью предоставить веб-дизайнерам новые возможности размещения контента, который теперь может обтекать сложные геометрические фигуры, как изнутри, так и снаружи - чего мы раньше не могли сделать даже с помощью JavaScript.
Например, обратите внимание, как текст обтекает круглое изображение в этом макете. Без Shapes, текст был бы просто прямоугольным блоком - возможность взаимодействия со сложными фигурами действительно открывает перед дизайнерами новые горизонты:

Давайте рассмотрим, как работает Shapes, и как вы можете начать его использовать.
Поддержка браузерами
В настоящее время CSS Shapes поддерживается только в Webkit Nightly и Chrome Canary, но его Модульный уровень 1 получил статус «рекомендовано к рассмотрению», то есть свойства и синтаксис, определенные в спецификации, вполне стабильны.
Думаю, не пройдет много времени, прежде чем Shapes будет реализован в других браузерах. Этот уровень ориентирован на свойства Shapes, которые изменяют обтекание фигур контентом.
В частности, здесь определено свойство shape-outside и связанные с ним другие свойства. В сочетании с другими новейшими функциями, такими как Обрезка и наложение, CSS-фильтры, и Компоновка и взаимодействие, CSS Shapes позволят нам создать более сложные конструкции, не прибегая при этом к помощи графических редакторов, таких как Photoshop или InDesign.
Последующие уровни CSS Shapes будут описывать заключение контента внутри фигур. Например, на сегодняшний день в CSS довольно просто создать фигуру ромба: просто повернуть элемент на 45 градусов, а затем повернуть содержимое внутри него в обратную сторону, чтобы текст располагался горизонтально.
Но контент внутри ромба не будет зависеть от контейнера этой фигуры, он всегда будет оставаться прямоугольным блоком.
Когда же будут реализованы свойства CSS Shapes shape-inside, мы сможем сделать блок самого контента также ромбическим, и такие макеты, как тот, что приведен ниже, станут вполне возможны:

Сегодня для того чтобы использовать CSS Shapes в Chrome Canary, вы должны с помощью специальной опции разрешить использование экспериментальных функций. Если вы не уверены, как это делается, посмотрите эту пошаговую инструкцию в блоге Adobe.
Создание CSS Shape
Вы можете применить форму к элементу с помощью одного из свойств Shapes. Вы передаете свойство фигуры в функцию Shapes в качестве значения. Функция фигуры, это то куда вы передаете аргументы, определяющие фигуру, которую вы хотите применить к элементу:

Фигуры могут быть созданы с помощью одной из следующих функций:
- circle();
- ellipse();
- inset();
- polygon().
Каждая фигура определяется набором точек. Некоторые функции принимают точки в качестве параметров; другие принимают смещения - но все они в конечном итоге рисуют фигуры в виде набора точек. Мы рассмотрим параметры для каждой из этих функций в приведенных ниже примерах.
Фигура также может быть определена путем ее извлечения из изображения с помощью альфа-канала. Когда изображение передается в свойства фигуры, браузер извлекает фигуру из картинки, используя shape-image-threshold. Форма определяется пикселями, чьи альфа-значения больше, чем пороговое значение.
Изображение должно быть совместимо с CORS. Если предоставляемое изображение по какой-либо причине не может быть отображено (например, если оно не существует), то не будет применяться ни одна из фигур.
Список свойств фигуры, которые принимают указанные выше функции в качестве значений:
- shape-outside: укладывает контент вокруг (вне) фигуры;
- shape-inside: укладывает контент внутри фигуры.
Вы можете использовать свойство shape-outside в сочетании со свойством shape-margin, чтобы добавить отступ от краев фигуры, этот отступ отодвинет текстовый контент от границ фигуры, создавая между ними свободное пространство. Аналогично сочетание свойств shape-inside и shape-padding отодвигает контент от границ фигуры изнутри, создавая внутренний отступ.
С помощью свойств и функций фигур, объявить фигуру, применяемую к элементу, можно одной строкой CSS-кода:
.element {
shape-outside: circle(); /* контент будет обтекать круг, определенный в элементе */
}
Или:
.element {
shape-outside: url(path/to/image-with-shape.png);
}
Но...
Даже если вы примените этот CSS-код к элементу, форма не будет применена, если не будут выполнены два условия:
- Элемент должен быть плавающим. Будущие уровни CSS Shapes предоставят нам возможность определять фигуры и для не плавающих элементов, однако пока мы не можем сделать это;
- Элемент должен иметь внутренние размеры. Высота и ширина, установленные в элементе, будут использоваться для создания системы координат этого элемента.
Как я уже сказала, фигуры определяются в виде наборов точек. Так как эти точки имеют координаты, браузеру нужна система координат, чтобы знать, где расположить каждую точку в элементе. Так, приведенный выше пример будет работать, если он включен приблизительно следующим образом:
.element {
float: left;
height: 10em;
width: 15em;
shape-outside: circle();
}
Установка таких внутренних размеров элемента, однако, не означает, что это повлияет на его адаптивность (мы поговорим об этом чуть позже).
Поскольку каждая фигура определяется набором точек, расположенных с помощью пары координат, изменение координат точки будет непосредственно влиять на созданную фигуру. Например, следующее изображение показывает шестиугольник, который может быть создан с помощью функции polygon().
Фигура состоит из шести точек. Изменение горизонтальной координаты оранжевой точки изменит получившуюся фигуру, и это повлияет на расположение контента внутри и / или снаружи любого элемента, к которому эта фигура применяется:

Исходный бокс Shapes
CSS Shapes определяется и создается внутри исходного бокса (reference box), который используется, чтобы нарисовать фигуру в элементе. Кроме высоты и ширины элемента, бокс содержит: бокс границы, бокс смещения, бокс отступа, бокс контента, - они также используются в качестве основы для определения характеристик фигуры элемента.
По умолчанию бокс отступа используется в качестве основы - так, если вы применяете фигуру для элемента с отступом снизу, то этот отступ будет отсчитываться не от края фигуры, а от зоны отступа по умолчанию. Если вы хотите использовать одно из других значений бокса, вы можете указать его в сочетании с функцией фигуры, которую вы передаете в свойства фигуры:
shape-outside: circle(250px at 50% 50%) padding-box;
Ключевое слово padding-box в приведенном выше коде указывает, что форма применяется, и она ограничивается боксом заполнения (областью заполнения) элемента. Функция circle() определяет фигуру круга, его размер и положение в элементе.
Определение Shapes с помощью функции фигуры
Мы начнем с укладки некоторой информации вокруг круглой картинки-аватара пользователя, вы могли бы использовать это для отображения профиля пользователя или вывода краткой справки о нем:

Мы будем использовать функцию circle(), чтобы применить фигуру круга с изображением пользователя, используя следующий код:
<img src="http://api.randomuser.me/0.3.2/portraits/men/7.jpg" alt="profile image" />
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Harum itaque nam blanditiis eveniet enim eligendi quae adipisci?</p>
<p>Assumenda blanditiis voluptas tempore porro quibusdam beatae deleniti quod asperiores sapiente dolorem error! Quo nam quasi soluta reprehenderit laudantium optio ipsam ducimus consequatur enim fuga quibusdam mollitia nesciunt modi.</p>
Вы можете спросить: "Почему бы не использовать border-radius для круглого изображения?" Ответ таков - свойство border-radius не влияет на обтекание контентом внутри или вокруг элемента, к которому применяется - оно не влияет на область контента внутри элемента или обтекание областью контента вокруг элемента. Оно влияет только на границы элемента и фоны.
Фоновая область обрезается по кругу, исходя из того, как задано свойство, но это и все. Контент внутри элемента будет оставаться прямоугольной формы, а контент вне элемента будет по-прежнему взаимодействовать с элементом, как будто он прямоугольной формы, потому что таково это свойство.
Мы используем свойство border-radius, чтобы сделать изображение круглым, таким образом, мы обычно и придаем круглую форму изображениям или другим элементам страницы:
img {
float: left;
width: 150px;
height: 150px;
border-radius: 50%;
margin-right: 15px;
}

В браузере, который не поддерживает CSS Shapes, контент вокруг круглого изображения будет обтекать его так, как будто оно вовсе не имеет круглую форму. Это будет нашим запасным вариантом для старых браузеров.
Для того чтобы изменить обтекание контента соответственно определенной фигуре, можно использовать свойства фигуры:
img {
float: left;
width: 150px;
height: 150px;
border-radius: 50%;
shape-outside: circle();
shape-margin: 15px;
}
С помощью этого кода текст будет "видеть" круглую фигуру, примененную к изображению и укладываться вокруг него, как это было показано на первом скриншоте. (Сам результат вы можете увидеть здесь.) В браузерах, не поддерживающих Shapes, будет применяться код, который выводит контент так, как показано на втором скриншоте.
Вы можете использовать функцию circle(), как есть, или путем передачи в нее параметров. Ее официальный синтаксис следующий:
circle() = circle( [<shape-radius>]? [at <position>]? )
Знаки вопроса показывают, что эти параметры являются необязательными и могут быть опущены. Если вы опускаете один из параметров, его значение в браузере устанавливается по умолчанию. Если вы используете функцию circle() без указания расположения, то по умолчанию будет определяться круг, который расположен в центре элемента, к которому применена фигура.
Вы можете указать радиус окружности, используя любые единицы длины (px, em, pt и т.д.) Вы также можете указать радиус, используя либо furthest-side, либо closest-side, но по умолчанию используется параметр closest-side, что означает, что браузер будет использовать расстояние от центра элемента до ближайшей к нему стороны, как длину радиуса. farthest-side использует расстояние от центра до самой дальней стороны элемента:
shape-outside: circle(farthest-side at 25% 25%); /* определяет круг с радиусом, равным половине расстояния от центра элемента до его дальней стороны, расположенный в точке с координатами 25% 25% по системе координат элемента*/
shape-inside: circle(250px at 500px 300px); /* определяет круг с центром расположенным в точке с координатами 500 пикселей по горизонтали, 300 пикселей по вертикали и радиусом 250 пикселей */

Функция ellipse() действует так же, как функция circle(), с теми же значениями, за исключением того, что вместо одного параметра радиуса, она принимает два: один для длины радиуса по оси х, второй - по оси у:
ellipse() = ellipse( [<shape-radius>{2}]? [at <position>]? )
Функция inset() напрямую не связана ни с кругом, ни с эллипсом, она используется для создания прямоугольных фигур внутри элемента.
Но поскольку элементы уже имеют прямоугольную форму, и нам не нужно отдельно задавать прямоугольник, inset() может помочь нам создавать прямоугольники с закругленными углами, вокруг которых текст будет обтекать соответствующим образом:

Функция inset() принимает от одного до четырех значений смещения, которые определяют смещения внутри от краев исходного бокса. Они определяют, где прямоугольник будет размещен внутри элемента.
Функция также принимает необязательный параметр степени закругления углов вставляемого прямоугольника. Закругленные углы задаются точно так же, как border-radius, с использованием от одного до четырех значений, в сочетании с ключевым словом round:
inset() = inset( offset{1,4} [round <border-radius>]? )
Следующий код будет создавать прямоугольник с закругленными углами для плавающего элемента:
.element {
float: left;
width: 250px;
height: 150px;
shape-outside: inset(0px round 100px) border-box;
}
Реальный пример вы можете увидеть здесь.
И еще одна функция Shape - polygon(), она определяет более сложные произвольные фигуры, используя любое количество точек. Функция принимает набор пар координат, каждая из которых указывает положение одной точки. Множество точек в совокупности определяют фигуру.
В следующем примере, изображение расположено на странице справа, занимая всю высоту экрана. Мы хотим, чтобы текст обтекал песочные часы внутри изображения, поэтому мы используем функцию polygon(), чтобы задать неправильную фигуру внутри изображения:

CSS для приведенного выше изображения выглядит следующим образом:
img.right {
float: right;
height: 100vh;
width: calc(100vh + 100vh/4);
shape-outside: polygon(40% 0, 100% 0, 100% 100%, 40% 100%, 45% 60%, 45% 40%);
}
Вы можете установить координаты точек, определяющих форму, в единицах длины или процентах, как в данном случае.
Этот код сам по себе дает такой результат, но как вы можете видеть, функция фигуры не влияет на остальные части изображения вне определенной формы.
В самом деле, применение функции фигуры к элементу - изображению, контейнеру или чему-то среднему - не влияет ни на что, кроме обтекания текстом обозначенной области фигуры. Фон, границы и все остальное остаются неизменным.
Для того чтобы визуализировать форму многоугольника, который мы создали, мы должны «обрезать» части изображения вне этой фигуры. В этом нам поможет свойство clip-path из CSS Masking Module.
Свойство clip-path принимает те же функции фигуры и значения, что и свойства фигуры. Если мы передадим в свойство clip-path ту же фигуру многоугольника, которую мы использовали в свойстве shape-outside, мы обрежем все части изображения, которые находятся вне определенной фигуры:
img.right {
float: right;
height: 100vh;
width: calc(100vh + 100vh/4);
shape-outside: polygon(40% 0, 100% 0, 100% 100%, 40% 100%, 45% 60%, 45% 40%);
/* обрезает изображение по заданной фигуре */
clip-path: polygon(40% 0, 100% 0, 100% 100%, 40% 100%, 45% 60%, 45% 40%);
}
Результат будет следующим:

Свойство clip-path на сегодняшний день поддерживается с помощью префиксов, поэтому оно работает в Chrome через добавление к свойству префикса -webkit-. Реальный пример вы можете увидеть здесь.
Свойство clip-path прекрасно сочетается со свойствами фигур, так как оно помогает визуализировать созданные фигуры и обрезать все части элемента, которые находятся вне определенных форм. Поэтому вы, вероятно, найдете его полезным для себя и будете часто использовать его вместе со свойствами Shapes.
Функция polygon() также может принимать (необязательно) ключевые слова nonzero или evenodd. С их помощью указывается, как располагаются относительно друг друга области внутри фигуры многоугольника, которые имеют пересекающиеся сектора.
Больше об этом вы можете узнать в разделе свойства SVG fill-rule.
Определение фигуры с помощью изображения
Чтобы определить фигуру с помощью изображения, само изображение должно иметь альфа-канал, из которого браузер может извлечь фигуру.
Фигура определяется пикселями, чьи альфа-значения больше, чем определенное крайнее значение. Этот порог по умолчанию равен 0,0 (полностью прозрачный), или вы можете установить собственное значение с помощью свойства shape-image-threshold. Таким образом, любой непрозрачный пиксель будет использоваться как часть определенной формы из изображения.
Будущие уровни CSS Shapes смогут определять переходы, используя данные яркости изображения, вместо альфа-данных. Если это произойдет, shape-image-threshold сможет использовать или альфа-данные, или яркость, в зависимости от состояния переключателя.
Сейчас я хочу использовать следующее изображение, чтобы определить фигуру, соответствующую этому элементу, и задать обтекание текстом вокруг этой фигуры:

С помощью свойства shape-outside со значением url(), указывающим на это изображение фотографии, мы можем задать обтекание контентом вокруг элемента в форме листа:
.leaf-shaped-element {
float: left;
width: 400px;
height: 400px;
shape-outside: url(leaf.png);
shape-margin: 15px;
shape-image-threshold: 0.5;
background: #009966 url(path/to/background-image.jpg);
mask-image: url(leaf.png);
}
Конечно, если бы вы применяли к элементу фон, его нужно было бы обрезать вне определенной фигуры. Так как clip-path не принимает альфа-изображение в качестве значения, это можно сделать с помощью свойства mask-image (с соответствующими префиксами) из Masking Module. Результат выглядит следующим образом:

Если вы создаете сложные фигуры, вы, возможно, захотите определить форму, используя изображение. Это позволит использовать альфа-канал изображения в Photoshop, вместо того, чтобы вручную определять точки.
Вы также, вероятно, захотите использовать изображение вместо функции фигуры, когда у вас есть несколько обтекаемых или исключаемых областей внутри элемента - в данный момент мы не можем объявлять несколько фигур в элементе. Но если изображение содержит несколько областей, браузер сможет извлечь эти области из изображения и использовать их.
CSS Shapes в адаптивном дизайне
Может ли CSS Shapes использоваться в процессе разработки адаптивного дизайна? Текущая спецификация уже охватывает shape-outside, и так как мы можем указывать размеры элемента не только в различных единицах длины, но и в процентах, мы смело можем этим пользоваться.
Это означает, что элемент с заданной shape-outside будет полностью адаптивным, как и любой другой плавающий элемент с размерами, заданными в процентах.
shape-inside пока еще не является адаптивной, но это только потому, что данный вопрос специально реализуется в Модульном уровне 2, многие из нынешних ограничений будут решены в следующем уровне.
Инструменты Shape
Создание сложных форм с помощью функций фигур может оказаться непростой задачей, особенно если вы при помощи функции polygon() создаете фигуру, состоящую из множества точек, каждая со своими координатами. К счастью, команда веб-платформы компании Adobe работает над развитием интерактивного инструментария, что сделает многие вещи гораздо проще.
Беар Трэвис создал коллекцию Shape Tools, которая позволяет визуально задавать многоугольные фигуры. Затем инструмент автоматически генерирует для нас функцию фигуры. Это довольно удобно, но данные инструменты имеют определенные ограничения.
Если вы хотите создать форму на основе определенного изображения, не существует никакого способа вставить изображение в инструмент, а затем создать для него фигуру.
Более продвинутый и гибкий инструмент Shapes был разработан командой Adobe Web Platform. Инструмент был недавно выпущен в качестве расширения для бесплатного редактора Brackets компании.
Он позволяет визуализировать и редактировать фигуры непосредственно в браузере, и имеет интерактивную функцию предварительного просмотра, которая обновляет значения фигуры в таблице стилей, когда вы вносите изменения на странице.
Это позволяет мгновенно визуально отображать все изменения, и вы сразу можете увидеть, как ваши фигуры взаимодействуют с другими элементами страницы.
В правой части окна браузера осуществляется редактирование фигуры, а слева сразу интерактивно отображается код:

Этот инструмент станет для вас незаменимым, потому что он облегчает создание, редактирование и отладку фигур. Разван Калиман написал статью в блоге Brackets, из которой вы можете получить представление о том, как вам установить и начать использовать редактор Shapes в Brackets.
Будущее: CSS Exclusions
Спецификация CSS Shapes раньше использовалась и как спецификация CSS Shapes, и как Exclusions, но позже они были разделены.
В то время как CSS Shapes определяет свойства shape-inside и shape-outside, CSS Exclusions будет определять свойства, которые позволяют нам уложить контент вокруг элементов, которые не являются плавающими, например, элементов с заданным абсолютно расположением.
Это позволяет уложить контент таким образом, чтобы он со всех сторон был окружен другими элементами, как это показано на рисунке ниже:

В будущем, CSS Exclusions позволит нам уложить текст в виде врезки, как показано на этом развороте журнала. Врезка может также быть круглой формы, текст все равно отлично впишется.
Подобные макеты с элементами определенной формы расположенными по центру статьи - с текстом, обтекающим их со всех сторон - также будут возможны.
Дальнейшее развитие Shapes
Текущая спецификация CSS Shapes - это лишь первый шаг. Вскоре новые опции предоставят нам больше контроля при создании фигур и укладке контента в и вокруг них. Что в свою очередь облегчит превращение макетов в интерактивные конструкции с помощью всего нескольких строк кода.
Сегодня редакторы спецификации ориентированы на работу с shape-outside, и еще до конца 2014 года мы, вероятно, увидим широкое применение CSS Shapes.
Вы можете использовать Shapes уже сегодня, как инновационную часть своего рабочего процесса, при этом учитывая, что они на текущий момент еще недостаточно поддерживаются браузерами. Для более сложных конструкций вы можете использовать специальный скрипт для проверки того поддерживает ли браузер Shapes, и, если это не так, предоставлять запасной вариант.
Вы также можете расширить тест Modernizr с помощью этого скрипта, чтобы проверить поддерживается ли shape-outside или скачать пользовательские сборки, включающие этот скрипт.
CSS Shapes еще больше приблизит веб-дизайн к полиграфии. Примеры, приведенные в этой статье, довольно просты, но они позволят вам создавать конструкции, настолько же сложные, как и в иллюстрированных журналах или на плакатах - все это вы сможете воссоздать на экране.
Что бы вас не заинтересовало - макеты неправильной формы или анимированные Shapes - пришло время попробовать их на практике и поэкспериментировать.