23

I have a page with some background image.

In body tag I have a svg element with only one inner path element.

How to add backdrop-filter to path element so it could blur background in non-rectangular shape?

svg path backdrop-filter scheme

$(function() {

  var pattern = "M0,{offsetTop} C{ax1},{power},{ax2},{power},{width},{offsetTop} L{width},{height},0,{height}Z";

  var $svg = $('svg#footer');
  var $path = $svg.find('path');

  var settings = {
    width: 1200,
    height: 200,
    offsetTop: 200,
    power: 200
  }

  settings.ax1 = settings.width / 3 * 1;
  settings.ax2 = settings.width / 3 * 2;

  function render() {
    var newPath = pattern;
    for (var i in settings) {
      newPath = newPath.split('{' + i + '}').join(settings[i]);
    }
    $path.attr('d', newPath);
  }

  TweenMax.set($svg, {
    force3D: true
  })

  var opened = false;

  function open() {
    if (opened) {
      return
    }
    opened = true;
    TweenMax.to(settings, 0.35, {
      overwrite: true,
      offsetTop: 80,
      ease: Strong.easeOut,
      onUpdate: render
    })
    TweenMax.to(settings, 1, {
      power: 80,
      ease: Elastic.easeOut,
      onUpdate: render
    })
  }

  function close() {
    if (!opened) {
      return
    }
    opened = false;
    TweenMax.to(settings, 0.35, {
      overwrite: true,
      offsetTop: 200,
      ease: Back.easeIn,
      onUpdate: render
    })
    TweenMax.to(settings, 0.35, {
      power: 200,
      delay: 0.15,
      ease: Back.easeOut,
      onUpdate: render
    })
  }

  $(window).on('mousedown touchstart', function(e) {
    opened ? close() : open();
  })

  open();
})
html,
body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
}

body {
  background-image: url('http://i839.photobucket.com/albums/zz314/mrkanpuc/stuffs/1PZ1.jpg');
  background-repeat: no-repeat;
  background-size: cover;
}

svg {
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 200px;
}

svg path {
  fill: rgba(0, 0, 0, 0.5);
}
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/TweenMax.min.js"></script>

<svg id="footer" viewBox="0 0 1200 200" preserveAspectRatio="none"><path/></svg>
Paolo Forgia
  • 6,572
  • 8
  • 46
  • 58
  • 2
    i believe this is not possible, a common trick to get something like this is to copy your background into a separate object, add a filter to that and add a clip path. – ZPiDER Jun 22 '17 at 14:10
  • Maybe looking [here](https://stackoverflow.com/questions/58133329/how-to-use-css-backdrop-filter-on-text/63252650#63252650) (**the second solution**) may help someone with the same problem.
    Swapping the url path/mask with rect/custom one may do the trick !
    – Cristian Davide Conte Aug 07 '20 at 16:48

1 Answers1

8

Without doing too many changes to your code, you can achieve that by increasing your power and/or decreasing your offsetTop in the open function.

TweenMax.to(settings, 0.35, {overwrite: true, offsetTop: 80, ease: Strong.easeOut, onUpdate: render })
TweenMax.to(settings, 1, {power: 120, ease: Elastic.easeOut, onUpdate: render })

$(function() {

  var pattern = "M0,{offsetTop} C{ax1},{power},{ax2},{power},{width},{offsetTop} L{width},{height},0,{height}Z";

  var $svg = $('svg#footer');
  var $path = $svg.find('path');

  var settings = {
    width: 1200,
    height: 200,
    offsetTop: 200,
    power: 200
  }

  settings.ax1 = settings.width / 3 * 1;
  settings.ax2 = settings.width / 3 * 2;

  function render() {
    var newPath = pattern;
    for (var i in settings) {
      newPath = newPath.split('{' + i + '}').join(settings[i]);
    }
    $path.attr('d', newPath);
  }

  TweenMax.set($svg, {
    force3D: true
  })

  var opened = false;

  function open() {
    if (opened) {
      return
    }
    opened = true;
    TweenMax.to(settings, 0.35, {
      overwrite: true,
      offsetTop: 80,
      ease: Strong.easeOut,
      onUpdate: render
    })
    TweenMax.to(settings, 1, {
      power: 150,
      ease: Elastic.easeOut,
      onUpdate: render
    })
  }

  function close() {
    if (!opened) {
      return
    }
    opened = false;
    TweenMax.to(settings, 0.35, {
      overwrite: true,
      offsetTop: 200,
      ease: Back.easeIn,
      onUpdate: render
    })
    TweenMax.to(settings, 0.35, {
      power: 200,
      delay: 0.15,
      ease: Back.easeOut,
      onUpdate: render
    })
  }

  $(window).on('mousedown touchstart', function(e) {
    opened ? close() : open();
  })

  open();
})
html,
body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
}

body {
  background-image: url('http://i839.photobucket.com/albums/zz314/mrkanpuc/stuffs/1PZ1.jpg');
  background-repeat: no-repeat;
  background-size: cover;
}

svg {
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 200px;
}

svg path {
  fill: rgba(0, 0, 0, 0.5);
}
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/TweenMax.min.js"></script>

<svg id="footer" viewBox="0 0 1200 200" preserveAspectRatio="none"><path/></svg>

Quadratic Bézier curve

Another solution is to add a curved path (called quadratic Bézier curve) to your rectangle. The curve is built like this:

