【问题标题】:SVG filter: different result depending on browserSVG过滤器:不同的结果取决于浏览器
【发布时间】:2017-09-05 03:10:43
【问题描述】:

我正在尝试将point light effect 添加到SVG 矩形。问题是我得到了不同的结果,具体取决于我使用的浏览器。例如,在 Chrome 和 Safari 中,我得到了以下信息:

如何在不同浏览器上使用 svg 过滤器获得一致的结果?

*, *:before, *:after {
  box-sizing: border-box;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.css" rel="stylesheet"/>



<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <filter id="customPointLight">
      <feSpecularLighting result="lightBuffer" specularConstant="1.5"
          specularExponent="80" lighting-color="#fff">
        <fePointLight x="100" y="100" z="80"/>
      </feSpecularLighting>
      <feComposite in="SourceGraphic" in2="lightBuffer" operator="out"
          k1="0" k2="1" k3="1" k4="0"/>
    </filter>
  </defs>

  <rect x="50" y="50" width="100" height="100" fill="blue" filter="url(#customPointLight)"></rect>
  
</svg>

【问题讨论】:

    标签: svg lighting svg-filters


    【解决方案1】:

    Safari 会自动选择不正确的过滤器分辨率,可能是因为没有人费心为视网膜显示器更新代码。您可以通过将 filterRes="200" 添加到过滤器元素来让 Safari 做“大部分”正确的事情,因为它还没有放弃对 filterRes 的支持。

    也就是说,今天跨浏览器的正确做法是完全打开光源,只使用一个填充了作为数据导入的黑白径向渐变的矩形:URI 和 feImage(用于 Firefox 和 Edge兼容性)。正如我认为你想要的那样,屏幕混合会将白色高光添加到原件中。像这样:

    svg {
    background: red;
    }
    <svg width="400px" height="200px" xmlns="http://www.w3.org/2000/svg"
        xmlns:xlink="http://www.w3.org/1999/xlink">
      <defs>
         <radialGradient id="lightHack">
          <stop offset="35%" stop-color="white"/>
          <stop offset="80%" stop-color="black"/>
        </radialGradient>
        
        <filter id="customPointLight">
          <feSpecularLighting result="lightBuffer" specularConstant="1.5"
              specularExponent="80" lighting-color="#fff">
            <fePointLight x="100" y="100" z="80"/>
          </feSpecularLighting>
          <feComposite in="SourceGraphic" in2="lightBuffer" operator="out"
              k1="0" k2="1" k3="1" k4="0"/>
        </filter>
        
        <filter id="pointLightHack" x="0%" y="0%" width="100%" height="100%">
           <feImage width="100" height="100" xlink:href="data:image/svg+xml;charset=utf-8;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgdmlld0JveD0iMCAwIDEwMCAxMDAiDQogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPg0KDQogIDxkZWZzPg0KICAgIDxyYWRpYWxHcmFkaWVudCBpZD0iZXhhbXBsZUdyYWRpZW50Ij4NCiAgICAgIDxzdG9wIG9mZnNldD0iNDAlIiBzdG9wLWNvbG9yPSJ3aGl0ZSIvPg0KICAgICAgPHN0b3Agb2Zmc2V0PSI3NSUiIHN0b3AtY29sb3I9ImJsYWNrIi8+DQogICAgPC9yYWRpYWxHcmFkaWVudD4NCiAgPC9kZWZzPg0KICA8Y2lyY2xlIGZpbGw9InVybCgjZXhhbXBsZUdyYWRpZW50KSIgY3g9IjUwIiBjeT0iNTAiIHI9IjUwIi8+DQo8L3N2Zz4="/>
          <feBlend mode="screen" in="SourceGraphic"/>
        </filter>
      </defs>
    
      <rect x="50" y="50" width="100" height="100" fill="blue" filter="url(#customPointLight)"/>
      <rect x="250" y="50" height="100" width="100" fill="blue" filter="url(#pointLightHack)"/>
    </svg>
    
      <!-- SVG source of the base64 encoded feImage -->
    
      <svg width="100" height="100" viewBox="0 0 100 100"
       xmlns="http://www.w3.org/2000/svg">
    
      <defs>
        <radialGradient id="exampleGradient">
          <stop offset="40%" stop-color="white"/>
          <stop offset="75%" stop-color="black"/>
        </radialGradient>
      </defs>
      <circle fill="url(#exampleGradient)" cx="50" cy="50" r="50"/>
    </svg>

    顺便说一句,您没有正确使用光照效果,镜面光照应该添加“闪亮”的高光,因此正确的用法是将结果合成在光源之上。漫射照明应该添加“常规”光,并且应该与原始图形相乘。在这两种情况下,您都不应该使用“out”复合操作 - 这是在矩形上打一个透明孔,正如您在上面添加红色背景时所看到的那样。

    【讨论】:

    【解决方案2】:

    对于在计算中使用相邻像素的所有滤镜,例如feSpecularLightingfeGaussianBlurfeConvolveMatrix,其结果受属性filterRes 的影响,该属性定义了计算滤镜效果的分辨率。与其他属性不同,specification 没有定义默认值:

    如果未提供,则用户代理将使用合理的值在输出设备上产生高质量的结果。

    这为 UA 之间的许多差异留下了空间。

    feSpecularLighting 本身有一个属性kernelUnitLength 明确引用过滤器分辨率:

    为了在显示媒体和用户代理之间实现某种程度的一致性(原文如此!),有必要为 'filterRes''kernelUnitLength'.

    【讨论】:

    • filterRes 已过时,Chrome 和 Firefox 都不再支持它。
    • 那么你现在如何处理一致性?
    • 根据stackoverflow.com/questions/44891524/…,这是一个与 Safari 相关的已知未解决错误。可悲的是,目前没有修复。我认为解决此问题的唯一方法是为 Safari 编写特定代码,直到浏览器团队修复该错误..
    • kernelUnitLength AFAIK 也已弃用。
    【解决方案3】:

    现在解决了添加一个带有模糊原语的圆圈,它给出了类似的效果,并且似乎可以在浏览器中正确呈现。

    *, *:before, *:after {
      box-sizing: border-box;
    }
    <link href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.css" rel="stylesheet"/>
    
    <svg width="200" height="200" xmlns="http://www.w3.org/2000/svg"
        xmlns:xlink="http://www.w3.org/1999/xlink">
      <defs>
        <filter id="blur">
          <feGaussianBlur in="SourceGraphic" stdDeviation="4"></feGaussianBlur>
        </filter>
      </defs>
    
      <rect x="50" y="50" width="100" height="100" fill="blue""></rect>
      <circle cx="100" cy="100" r="20" fill="#fff" filter="url(#blur)"></circle>	
      
    </svg>

    【讨论】:

      猜你喜欢
      • 2019-09-25
      • 1970-01-01
      • 2015-01-02
      • 1970-01-01
      • 2018-11-12
      • 2014-12-22
      • 2015-01-25
      • 2019-09-22
      • 1970-01-01
      相关资源
      最近更新 更多