В первой статье мы уже разобрались с основами SVG-фильтров, научились их создавать и рассмотрели несколько часто используемых примитивов. Если вы ее еще не читали, обязательно загляните.
<feMorphology>
— одна из самых простых и в то же время эффектных операций фильтрации. Результаты ее применения к различным элементам в большинстве случаев предсказуемы.
Что такое морфинг?
Морфинг означает преобразование формы объекта.
Морфологический фильтр предлагает два способа преобразования формы:
- erosion – сжатие;
- dilation – расширение или растягивание.
Эти операции работают на пиксельном уровне. Они либо растягивают контрольный пиксель на соседние области, либо размывают соседние пиксели, сохраняя контур.
Параметр radius
задает величину расширения или количество соседних пикселей, используемых для модификации контрольного.
<feMorphology
in=".." result=".."
operator="dilate || erode" radius="">
</feMorphology>
Все пиксели, попавшие в круг, определенный радиусом морфинга считаются соседними для контрольного пикселя.
Не заморачивайтесь особенно техническими подробностями реализации. Важно понять, как работает этот примитив на визуальном уровне. Вы можете передать в radius одно значение для обеих осей или два – по одному для x-
и y-
осей.
Морфинг изображений
Применение операции feMorphologe
к изображениям дает предсказуемые результаты:
- Размер картинки уменьшается (
erode
) или увеличивается (dilate
). - В обоих случаях изображение выглядит «нарисованным» большой кистью, уменьшается количество мелких деталей.
Простейший код фильтра выглядит так:
<svg width="450" height="300" viewBox="0 0 450 300">
<filter id="erode">
<feMorphology operator="erode" radius="3"></feMorphology>
</filter>
<image xlink:href="..." width="90%" height="90%" x="10" y="10" filter="url(#erode)"></image>
</svg>
Здесь мы сжимаем картинку на 3 пикселя. Обратите внимание изображение справа (результат) немного меньше левого (исходник):
Теперь заменим оператор erode
на dilate
. Полученный эффект немного похож на предыдущий, но в то же время существенно отличается:
Изображение в любом случае выглядит как нарисованная абстракция, а его размер изменяется по мере расширения или сжатия пикселей.
Кроме того, изменяются цвета. Операция erode
создает изображение с большим количеством темных пикселей, dilate
, наоборот, осветляет картинку.
erode
(значение по умолчанию) устанавливает для каждого канала пикселя (R, G, B, A) самое темное или самое прозрачное из значений его соседей;dilate
же выбирает самое яркое или наименее прозрачное значение.
See the Pen feMorphology on an image by Sara Soueidan (@SaraSoueidan) on CodePen.
Если применять feMorphologe
к одноцветным элементам (например, к тексту), то никаких заметных изменений цвета, конечно, не произойдет. В этом случае имеет значение именно эффект сжатия/расширения.
Добавляем цветной контур
Вы наверняка знакомы с атрибутом stroke, который позволяет добавлять контур элементам SVG (в том числе и тексту).
<text font-size="80px" dx="100" dy="200" font-weight="700" stroke="deepPink" stroke-width="3px">Stroked Text</text>
Проблема в том, что обводка stroke
располагается на границе элемента так, что ее половина заходит на сам элемент. То есть текст становится тоньше, а это не всегда нам подходит.
С помощью примитива feMorphology
можно накладывать контур, не задевая сам текст, то есть расширять его. Утолщенный таким образом текст может быть использован как входные данные для другого примитива фильтра.
Прежде чем мы начнем, оцените разницу между контурами stroke
и feMorphology
визуально:
А теперь шаг за шагом создадим что-то в таком роде:
Начнем с вывода текста в SVG и простой операции расширения с помощью feMorphology
. Параметр radius
определяется желаемой толщиной контура.
<svg width="900" height="200" viewBox="100 0 900 200">
<filter id="outline">
<feMorphology in="SourceAlpha" result="DILATED" operator="dilate" radius="4"></feMorphology>
</filter>
<!-- Расширенный текст -->
<text font-size="85px" dx="125" dy="130" font-weight="700" filter="url(#outline)">upgrade yourself</text>
</svg>
Примитив получает альфа-канал текста – его сплошь черную версию и увеличивает его на 4 пикселя.
Исходный текст выглядел вот так:
Уже догадались, как сделать контур?
Мы просто наложим исходный текст поверх расширенного. Таким образом эти дополнительные 4 пикселя будут выглядывать из-за него как рамка. Для наложения используем уже знакомый нам из первой статьи примитив feMerge
.
Также контур нужно раскрасить. Это мы тоже уже делали. Примитив feFlood
зальет все нужным цветом, а feComposite
с оператором in
ограничит заливку только границами текста.
<svg width="900" height="200" viewBox="100 0 900 200">
<filter id="outline">
<feMorphology in="SourceAlpha" result="DILATED" operator="dilate" radius="4"></feMorphology>
<feFlood flood-color="#32DFEC" flood-opacity="1" result="PINK"></feFlood>
<feComposite in="PINK" in2="DILATED" operator="in" result="OUTLINE"></feComposite>
<feMerge>
<feMergeNode in="OUTLINE" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<text font-size="85px" dx="125" dy="130" font-weight="700" filter="url(#outline)">upgrade yourself</text>
</svg>
Для создания SVG-фильтра мы учимся комбинировать простейшие операции и использовать результаты их работы.
See the Pen Colored Text Outline with feMorphology by Sara Soueidan (@SaraSoueidan) on CodePen.
Цвет самого текста можно указать либо в CSS, либо в элементе text с помощью атрибута fill
. Цвет контура устанавливается в атрибуте flood-color
примитива feFlood
.
Вырезаем текст
Можно сделать также эффект «вырезанного текста» (knockout text) – при этом остается только обводка, а через сами буквы виден фон. Попробуем реализовать вот такой демо-пример:
Это еще проще, а код получится намного короче.
Вместо наслоения исходного текста поверх расширенного, мы будем использовать этот исходный текст для вырезания внутренней части расширенного. Таким образом, останется только добавленная толщина – то есть сам контур.
Используем для этого примитив feComposite
с оператором out
. Исходный текст будет сверху, а расширенный – фоном. Фильтр отрисует только те части фона, которые не перекрываются верхним слоем.
<svg width="900" height="450" viewBox="0 0 900 450">
<filter id="outliner">
<!-- Получаем альфа-канал текста и расширяем его-->
<feMorphology operator="dilate" radius="8" in="SourceAlpha" result="THICKNESS" />
<!-- Берем исходный текст и вырезаем его из расширенного -->
<feComposite operator="out" in="THICKNESS" in2="SourceGraphic"></feComposite>
</filter>
<text dx="100" dy="300" filter="url(#outliner)" letter-spacing="10px">SVG Rocks</text>
</svg>
Добавим сюда еще красивый шрифт – вуа-ля!
Получилось круто.
Но что, если вы захотите изменить цвет контура? Придется снова использовать примитив feFlood
и комбинировать контур с заливкой снова и снова? Нет, это было бы слишком утомительно, сделаем проще.
Вместо того, чтобы расширять голый альфа-канал текста (SourceAlpha
), который всегда черный, можно расширить сам текст (SourceGraphic
), который может быть любого цвета. В этом случае цвет контура всегда будет совпадать с цветом исходного текста и его можно будет легко поменять из CSS.
Также этот фильтр легко можно будет переиспользовать с другими элементами.
Наш улучшенный код теперь выглядит так:
<svg width="900" height="450" viewBox="0 0 900 450">
<filter id="outliner">
<!-- Берем исходный текст и расширяем его-->
<feMorphology operator="dilate" radius="8" in="SourceGraphic" result="THICKNESS" />
<!-- Берем исходный текст и вырезаем его из расширенного -->
<feComposite operator="out" in="THICKNESS" in2="SourceGraphic"></feComposite>
</filter>
<text dx="100" dy="300" filter="url(#outliner)" letter-spacing="10px">SVG Rocks</text>
</svg>
В таблице стилей можно установить любой цвет контура и фона, можно поставить изображение или анимацию.
svg text {
font-family: 'Bangers', cursive;
font-size: 150px;
letter-spacing: 13px;
fill: #000; /* цвет контура */
}
svg {
background-color: gold;
animation: colorsssss 2s linear infinite;
animation-delay: 3s;
}
@keyframes colorsssss {
50% {
background-color: deepPink;
}
}
Этот SVG-фильтер легко можно применять и к HTML-элементам через CSS-свойство filter
. При этом цвет контура будет определяться как всегда свойством color
.
h2 {
filter: url(#outliner);
color: deepPink;
}
Та-дам!
See the Pen (Text) Outlines (Only) by Sara Soueidan (@SaraSoueidan) on CodePen.
Самое классное, что такой фильтр можно использовать как прогрессивное улучшение. Если браузер не поддерживает SVG-фильтры, или CSS-фильтры, или применение SVG к HTML-элементам, пользователь получит простой и доступный исходный текст без всяких эффектов.
В любом случае этот текст будет полностью доступен для поисковых роботов и для выделения пользователем.
В заключение
Используя всего два SVG-примитива фильтров, вы можете добавить тексту (в SVG или в HTML) эффект контура. Поместите созданный фильтр на страницу и используйте его так часто, как необходимо.
0 комментариев