Меню с SVG фильтрами (Goo effect)

248
13 марта 2018, 01:04

Есть меню, которое реализовано на HTML/CSS. Мне пришла идея сделать его совместно с SVGфильтрами, а конкретно с эффектом "вязкости" (Goo) для каждого элемента меню.

1. Пример с Goo:

2. Меню, которое нужно сделать с таким эффектом:

Вопрос: Как правильно применить фильтры для этого меню?

Answer 1

Фильтры SVG - это довольно огромная тема.
Одни из самых широко применяемых - <feGaussianBlur/>, который присутствует также в CSS ( filter: blur(N) ), <feColorMatrix/>, <feBlend>, <feComposite/>, <feImage/>, <feMerge/> и так далее.

В данном случае мы будем применять <feGaussianBlur/>, <feColorMatrix/> и <feComposite/>.

Первый шаг:

  • Возьмём для начала "каркас":

$(".goo-button").on("click", function() { 
  $(".goo-button").toggleClass("active"); 
  $(".goo-button span").toggleClass("active"); 
  $(".circle").toggleClass("goo-active"); 
});
* { 
  margin: 0; 
  padding: 0; 
} 
 
a { 
  font-size: 1.5em; 
  color: #fff; 
} 
 
.wrapper { 
  position: relative; 
  margin: 15px; 
} 
 
.goo-button { 
  position: relative; 
  background-color: #0066ff; 
  width: 80px; 
  height: 80px; 
  border-radius: 50%; 
  cursor: pointer; 
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.7); 
  transition: ease-out 200ms; 
} 
 
.goo-button.active { 
  transform: scale(0.8); 
} 
 
.goo-menu span { 
  position: absolute; 
  display: block; 
  width: 40px; 
  height: 4px; 
  background-color: #ffffff; 
  margin: 4px; 
  transition: all 0.5s; 
} 
 
.goo-menu span:first-child { 
  top: 26px; 
  left: 15px; 
} 
 
.goo-menu span:nth-child(2) { 
  top: 36px; 
  left: 15px; 
} 
 
.goo-menu span:nth-child(3) { 
  top: 46px; 
  left: 15px; 
} 
 
.goo-menu span.active:first-child { 
  top: 36px; 
  transform: rotate(45deg); 
} 
 
.goo-menu span.active:nth-child(2) { 
  opacity: 0; 
  transition: opacity 0.3s; 
} 
 
.goo-menu span.active:nth-child(3) { 
  top: 36px; 
  transform: rotate(-45deg); 
} 
 
.circle { 
  display: flex; 
  justify-content: center; 
  align-items: center; 
  width: 4em; 
  height: 4em; 
  background: #0066ff; 
  border-radius: 50%; 
  position: absolute; 
  top: 8px; 
  left: 8px; 
  z-index: -1; 
  transition: ease-out 200ms; 
  cursor: pointer; 
} 
 
.c1.goo-active { 
  top: 105px; 
  left: 20px; 
  transition-delay: 0.1s; 
} 
 
.c2.goo-active { 
  top: 20px; 
  left: 105px; 
  transition-delay: 0.3s; 
} 
 
