【问题标题】:Opacity vs visibility attribute and specificity for SVG elementsSVG 元素的不透明度与可见性属性和特异性
【发布时间】:2019-12-14 15:20:33
【问题描述】:

我有一个我创建的 SVG 元素,我想部分地制作动画。第一个动画按预期工作(“绘制”路径以创建文本轮廓),但随后我希望 SVG 的其余部分(填充颜色、渐变、阴影等)淡入。我有以下 CodePen: https://codepen.io/klarson32907/pen/MNQoLo

目前,它可以满足我的要求,但有一个短暂的时刻,整个 SVG 都有opacity: 0;,这很不和谐。到目前为止,我已经尝试将整个 SVG 元素的初始不透明度设置为 0,希望我可以使用更具体的选择器为不透明度设置动画。但是,当我这样做时,不透明度永远不会从 0 改变,即使使用 !important 声明也是如此。提前对代码墙表示抱歉。

谁能解释一下为什么 HTML/CSS 中的特殊性规则不适用于 SVG/CSS?

.draw {
  visibility: visible;
  animation: draw 3s forwards 1;
}

.logoFinal {
  position: absolute;
  left: 50%;
  margin-left: -320px;
  visibility: hidden;
  animation: show 2.5s forwards 3s;
}

 @keyframes draw {
  0% {
    stroke-dasharray: 0 400;
  }
  100% {
    stroke-dasharray: 200 0;
  }
}

@keyframes show {
  0% {
    visibility: visible;
    opacity: 0;
  }
  100% {
    visibility: visible;
    opacity: 1;
  }  
} 
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="640" height="640" class="logoFinal">
  <defs>
    <path d="M330.24 157.71l127.05 127.6-127.6 127.05-127.05-127.6 127.6-127.05z" id="b"/>
    <radialGradient id="c" gradientUnits="userSpaceOnUse" cx="290.77" cy="171.67" r="158.19">
      <stop offset="0%" stop-color="#f2f2f2"/>
      <stop offset="100%" stop-color="#414141"/>
    </radialGradient>
    <path d="M291.55 400c5.18 0 9.92-2.92 12.26-7.55 5.54-10.99 19.39-38.48 41.56-82.45 26.97 44.43 43.82 72.19 50.56 83.3 2.53 4.16 7.04 6.7 11.91 6.7H420l-64.38-110c29.6-59.77 48.1-97.13 55.5-112.08 4.09-8.25-1.91-17.92-11.12-17.92L290 380V160h-2.62c-9.6 0-17.38 7.78-17.38 17.38v206.69c0 8.8 7.13 15.93 15.93 15.93h5.62z" id="e"/>
    <radialGradient id="f" gradientUnits="userSpaceOnUse" cx="238.05" cy="183.42" r="211.69">
      <stop offset="0%" stop-color="#2900d8"/>
      <stop offset="100%"/>
    </radialGradient>
    <path d="M380 275v20l47.55 90h20l-50-100 50-100h-20L380 275z" id="h"/>
    <radialGradient id="i" gradientUnits="userSpaceOnUse" cx="365.61" cy="204.52" r="161.87">
      <stop offset="0%" stop-color="#2900d8"/>
      <stop offset="100%"/>
    </radialGradient>
    <path d="M257.55 275v20L210 385h-20l50-100-50-100h20l47.55 90z" id="k"/>
    <radialGradient id="l" gradientUnits="userSpaceOnUse" cx="271.94" cy="204.52" r="161.87">
      <stop offset="0%" stop-color="#2900d8"/>
      <stop offset="100%"/>
    </radialGradient>
  </defs>
  <filter id="a" x="142.64" y="97.71" width="378.65" height="380.65" filterUnits="userSpaceOnUse">
    <feFlood/>
    <feComposite in2="SourceAlpha" operator="in"/>
    <feGaussianBlur stdDeviation="4.8"/>
    <feOffset dx="4" dy="6" result="afterOffset"/>
    <feFlood flood-color="#000" flood-opacity=".5"/>
    <feComposite in2="afterOffset" operator="in"/>
    <feMorphology operator="dilate" radius="3"/>
    <feComposite in2="SourceAlpha" operator="out"/>
  </filter>
  <path d="M330.24 157.71l127.05 127.6-127.6 127.05-127.05-127.6 127.6-127.05z" fill="#fff" filter="url(#a)"/>
  <use xlink:href="#b" fill="url(#c)"/>
  <filter id="d" x="219" y="109" width="256" height="346" filterUnits="userSpaceOnUse">
    <feFlood/>
    <feComposite in2="SourceAlpha" operator="in"/>
    <feGaussianBlur stdDeviation="4.47"/>
    <feOffset dx="4" dy="4" result="afterOffset"/>
    <feFlood flood-color="#000" flood-opacity=".5"/>
    <feComposite in2="afterOffset" operator="in"/>
    <feMorphology operator="dilate" radius="2"/>
    <feComposite in2="SourceAlpha" operator="out"/>
  </filter>
  <path d="M291.55 400c5.18 0 9.92-2.92 12.26-7.55 5.54-10.99 19.39-38.48 41.56-82.45 26.97 44.43 43.82 72.19 50.56 83.3 2.53 4.16 7.04 6.7 11.91 6.7H420l-64.38-110c29.6-59.77 48.1-97.13 55.5-112.08 4.09-8.25-1.91-17.92-11.12-17.92L290 380V160h-2.62c-9.6 0-17.38 7.78-17.38 17.38v206.69c0 8.8 7.13 15.93 15.93 15.93h5.62z" fill="#fff" filter="url(#d)"/>
  <use class="fill" xlink:href="#e" fill="url(#f)"/>
  <use xlink:href="#e" fill-opacity="0" stroke="#000" stroke-width="2" class="draw"/>
  <filter id="g" x="329" y="134" width="173.55" height="306" filterUnits="userSpaceOnUse">
    <feFlood/>
    <feComposite in2="SourceAlpha" operator="in"/>
    <feGaussianBlur stdDeviation="4.47"/>
    <feOffset dx="4" dy="4" result="afterOffset"/>
    <feFlood flood-color="#000" flood-opacity=".5"/>
    <feComposite in2="afterOffset" operator="in"/>
    <feMorphology operator="dilate" radius="2"/>
    <feComposite in2="SourceAlpha" operator="out"/>
  </filter>
  <path d="M380 275v20l47.55 90h20l-50-100 50-100h-20L380 275z" fill="#fff" filter="url(#g)"/>
  <use class="fill" xlink:href="#h" fill="url(#i)"/>
  <use xlink:href="#h" fill-opacity="0" stroke="#000" stroke-width="2" class="draw"/>
  <g>
    <filter id="j" x="139" y="134" width="173.55" height="306" filterUnits="userSpaceOnUse">
      <feFlood/>
      <feComposite in2="SourceAlpha" operator="in"/>
      <feGaussianBlur stdDeviation="4.47"/>
      <feOffset dx="4" dy="4" result="afterOffset"/>
      <feFlood flood-color="#000" flood-opacity=".5"/>
      <feComposite in2="afterOffset" operator="in"/>
      <feMorphology operator="dilate" radius="2"/>
      <feComposite in2="SourceAlpha" operator="out"/>
    </filter>
    <path d="M257.55 275v20L210 385h-20l50-100-50-100h20l47.55 90z" fill="#fff" filter="url(#j)"/>
    <use class="fill" xlink:href="#k" fill="url(#l)"/>
    <use xlink:href="#k" fill-opacity="0" stroke="#000" stroke-width="2" class="draw"/>
  </g>
