SVG 元素的不透明度与可见性属性和特异性

Opacity vs visibility attribute and specificity for SVG elements

我创建了一个 SVG 元素,我想对其进行动画处理。第一个动画按预期工作('draw' 创建文本轮廓的路径),但随后我希望 SVG 的其余部分(填充颜色、渐变、阴影等)淡入。我有以下内容代码笔: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>

这里有两个主要问题。

首先,隐形闪光是有道理的,因为在你对 SVG 的某些部分进行动画处理之后,你可以将 整个 SVG 的不透明度设置为零show 动画的第一步。

要解决此问题,您需要将 selector 更改为仅 select 您未在 draw 动画中制作动画的 SVG 部分。一个快速而肮脏的 select 或者这里会是 .logoFinal defs ~ *:not(.draw) 之类的东西,尽管理想情况下你会用这个 and/or 做一些测试尝试简化 SVG 标记以缩小 select 或向下以减少一次设置动画的元素总数。

一旦解决了这个问题,我们就会引入一个新问题,即 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 格式。将所有渐变、过滤器和参考路径移动到 <defs> 中。然后根据其他元素是最终徽标的一部分还是绘制的轮廓对其他元素进行分组。

一旦你这样做了,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>