M{startWidth}, {startHeight} q {curvePeak}, {curveHeight}, {endWidth}, {endHeight}
  • startWidth - x-axis positioning of P0: x coordinate where the curve starts
  • startHeight - y-axis positioning of P0: y coordinate where the curve starts
  • curvePeak - x-axis positioning of P1: where the curve reach it's peak
  • curveHeight - y-axis positioning of P1: height of the curve
  • endWidth - x-axis positioning of P2: dimension of the curve
  • endHeight - y-axis positioning of P2: inclination of the curve

See also: Quadratic Bézier Curve: Calculate Points or click here for an interactive example of the quadratic Bézier curve.

Negative

This solution has some problems when using two different animations and duration, like in your case.

$(function() {

  var pattern = "M0,{offsetTop} C{ax1},{power},{ax2},{power},{width},{offsetTop} L{width},{height},0,{height}Z q 600, 100, 1200, 0";

  var $svg = $('svg#footer');
  var $path = $svg.find('path');

  var settings = {
    width: 1200,
    height: 200,
    offsetTop: 200,
    power: 200
  }

  settings.ax1 = settings.width / 3 * 1;
  settings.ax2 = settings.width / 3 * 2;

  function render() {
    var newPath = pattern;
    for (var i in settings) {
      newPath = newPath.split('{' + i + '}').join(settings[i]);
    }
    $path.attr('d', newPath);
  }

  TweenMax.set($svg, {
    force3D: true
  })

  var opened = false;

  function open() {
    if (opened) {
      return
    }
    opened = true;
    TweenMax.to(settings, 0.35, {
      overwrite: true,
      offsetTop: 80,
      ease: Strong.easeOut,
      onUpdate: render
    })
    TweenMax.to(settings, 1, {
      power: 80,
      ease: Elastic.easeOut,
      onUpdate: render
    })
  }

  function close() {
    if (!opened) {
      return
    }
    opened = false;
    TweenMax.to(settings, 0.35, {
      overwrite: true,
      offsetTop: 200,
      ease: Back.easeIn,
      onUpdate: render
    })
    TweenMax.to(settings, 0.35, {
      power: 200,
      delay: 0.15,
      ease: Back.easeOut,
      onUpdate: render
    })
  }

  $(window).on('mousedown touchstart', function(e) {
    opened ? close() : open();
  })

  open();
})
html,
body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
}

body {
  background-image: url('http://i839.photobucket.com/albums/zz314/mrkanpuc/stuffs/1PZ1.jpg');
  background-repeat: no-repeat;
  background-size: cover;
}

svg {
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 200px;
}

svg path {
  fill: rgba(0, 0, 0, 0.5);
}
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/TweenMax.min.js"></script>

<svg id="footer" viewBox="0 0 1200 200" preserveAspectRatio="none"><path/></svg>

Positive

On the contrary it works great when using the same animation and duration.

Both with Elastic.easeOut : 1.00s

$(function() {

  var pattern = "M0,{offsetTop} C{ax1},{power},{ax2},{power},{width},{offsetTop} L{width},{height},0,{height}Z q 600, 100, 1200, 0";

  var $svg = $('svg#footer');
  var $path = $svg.find('path');

  var settings = {
    width: 1200,
    height: 200,
    offsetTop: 200,
    power: 200
  }

  settings.ax1 = settings.width / 3 * 1;
  settings.ax2 = settings.width / 3 * 2;

  function render() {
    var newPath = pattern;
    for (var i in settings) {
      newPath = newPath.split('{' + i + '}').join(settings[i]);
    }
    $path.attr('d', newPath);
  }

  TweenMax.set($svg, {
    force3D: true
  })

  var opened = false;

  function open() {
    if (opened) {
      return
    }
    opened = true;
    TweenMax.to(settings, 1, {
      overwrite: true,
      offsetTop: 80,
      ease: Elastic.easeOut,
      onUpdate: render
    })
    TweenMax.to(settings, 1, {
      power: 80,
      ease: Elastic.easeOut,
      onUpdate: render
    })
  }

  function close() {
    if (!opened) {
      return
    }
    opened = false;
    TweenMax.to(settings, 0.35, {
      overwrite: true,
      offsetTop: 200,
      ease: Back.easeIn,
      onUpdate: render
    })
    TweenMax.to(settings, 0.35, {
      power: 200,
      ease: Back.easeIn,
      onUpdate: render
    })
  }

  $(window).on('mousedown touchstart', function(e) {
    opened ? close() : open();
  })

  open();
})
html,
body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
}

body {
  background-image: url('http://i839.photobucket.com/albums/zz314/mrkanpuc/stuffs/1PZ1.jpg');
  background-repeat: no-repeat;
  background-size: cover;
}

svg {
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 200px;
}

svg path {
  fill: rgba(0, 0, 0, 0.5);
}
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/TweenMax.min.js"></script>

<svg id="footer" viewBox="0 0 1200 200" preserveAspectRatio="none"><path/></svg>
Paolo Forgia
  • 6,572
  • 8
  • 46
  • 58
  • 3
    Can't speak for the OP, but I don't think this answers the question. The question is how to apply backdrop-filter to a non-rectangular shape. I personally tried many approaches (border radius, svg element, cutout) but in each approach, back-drop-filter is applied as a rectangular shape, not the non-rectangular shape you intend. – Fer Jun 16 '17 at 15:57
  • 1
    Your solution does not apply a back-drop filter. Check the screenshot of the question where the backdrop of the SVG shape is blurred. The OP's attempt does not do that, nor does your answer. – Fer Jun 19 '17 at 17:09
  • I have no problems with svg animations. But the question is how to apply backdrop-filter to a non-rectangular shape. As i tested there is no chances to do that without canvas and lots of magic. – Michael Chistyakov Jun 26 '17 at 05:35