[Перевод] Липкий эффект

Буквально недавно Крис написал про «Эффект капельного преобразования в CSS». Эффект реально крутой и сама техника реализована по-умному, но данный подход через обычные CSS фильтры имеет определенные недостатки: нельзя использовать непрозрачность, добавлять контент внутрь капель, проблемы с фоновыми цветами.В последние дни я достаточно много экспериментировал с SVG фильтрами и заметил, что с их помощью можно решить вышеописанные проблемы в CSS реализации. Посмотрите на липкое меню, которое я сделал для демонстрации:

CodePen023d505a3c9448a48437f8ba3919765d.gif

SVG Filters 101SVG фильтры — это очень мощная штука. Но это очень обширная тема, поэтому мы поговорим только о самом необходимом для решения нашей задачи.Несмотря на название мы можем применять эти фильтры к DOM элементам с помощью CSS и это будет работать в большинстве браузеров.

Классический синтекс для описания фильтров:

Применение фильтра к DOM элементу:

.selector { filter: url ('#name-of-your-filter-here');

/* you can also load filters from external SVGs this way: */ filter: url ('filters.svg#name-of-your-other-filter-here'); } Вам могут понадобиться вендорные префиксы для свойства filter.

Элемент содержит в себе от одного и более фильтровых приметив (filter primitives), которые выполняют функции blur, color transform, shading. Полные перечень этих примитив находится тут.

Взглянем на парочку примеров:

CodePen55ffd609646c457e9d62b3de3bc4e6d2.jpg

Этот простой фильтр выполняет трех-пиксельное размытие элемента. Важно обратить внимание на атрибут in=«SourceGraphic». В in определяется к чему именно будет применяться фильтр. Значение SourceGraphic возвращает оригинальный элемент. Таким образом мы указываем, что размытие должно происходить для оригинального графического объекта. Все достаточно просто.

Давайте рассмотрим пример немного посложнее: drop shadow. В нем наглядно показано как работает цепочка фильтровых приметив вместе:

CodePen55ffd609646c457e9d62b3de3bc4e6d2.jpg

Взгляните на result и in атрибуты. В result указывается имя результата с применением фильтра, что в последствии дает нам возможность фильтровать этот результат в отличии от оригинального графического объекта. Тоесть в этом примере мы произвели размытие для элемента, затемнили конкретно размытый объект, а потом уже изменили позиции для размытого и затемненного объектов.

Обратите внимание на приметиву . Она содержит два атрибута для обозначения области применения: in со значением SourceGraphic и in2 со значением shadow.

Теперь, когда мы понимает базовые принципы работы SVG фильтров, давайте разберемся как делать липкий эффект.

Закрепим уже пройденное Основная техника описана здесь. Напомню, что идея заключается в том, чтобы одновременно размывать и контрастировать элементы. И все заработает магическим образом.CodePen885e386d4f1141b49d44ba4024202f0c.jpgОднако, мы по прежнему имеем:

Проблемы в работе с разным цветами. Размытие производится для всего элемента, включая содержимое. Невозможность использовать непрозрачность. Все это не позволяет применить данный трюк в реальном проекте.

С помощью SVG фильтров мы можем реализовать то, что не было возможно с CSS: мы можем увеличивать контрастность только для альфа-канала, не изменяя цвета; и с помощью SourceGraphic мы можем применять размытие только для самого элемента, не меняя содержимое.Также поскольку мы работаем с альфа-каналом, то не только он должен быть прозрачным, прозрачный фон необходим, будьте осторожны с этим.

Основной код:

Коротко о том, что мы сделали:

Во-первых мы произвели размытие в 10 пикселей и присвоим имя данному результату. Затем для получившегося результата мы применили color matrix filter для увеличения контрастности альфа-канала. И после этого мы вставили оригинальным графический объект в этот эффект. О Color Matrices Если вы до этого не использовали color matrix filter, то тогда необходимо пояснить как это работает. Представьте таблицу из четырех строк и пяти столбцов. Она будет выглядеть следующим образом. | R | G | B | A | + ---|------------------- R | 1×0 | 0×0 | 0 ---|------------------- G | 0×1 | 0×0 | 0 ---|------------------- B | 0×0 | 1×0 | 0 ---|------------------- A | 0×0 | 0×1 | 0 ---|------------------- Каждая строка представляет из себя канал (red, green, blue и alpha) и использует для установки значения канала. Первые четыре столбца также представляют из себя каналы. Число в клетке являет мультипликатором канала в столбце для канала в строке. Например, 0.5 в строке R и столбце G добавит к красному каналу текущее значение Green*0.5. Последняя колонка уже не представляет из себя канал и используется для добавления или вычитания. Числа указанные в ней умножаются на 255 и присваиваются соответствующему каналу.

Это долго объяснять, но на самом деле использование фильтра предельно простое. В нашем случае мы изменяем только значение альфа-канала и наша матрица будет выглядеть так:

| R | G | B | A | + ---|------------------- R | 1×0 | 0×0 | 0 ---|------------------- G | 0×1 | 0×0 | 0 ---|------------------- B | 0×0 | 1×0 | 0 ---|------------------- A | 0×0 | 0×18 |-7 ---|------------------- RGB каналы остаются неизмененными. Значение альфа-канала умножается 18, а затем из него вычитается 7×255, эффективно увеличивая контраст одной только прозрачности. Все значения можно настроить под ваши потребности.

Чтобы применить эту матрицу для feColorMatrix фильтра, мы должны написать все значения в определенном порядке:

values=»1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7» Демо В итоге задуманный нами эффект работает. Пример: CodePenb4199c9ec7064b34a235518f31e2bbce.gif

Вы можете кастомизировать все, что вам нужно, добавить тень, изменить цвет каждого элемента, все в вашем распоряжении!

Подытожим Фильтр должен применять к контейнеру с элементами, а не к самим элементам. Из за самого тянущего эффекта контейнер должен быть немного большей области чем содержимое. В противном случае вы можете получить подобные дефекты на краях: image Для того, чтобы применять данный фильтр к примеру для прямоугольников мы должны воспользоваться немного более изощренным способом. Вместо отрисовки оригинального объекта над липкоим эффектом, мы должны применить feComposite фильтр с атрибутом atop, для того чтобы скрыть все, что выходит за рамки: CodePen354567720ac1493aabeb268072292d7e.gifДанный подход вы можете использовать не только для создания липкого эффекта, но и в более простых случаях, например, для закругления углов нескольких прямоугольников. Данный фильтр хоть и легок в своем объеме, но может быть очень ресурсоемким, если применяется для больших площадей. Поэтому будьте осторожны. Поддержка SVG фильтры имеют хорошую поддержку, но не все браузеры поддерживают их применение к DOM элементам, в частности, Safari. Однако они действительно работают, по крайней мере, над Firefox и Хромом, даже версией Android. Но фильтр заметно портит картину если не поддерживается. В случае если его использование вам необходимо, то используйте его для элементов SVG вместо элементов DOM.

© Habrahabr.ru