</svg>

【问题讨论】:

    标签: css svg css-animations css-specificity


    【解决方案1】:

    我首先对您的 SVG 进行了一些重新格式化。将所有渐变、过滤器和引用路径移动到&lt;defs&gt;。然后根据它们是最终徽标的一部分还是绘制的轮廓对其他元素进行分组。

    一旦你这样做了,CSS 就会变得更加简单明了。你不需要使用visibility。只需设置您想要的初始条件。然后在正确的时间为它们制作动画。

    .logoFinal {
      position: absolute;
      left: 50%;
      margin-left: -320px;
    }
    
    .draw {
      stroke-dasharray: 0 400;
      animation: draw 3s forwards 1s;
    }
    
    .logo {
      opacity: 0;
      animation: show 2.5s forwards 3s;
    }
    
    @keyframes draw {
      0% {
        stroke-dasharray: 0 400;
      }
      100% {
        stroke-dasharray: 200 0;
      }
    }
    
    @keyframes show {
      0% {
        opacity: 0;
      }
      100% {
        opacity: 1;
      }  
    }
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="640" height="640" class="logoFinal">
      <defs>
        <radialGradient id="c" gradientUnits="userSpaceOnUse" cx="290.77" cy="171.67" r="158.19">
          <stop offset="0%" stop-color="#f2f2f2"/>
          <stop offset="100%" stop-color="#414141"/>
        </radialGradient>
        <radialGradient id="f" gradientUnits="userSpaceOnUse" cx="238.05" cy="183.42" r="211.69">
          <stop offset="0%" stop-color="#2900d8"/>
          <stop offset="100%"/>
        </radialGradient>
        <radialGradient id="i" gradientUnits="userSpaceOnUse" cx="365.61" cy="204.52" r="161.87">
          <stop offset="0%" stop-color="#2900d8"/>
          <stop offset="100%"/>
        </radialGradient>
        <radialGradient id="l" gradientUnits="userSpaceOnUse" cx="271.94" cy="204.52" r="161.87">
          <stop offset="0%" stop-color="#2900d8"/>
          <stop offset="100%"/>
        </radialGradient>
    
        <filter id="a" x="142.64" y="97.71" width="378.65" height="380.65" filterUnits="userSpaceOnUse">
          <feFlood/>
          <feComposite in2="SourceAlpha" operator="in"/>
          <feGaussianBlur stdDeviation="4.8"/>
          <feOffset dx="4" dy="6" result="afterOffset"/>
          <feFlood flood-color="#000" flood-opacity=".5"/>
          <feComposite in2="afterOffset" operator="in"/>
          <feMorphology operator="dilate" radius="3"/>
          <feComposite in2="SourceAlpha" operator="out"/>
        </filter>
    
        <filter id="d" x="219" y="109" width="256" height="346" filterUnits="userSpaceOnUse">
          <feFlood/>
          <feComposite in2="SourceAlpha" operator="in"/>
          <feGaussianBlur stdDeviation="4.47"/>
          <feOffset dx="4" dy="4" result="afterOffset"/>
          <feFlood flood-color="#000" flood-opacity=".5"/>
          <feComposite in2="afterOffset" operator="in"/>
          <feMorphology operator="dilate" radius="2"/>
          <feComposite in2="SourceAlpha" operator="out"/>
        </filter>
    
        <filter id="g" x="329" y="134" width="173.55" height="306" filterUnits="userSpaceOnUse">
          <feFlood/>
          <feComposite in2="SourceAlpha" operator="in"/>
          <feGaussianBlur stdDeviation="4.47"/>
          <feOffset dx="4" dy="4" result="afterOffset"/>
          <feFlood flood-color="#000" flood-opacity=".5"/>
          <feComposite in2="afterOffset" operator="in"/>
          <feMorphology operator="dilate" radius="2"/>
          <feComposite in2="SourceAlpha" operator="out"/>
        </filter>
    
        <filter id="j" x="139" y="134" width="173.55" height="306" filterUnits="userSpaceOnUse">
          <feFlood/>
          <feComposite in2="SourceAlpha" operator="in"/>
          <feGaussianBlur stdDeviation="4.47"/>
          <feOffset dx="4" dy="4" result="afterOffset"/>
          <feFlood flood-color="#000" flood-opacity=".5"/>
          <feComposite in2="afterOffset" operator="in"/>
          <feMorphology operator="dilate" radius="2"/>
          <feComposite in2="SourceAlpha" operator="out"/>
        </filter>
    
        <path d="M330.24 157.71l127.05 127.6-127.6 127.05-127.05-127.6 127.6-127.05z" id="b"/>
        <path d="M291.55 400c5.18 0 9.92-2.92 12.26-7.55 5.54-10.99 19.39-38.48 41.56-82.45 26.97 44.43 43.82 72.19 50.56 83.3 2.53 4.16 7.04 6.7 11.91 6.7H420l-64.38-110c29.6-59.77 48.1-97.13 55.5-112.08 4.09-8.25-1.91-17.92-11.12-17.92L290 380V160h-2.62c-9.6 0-17.38 7.78-17.38 17.38v206.69c0 8.8 7.13 15.93 15.93 15.93h5.62z" id="e"/>
        <path d="M380 275v20l47.55 90h20l-50-100 50-100h-20L380 275z" id="h"/>
        <path d="M257.55 275v20L210 385h-20l50-100-50-100h20l47.55 90z" id="k"/>
      </defs>
    
      <g class="logo">
        <path d="M330.24 157.71l127.05 127.6-127.6 127.05-127.05-127.6 127.6-127.05z" fill="#fff" filter="url(#a)"/>
        <use xlink:href="#b" fill="url(#c)"/>
        <path d="M291.55 400c5.18 0 9.92-2.92 12.26-7.55 5.54-10.99 19.39-38.48 41.56-82.45 26.97 44.43 43.82 72.19 50.56 83.3 2.53 4.16 7.04 6.7 11.91 6.7H420l-64.38-110c29.6-59.77 48.1-97.13 55.5-112.08 4.09-8.25-1.91-17.92-11.12-17.92L290 380V160h-2.62c-9.6 0-17.38 7.78-17.38 17.38v206.69c0 8.8 7.13 15.93 15.93 15.93h5.62z" fill="#fff" filter="url(#d)"/>
        <use class="fill" xlink:href="#e" fill="url(#f)"/>
        <path d="M380 275v20l47.55 90h20l-50-100 50-100h-20L380 275z" fill="#fff" filter="url(#g)"/>
        <use class="fill" xlink:href="#h" fill="url(#i)"/>
        <path d="M257.55 275v20L210 385h-20l50-100-50-100h20l47.55 90z" fill="#fff" filter="url(#j)"/>
        <use class="fill" xlink:href="#k" fill="url(#l)"/>
      </g>
    
      <g class="draw">
        <use xlink:href="#e" fill-opacity="0" stroke="#000" stroke-width="2"/>
        <use xlink:href="#h" fill-opacity="0" stroke="#000" stroke-width="2"/>
        <use xlink:href="#k" fill-opacity="0" stroke="#000" stroke-width="2"/>
      </g>
    </svg>

    【讨论】:

    • 我添加了可见性属性作为快捷方式,以确保我想要的“外观”是可行的,但我一直坚持使用不透明度,所以我将它添加到混合中。我可以问一下您如何能够将 SVG 分开并确定可以移动到 defs 的内容吗?我是 SVG 的新手,所以即使是参考链接也会有所帮助。非常感谢!
    • 大部分情况下,我只是将所有滤镜和渐变移至&lt;defs&gt;。那些不是直接渲染的。它们是从 呈现的元素中引用的。大多数 SVG 将它们保留在那里。 &lt;defs&gt; 之外的所有内容我都保持与原始文件中相同的顺序。除了我将徽标部分组合在一个&lt;g&gt; 中,而将“绘制”部分组合在另一个中。
    • 所以如果我理解的话,&lt;path&gt; 元素不会呈现,除非在 &lt;defs&gt; 之外引用?在用笔画、滤镜等“填充”之前,它只是一组空坐标?
    • 是的。 &lt;defs&gt; 部分中的 &lt;path&gt; 不会直接呈现。但它可以通过&lt;use&gt; 引用,然后会被渲染。
    【解决方案2】:

    这里有两个主要问题。

    首先,隐形闪光是有意义的,因为在您为 SVG 的某些部分设置动画之后,您可以在第一步中将整个 SVG 的不透明度设置为零show动画。

    要解决此问题,您需要将选择器更改为仅选择 SVG 中您未在 draw 动画中设置动画的部分。这里的快速而肮脏的选择器类似于.logoFinal defs ~ *:not(.draw),尽管理想情况下您会对此进行一些测试和/或尝试简化 SVG 标记以缩小该选择器以减少您的元素总数立即重新设置动画。

    一旦解决了这个问题,我们就会引入一个新问题,即opacity 将无法在path 上运行。请改用fill-opacity

    把它放在一起:

    .draw {
      visibility: visible;
      animation: draw 3s forwards 1;
    }
    
    .logoFinal {
      position: absolute;
      left: 50%;
      margin-left: -320px;
      visibility: hidden;
      /* animation: show 2.5s forwards 3s; */
    }
    
    .logoFinal defs ~ *:not(.draw) {
      visibility: hidden;
      fill-opacity: 0;
      animation: show 2.5s forwards 3s;
    }
    
     @keyframes draw {
      0% {
        stroke-dasharray: 0 400;
      }
      100% {
        stroke-dasharray: 200 0;
      }
    }
    
    @keyframes show {
      0% {
        visibility: visible;
        fill-opacity: 0;
      }
      100% {
        visibility: visible;
        fill-opacity: 1;
      }  
    }
    

    【讨论】:

    • 这绝对是我遇到的问题的一部分,但第一个响应中的 SVG 重构为我清除了代码。我明白最初的隐形闪光是从哪里来的,它只是我能得到的最接近我脑海中理想动画的地方。我对 SVG 非常陌生,很欣赏有关不透明度与填充不透明度属性的信息。
    • 我也喜欢你使用的狡猾的 CSS 选择器`~ *:not(.draw)`!
    猜你喜欢
    • 2020-06-23
    • 1970-01-01
    • 2012-07-12
    • 2011-11-24
    • 1970-01-01
    • 1970-01-01
    • 2012-08-31
    • 2020-06-10
    • 2012-06-23
    相关资源
    最近更新 更多