.c3.goo-active { 
  top: 80px; 
  left: 80px; 
  transition-delay: 0.2s; 
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css"> 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
<div class="wrapper"> 
  <div class="goo-menu"> 
    <div class="goo-button"> 
      <span></span> 
      <span></span> 
      <span></span> 
    </div> 
    <div class="circle c1"><a href="#"><i class="fa fa-pinterest"></i></a></div> 
    <div class="circle c2"><a href="#"><i class="fa fa-facebook"></i></a></div> 
    <div class="circle c3"><a href="#"><i class="fa fa-twitter"></i></a></div> 
  </div> 
</div>

Второй шаг:

  • Теперь нам нужно использовать сами фильтры, но перво-наперво немного теории.

    SVG фильтры модифицируют графические объекты. Каждый элемент фильтра содержит в себе набор примитивов фильтров, которые выполняют определённую графическую операцию. Мы можем использовать результат операции как входной сигнал для другого фильтра, создавая ограниченный охват возможностей для эффектов.

  • Самый обычный пример с использованием фильтра <feGaussianBlur/>:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="300" height="250"> 
  <defs> 
    <filter id="blurEffect"> 
      <feGaussianBlur in="SourceGraphic" stdDeviation="5 3" /> 
      <!--5 - горизонтальное, 3 - вертикальное размытие --> 
    </filter> 
  </defs> 
  <rect x="20" y="20" width="250" height="150" fill="blue" filter="url(#blurEffect)" />   
</svg>

Фильтры для HTML-элементов подключаются таким образом:

.elem{
  -webkit-filter: url("#filter");
  filter: url("#filter");
}

Третий шаг:

  • После того, как мы разобрались, можно приступать к созданию эффекта "вязкости (или липкости).

    В последнем фрагменте кода мы использовали 3 операции:

    1. <feGaussianBlur/> для создания размытия
    2. <feColorMatrix/> для увеличения контрастности альфа-канала
    3. <feComposite/> для видимости содержимого

$(".goo-button").on("click", function() { 
  $(".goo-button").toggleClass("active"); 
  $(".goo-button span").toggleClass("active"); 
  $(".circle").toggleClass("goo-active"); 
});
* { 
  margin: 0; 
  padding: 0; 
} 
 
a { 
  font-size: 1.5em; 
  color: #fff; 
} 
 
.wrapper { 
  position: relative; 
  margin: 15px; 
} 
 
 
/*Подключаем наши фильтры*/ 
 
.goo-menu { 
  -webkit-filter: url(#gooEffect"); 
  filter: url("#gooEffect"); 
} 
 
.goo-button { 
  position: relative; 
  background-color: #0066ff; 
  width: 80px; 
  height: 80px; 
  border-radius: 50%; 
  cursor: pointer; 
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.7); 
} 
 
.goo-button.active { 
  transform: scale(0.8); 
} 
 
.goo-menu span { 
  position: absolute; 
  display: block; 
  width: 40px; 
  height: 4px; 
  background-color: #ffffff; 
  margin: 4px; 
  transition: all 400ms; 
} 
 
.goo-menu span:first-child { 
  top: 26px; 
  left: 15px; 
} 
 
.goo-menu span:nth-child(2) { 
  top: 36px; 
  left: 15px; 
} 
 
.goo-menu span:nth-child(3) { 
  top: 46px; 
  left: 15px; 
} 
 
.goo-menu span.active:first-child { 
  top: 36px; 
  transform: rotate(45deg); 
} 
 
.goo-menu span.active:nth-child(2) { 
  opacity: 0; 
  transition: opacity 300ms; 
} 
 
.goo-menu span.active:nth-child(3) { 
  top: 36px; 
  transform: rotate(-45deg); 
} 
 
.circle { 
  display: flex; 
  justify-content: center; 
  align-items: center; 
  width: 4em; 
  height: 4em; 
  background: #0066ff; 
  border-radius: 50%; 
  position: absolute; 
  top: 8px; 
  left: 8px; 
  z-index: -1; 
  transition: ease-out 200ms; 
  cursor: pointer; 
} 
 
.c1.goo-active { 
  top: 105px; 
  left: 20px; 
  transition-delay: 100ms; 
} 
 
.c2.goo-active { 
  top: 20px; 
  left: 105px; 
  transition-delay: 300ms; 
} 
 
.c3.goo-active { 
  top: 80px; 
  left: 80px; 
  transition-delay: 200ms; 
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css"> 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
<div class="wrapper"> 
  <div class="goo-menu"> 
    <div class="goo-button"> 
      <span></span> 
      <span></span> 
      <span></span> 
    </div> 
    <div class="circle c1"><a href="#"><i class="fa fa-pinterest"></i></a></div> 
    <div class="circle c2"><a href="#"><i class="fa fa-facebook"></i></a></div> 
    <div class="circle c3"><a href="#"><i class="fa fa-twitter"></i></a></div> 
  </div> 
</div> 
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/2000/svg" version="1.1"> 
  <defs> 
    <filter id="gooEffect"> 
      <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" /> 
      <feComposite in="SourceGraphic" result="mix"/> 
    </filter> 
  </defs> 
</svg>

P.S. Воздерживайтесь от применения этих фильтров на больших площадях, так как они достаточно ресурсоёмкие.

READ ALSO
Фон, вылезающий за обложку

Фон, вылезающий за обложку

Как сделать этот синий фон в логотипе, который вылезает слева за wrapper?

175
Плавно растянуть div

Плавно растянуть div

в контейнер div с классомmessage добавляется другие div по средствам ajax как сделать что бы при добавлении новых элементов контейнер

251
Съезжает блок при добавлении текста

Съезжает блок при добавлении текста

Сорян за тупой вопрос, но почему блок съезжает вниз когда добавляю в него текст? И как исправить?

249
Как реализовать блок с такой рамкой

Как реализовать блок с такой рамкой

Подскажите, как реализовать блок с такой рамкой

186