{"id":195076,"date":"2015-02-04T09:03:18","date_gmt":"2015-02-04T16:03:18","guid":{"rendered":"http:\/\/css-tricks.com\/?p=195076"},"modified":"2019-02-22T17:34:57","modified_gmt":"2019-02-23T00:34:57","slug":"gooey-effect","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/gooey-effect\/","title":{"rendered":"The Gooey Effect"},"content":{"rendered":"

The following is a post by Lucas Bebber<\/a>. Lucas the originator of some of the most creative effects I’ve ever seen on the web. So much so I couldn’t resist blogging about them<\/a> myself several times<\/a>. Much better this time: we got the man himself to explain how SVG filters work and how you can use them to create a very cool gooey effect.<\/em><\/p>\n

<\/p>\n

A while ago, Chris wrote about Shape Blobbing in CSS<\/a>. The effect is cool and the technique behind it is clever, but the approach, through regular CSS filters, has several drawbacks: no transparency, no content inside the blobs, hard to make it in any color besides black and white, etc.<\/p>\n

However, these days, playing around with SVG filters, I figured I could use them to get around most of the problems of a pure CSS approach. Here you can see a gooey menu I made to demonstrate the effect:<\/p>\n

See the Pen CSS Gooey Menu (Version 1)<\/a> by Lucas Bebber (@lbebber<\/a>) on CodePen<\/a>.<\/p>\n

SVG Filters 101<\/h3>\n

SVG filters are quite powerful. It is a pretty extensive topic. Here we will only cover the basics necessary to understand how this effect works. <\/p>\n

Despite the name, we can apply SVG filters on regular DOM elements through CSS, in most browsers<\/a>. <\/p>\n

This is the basic syntax to define a filter:<\/p>\n

<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" version=\"1.1\">\r\n  <defs>\r\n    <filter id=\"name-your-filter-here\">\r\n      ...          \r\n      <!-- insert filters here -->\r\n      ...\r\n    <\/filter>\r\n    ...\r\n  <\/defs>\r\n<\/svg><\/code><\/pre>\n

To apply a SVG filter to a DOM element:<\/p>\n

.selector {\r\n  filter: url('#name-of-your-filter-here');\r\n\r\n  \/* you can also load filters from external SVGs this way: *\/\r\n  filter: url('filters.svg#name-of-your-other-filter-here');\r\n}<\/code><\/pre>\n

You may need vendor prefixes to use the filter<\/a><\/code> property. <\/p>\n

A <filter><\/code> element contains one or more filter primitives, which are the operations done by the filter, e.g. blur, color transform, shading. A complete list of filter primitives can be found here<\/a>.<\/p>\n

Let’s see a couple of examples:<\/p>\n

See the Pen svg blur demonstration<\/a> by Lucas Bebber (@lbebber<\/a>) on CodePen<\/a>.<\/p>\n

<filter id=\"blur\">\r\n  <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"3\" \/>\r\n<\/filter><\/code><\/pre>\n

This filter will do a single simple 3px blur on the object. Notice the in=\"SourceGraphic\"<\/code> attribute. The in<\/code> attribute defines the input of a filter primitive. SourceGraphic<\/code> is a keyword that returns the original, pre-filter graphic of the element. So what this means is that the input of the blur filter will be the original graphic of the object. Pretty straightforward.<\/p>\n

Now let’s see a common but more complex effect: a drop shadow filter. This will be useful in demonstrating how to chain filter primitives together:<\/p>\n

See the Pen svg drop shadow demonstration<\/a> by Lucas Bebber (@lbebber<\/a>) on CodePen<\/a>.<\/p>\n

<filter id=\"drop-shadow\">\r\n  <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"7\" result=\"shadow\" \/>\r\n  <feOffset in=\"shadow\" dx=\"3\" dy=\"4\" result=\"shadow\" \/>\r\n  <feColorMatrix in=\"shadow\" type=\"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\" \/>\r\n  <feBlend in=\"SourceGraphic\" in2=\"shadow\" \/>\r\n<\/filter><\/code><\/pre>\n

Take a look at the result<\/code> attribute of the first filter and the subsequent in<\/code> attributes. With the result<\/code> attribute you can name the result of a filter and then apply a filter to that result<\/em> instead of the source graphic. This allows you to, in this example, blur an object, darken the blurred object<\/em>, and then shift the position of the blurred and darkened<\/em> object. <\/p>\n

Pay attention to the last element there, the <feBlend><\/code> primitive. It demonstrates that some filter primitives take multiple inputs (the in2<\/code> parameter), and that you can call the SourceGraphic<\/code> keyword multiple times and at any point of the filter. That last filter, in this example, is taking both the SourceGraphic<\/code> keyword and the shadow<\/code> result to put back the original image over the shadow we made.<\/p>\n

Now that the basics of SVG filters are covered, let’s take a look at how to make that gooey effect.<\/p>\n

Making Things Stick<\/h3>\n

The basic technique has been already covered here<\/a>. To recap, the idea is to blur two or more objects together and increase the contrast. Pretty simple and works like a charm:<\/p>\n

See the Pen metaballs demonstration<\/a> by Lucas Bebber (@lbebber<\/a>) on CodePen<\/a>.<\/p>\n

However, as we’ve seen before, this also <\/p>\n

    \n
  1. Messes the colors up, making it hard to do anything other than black and white.<\/li>\n
  2. Blurs the content together, making it unusable.<\/li>\n
  3. The container requires a background, so no transparency.<\/li>\n<\/ol>\n

    All in all, this makes this effect usually unpractical.<\/p>\n

    With SVG filters, though, we can do some things that were not possible with CSS filters alone: we can increase the contrast of only the alpha channel, not changing the colors; and we can, with the SourceGraphic<\/code> keyword we’ve seen before, make the content visible as well. Also, since we’re dealing with the alpha channel, not only it will be transparent, a transparent background is *required*, so be careful with that.<\/p>\n

    So this is the basic code:<\/p>\n

    <filter id=\"goo\">\r\n  <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"10\" result=\"blur\" \/>\r\n  <feColorMatrix in=\"blur\" type=\"matrix\" values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 18 -7\" result=\"goo\" \/>\r\n  <feBlend in=\"SourceGraphic\" in2=\"goo\" \/>\r\n<\/filter><\/code><\/pre>\n

    It’s quite short, let’s break it down:<\/p>\n

      \n
    1. First, we apply a 10px blur to the SourceGraphic<\/code> and name that result.<\/li>\n
    2. Then, to the previous result, we apply a color matrix filter in order to increase the contrast of the alpha channel.<\/li>\n
    3. Finally, we insert the original graphics over the effect we made.<\/li>\n<\/ol>\n

      About Color Matrices<\/h3>\n

      If you haven’t used a color matrix filter before, it might need some explanation. You can think of it as a table of four rows and five columns. It looks like this:<\/p>\n

         | R | G | B | A | +\r\n---|-------------------\r\n R | 1 | 0 | 0 | 0 | 0\r\n---|-------------------\r\n G | 0 | 1 | 0 | 0 | 0\r\n---|-------------------\r\n B | 0 | 0 | 1 | 0 | 0\r\n---|-------------------\r\n A | 0 | 0 | 0 | 1 | 0\r\n---|-------------------<\/code><\/pre>\n

      Each row represents a channel (red, green, blue and alpha) and is used to set the channel’s value. Each of the first four columns represents a channel as well, and they return the current value of their respective channels. A number in a cell, then, adds to its row channel the result of the multiplication of that number by the current value of the channel represented by its column. For example, a 0.5 on the row R, column G, will, for each pixel, add to the red channel the current value of green*0.5. The last column doesn’t represent any channel and is used for addition\/subtraction, meaning that a number there will add to its channel its value multiplied by 255.<\/p>\n

      That’s a lengthy explanation, but using the filter is quite simple. In our case, since we are only increasing the contrast of the alpha channel, our matrix will look like this:<\/p>\n

         | R | G | B | A | +\r\n---|-------------------\r\n R | 1 | 0 | 0 | 0 | 0\r\n---|-------------------\r\n G | 0 | 1 | 0 | 0 | 0\r\n---|-------------------\r\n B | 0 | 0 | 1 | 0 | 0\r\n---|-------------------\r\n A | 0 | 0 | 0 |18 |-7\r\n---|-------------------<\/code><\/pre>\n

      This leaves the RGB channels unmodified, multiplies the value of the alpha channel by 18, and then subtracts 7*255 from that value, effectively increasing the contrast of the transparency alone. These values can be tweaked to your needs.<\/p>\n

      To apply this matrix to our feColorMatrix<\/code> filter, all we have to do is write these numbers sequentially, like this:<\/p>\n

      values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 18 -7\"<\/code><\/pre>\n

      Demo<\/h3>\n

      And with that we have our basic effect ready! Here is it:<\/p>\n

      See the Pen svg goo effect demonstration<\/a> by Lucas Bebber (@lbebber<\/a>) on CodePen<\/a>.<\/p>\n

      You can then customize it to your needs, like adding a drop shadow, using different colors for each element, or whatever have you! <\/p>\n

      Considerations<\/h3>\n