3,2
рейтинг
11 февраля 2015 в 04:05

Разработка → Липкий эффект перевод

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

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

CodePen



SVG Filters 101

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

Несмотря на название мы можем применять эти фильтры к DOM элементам с помощью CSS и это будет работать в большинстве браузеров.

Классический синтекс для описания фильтров:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <defs>
    <filter id="name-your-filter-here">
      ...          
      <!-- insert filters here -->
      ...
    </filter>
    ...
  </defs>
</svg>


Применение фильтра к 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. Полные перечень этих примитив находится тут.

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

CodePen


<filter id="blur">
  <feGaussianBlur in="SourceGraphic" stdDeviation="3" />
</filter>


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

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

CodePen


<filter id="drop-shadow">
  <feGaussianBlur in="SourceGraphic" stdDeviation="7" result="shadow" />
  <feOffset in="shadow" dx="3" dy="4" result="shadow" />
  <feColorMatrix in="shadow" mode="matrix" values="0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.6 0" result="shadow" />
  <feBlend in="SourceGraphic" in2="shadow" />
</filter>


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

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

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

Закрепим уже пройденное

Основная техника описана здесь. Напомню, что идея заключается в том, чтобы одновременно размывать и контрастировать элементы. И все заработает магическим образом.
CodePen


Однако, мы по прежнему имеем:

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


Все это не позволяет применить данный трюк в реальном проекте.

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

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

<filter id="goo">
  <feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
  <feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 18 -7" result="goo" />
  <feBlend in="SourceGraphic" in2="goo" />
</filter>


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

  1. Во-первых мы произвели размытие в 10 пикселей и присвоим имя данному результату.
  2. Затем для получившегося результата мы применили color matrix filter для увеличения контрастности альфа-канала.
  3. И после этого мы вставили оригинальным графический объект в этот эффект.


О 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"


Демо

В итоге задуманный нами эффект работает. Пример:

CodePen


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

Подытожим

  • Фильтр должен применять к контейнеру с элементами, а не к самим элементам.
  • Из за самого тянущего эффекта контейнер должен быть немного большей области чем содержимое. В противном случае вы можете получить подобные дефекты на краях:
    image
  • Для того, чтобы применять данный фильтр к примеру для прямоугольников мы должны воспользоваться немного более изощренным способом. Вместо отрисовки оригинального объекта над липкоим эффектом, мы должны применить feComposite фильтр с атрибутом atop, для того чтобы скрыть все, что выходит за рамки:
    <filter id="fancy-goo">
      <feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
      <feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 19 -9" result="goo" />
      <feComposite in="SourceGraphic" in2="goo" operator="atop"/>
    </filter>
    

    CodePen

    Данный подход вы можете использовать не только для создания липкого эффекта, но и в более простых случаях, например, для закругления углов нескольких прямоугольников.
  • Данный фильтр хоть и легок в своем объеме, но может быть очень ресурсоемким, если применяется для больших площадей. Поэтому будьте осторожны.


Поддержка

SVG фильтры имеют хорошую поддержку, но не все браузеры поддерживают их применение к DOM элементам, в частности, Safari. Однако они действительно работают, по крайней мере, над Firefox и Хромом, даже версией Android. Но фильтр заметно портит картину если не поддерживается. В случае если его использование вам необходимо, то используйте его для элементов SVG вместо элементов DOM.
Перевод: Lucas Bebber
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (16)

  • +38
    Ребят, вы все очень крутые, но на реальных сайтах все тормозит именно так как на гифках, меню сами раскрываются, закрываются, верстка ползет, вебсайт прыгает туда сюда и попасть в нужный тебе элемент простому смертному невозможно.
    Уф. Давно хотел это кому-то сказать.
    Извините.
    • НЛО прилетело и опубликовало эту надпись здесь
      • +5
        На самом деле это не имеет никакого значения, потому что ценность этих финтифлюшек определяется только редкостью их применения. За исключением, может быть, случаев написания статей специально о них.
        • 0
          Да прям уж никакого значения не имеет. Эстетическая составляющая имеет важное значение. Если бы это было не так, то тогда бы и музыку красивую не слушали и блюда к столу не пытались красиво оформить и т.д.
          • +2
            Ви таки будете смеяться, но далеко не все слушают музыку и заморачиваются с оформлением блюд. А тормозит у всех. Убедительная просьба к сайтостроителям: добавляйте галочку «убрать все финтифлюшки».
        • 0
          Ценность анимации в данном случае в том что она позволяет имитировать поведение объектов в реальном мире. Часто это делает интерфейсы более понятными. Пример: вы кликаете на ссылку и открывается новое окно, а предыдущее сворачивается в трей. Если окно исчезает постепенно — пользователь может проследить и понять куда оно делось и, что важнее, частности как вызвать его обратно.
    • +3
      Ну, это все делается как «смотрите что можно», а не для реальных применений)
      • +11
        А потом такое случайно попадается на глаза заказчику…
      • –3
        Позвольте не согласиться с Вами! Взять даже к примеру стандартное навигационное меню мобильной версии wordpress'а — унылое выпадающее меню, которое портит вид всего сайта. А теперь представьте на его месте кнопульку из первого примера. Чем не реальное применение?

        PS: кстати, никто не желает создать плагин для вордпресса меняющий стандартное responsive nav menu на gooey menu?
        • +3
          Дайте тогда ещё плагин для браузера, блокирующий загрузку сайтов на вордпрессе с плагином для вордпресса, меняющим стандартное responsive nav menu на gooey menu!

          Firefox со множеством открытых вкладок грузит процессор примерно на 8%, а после добавления вкладки с демонстрацией липкого эффекта начинает жрать больше 85%. И это на нормальном десктопе, а что тогда на мобильных устройствах?
    • 0
      Лично я с этим и не спорю. Но мы же пишем/писали про флекс-бокс, маски, анимации и градиенты когда они работали только на последних билдах ночных браузеров. Тут — тоже самое. Через год или два года данная техника будет идеально отображаться у 90% пользователей.
    • –4
      Ну если делать все через «одно место», конечно будет тормозить.
      Вот к примеру хорошие работа, все как надо, не тормозит, красиво.

      hellomonday.com
      middle-earth.thehobbit.com/map

      Конечно на калькуляторах будет тормозить, но эти сайты не для них.
      У вас видимо свои реалии.

      Даже этот пример с cp не тормозит.
      • +2
        Это ведь сарказм, да?
      • 0
        Надеюсь это не пример хорошего дизайна. А что касается кодинга — таки тормозит.
  • 0
    *удалил сам*
  • +2
    С точки зрения минимизирования вычислений такие эффекты надо решать на уровне операций с контурами с последующей растеризацией. Тогда эти операции были бы быстрыми. Фильтры в данном случае весьма избыточны, медленны и требуют много памяти.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.