将背景过滤器应用于 svg 路径元素

Posted

技术标签:

【中文标题】将背景过滤器应用于 svg 路径元素【英文标题】:Apply backdrop filter to svg path element 【发布时间】:2016-03-06 17:28:04 【问题描述】:

我有一个带有一些背景图片的页面。

在 body 标记中,我有一个 svg 元素,其中只有一个内部路径元素。

如何为路径元素添加背景滤镜,使其可以模糊非矩形形状的背景?

$(function() 

  var pattern = "M0,offsetTop Cax1,power,ax2,power,width,offsetTop Lwidth,height,0,heightZ";

  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>

【问题讨论】:

我相信这是不可能的,获得类似效果的常用技巧是将背景复制到单独的对象中,为其添加过滤器并添加剪辑路径。 也许看here(第二种解决方案)可能会帮助遇到同样问题的人。 将 url 路径/掩码与 rect/custom 交换可能会诡计! 【参考方案1】:

无需对代码进行太多更改,您可以通过在 open 函数中增加 power 和/或减少 offsetTop 来实现。

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 Cax1,power,ax2,power,width,offsetTop Lwidth,height,0,heightZ";

  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)。曲线是这样构建的:

MstartWidth, startHeight q curvePeak, curveHeight, endWidth, endHeight
startWidth - P0 的 x 轴定位:曲线起点的 x 坐标 startHeight - P0 的 y 轴定位:曲线起点的 y 坐标 curvePeak - P1 的 x 轴定位:曲线达到峰值的位置 curveHeight - P1 的 y 轴定位:曲线的高度 endWidth - P2 的 x 轴定位:曲线的尺寸 endHeight - P2 的 y 轴定位:曲线的倾斜度

另请参阅:Quadratic Bézier Curve: Calculate Points 或单击 here 以查看二次贝塞尔曲线的交互式示例。

否定

当使用两个不同的animations 和持续时间时,此解决方案会出现一些问题,就像您的情况一样。

Strong.easeOut : 0.35s Elastic.easeOut : 1.00s

$(function() 

  var pattern = "M0,offsetTop Cax1,power,ax2,power,width,offsetTop Lwidth,height,0,heightZ 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>

正面

相反,它在使用相同的动画和持续时间时效果很好。

Elastic.easeOut:1.00s

$(function() 

  var pattern = "M0,offsetTop Cax1,power,ax2,power,width,offsetTop Lwidth,height,0,heightZ 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>

【讨论】:

不能代表 OP,但我认为这不能回答问题。问题是如何将背景滤镜应用于非矩形形状。我个人尝试了许多方法(边框半径、svg 元素、切口),但在每种方法中,背景过滤器都应用为矩形,而不是您想要的非矩形。 您的解决方案未应用背景过滤器。检查 SVG 形状的背景模糊的问题的屏幕截图。 OP的尝试没有这样做,您的回答也没有。 我对 svg 动画没有任何问题。但问题是如何将背景滤镜应用于非矩形形状。正如我所测试的那样,没有画布和大量魔法就没有机会做到这一点。

以上是关于将背景过滤器应用于 svg 路径元素的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 CSS 将阴影过滤器应用于 SVG 特定元素/路径

如何使用 svg 过滤器应用渐变

如何更改以下 SVG 过滤器,以便将其应用于 HTML 元素中的文本?

动态注入 SVG 过滤器并应用于 HTML

如何将 CSS 过滤器应用于背景图像

如何将 CSS 过滤器应用于背景图像