【问题标题】:SVG Background Shaking when replaced更换时 SVG 背景抖动
【发布时间】:2020-06-24 18:43:38
【问题描述】:

我有一个带有 SVG 背景的 div。 div 的高度和宽度不会改变。唯一改变的是当 div 悬停时用于背景的 SVG 文件。

问题似乎在于,当 SVG 背景被替换时(即使在资源预加载之后),图像似乎在固定到位之前“摇晃”。我已经三重检查,两个 SVG 资源的高度和宽度以及视口完全相同,唯一的区别是颜色。

作为参考,这个问题可以在这个页面上看到:https://tqt.uwaterloo.ca/

将鼠标悬停在“汉堡包”图标上时,可以看到问题。 将鼠标悬停在“搜索”图标上时没有问题,但是“搜索”图标上有完全相同的 SVG 替换,并且可以按预期工作。

最后说明:此问题只能在 Retina (2x+) 显示器上重现。

【问题讨论】:

  • 解决您的问题的一个简单方法是消除过渡。如果您需要保持过渡,您可以使用内联 svg 并过渡路径的填充而不是更改图像
  • @enxaneta 我已经删除了过渡 CSS 属性,并没有发现任何区别。使用内联 SVG 和过渡填充的建议是个好主意。如果我无法通过替换背景图像获得可行的解决方案,我会探索一下!

标签: css svg retina-display


【解决方案1】:

这里有两个错误,一个在 Blink(基于 Chrome 和 Chromium 的浏览器)中,一个在 webkit 中,都是由 background-image 属性的转换引起的。

以下是这些错误的最小重现:

const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 34 26">
<path d="M0,0h34v4H0V0z M0,22h34v3.9H0V22z M0,11h34v4H0V11z" fill="black"/>
</svg>`;
const url = 'url(data:image/svg+xml,' + encodeURIComponent( svg ) + ')';
const urls = [ url, url.replace( 'black', 'red' ) ];
let i = 0;
setInterval(() =>
  document.querySelector( '.burger' ).style.backgroundImage = urls[ (++i % 2) ],
  500
);
.burger {
  height: 30px;
  width: 100px;
  background-position: center;
  background-repeat: no-repeat;
  transition: background-image .2s linear;
}
<div class="burger">
</div>

Chrome 的错误是由于您的 svg 文件没有自己的宽度和高度属性,设置一个将修复它。

Safari 错误是由视网膜缩放引起的,他们也奇怪地在其上应用了过渡...对于这个问题,修复会更难,但设置正确的高度会使其不那么明显,因为我们只有抗锯齿伪影移动。

这里是与上面相同的 sn-p,只是设置了 heightwidth 属性:

const svg = `<svg width="34" height="26" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 34 26">
<path d="M0,0h34v4H0V0z M0,22h34v3.9H0V22z M0,11h34v4H0V11z" fill="black"/>
</svg>`;
const url = 'url(data:image/svg+xml,' + encodeURIComponent( svg ) + ')';
const urls = [ url, url.replace( 'black', 'red' ) ];
let i = 0;
setInterval(() =>
  document.querySelector( '.burger' ).style.backgroundImage = urls[ (++i % 2) ],
  500
);
.burger {
  height: 30px;
  width: 100px;
  background-position: center;
  background-repeat: no-repeat;
  transition: background-image .2s linear;
}
<div class="burger">
</div>

现在,可能应该注意,如果只针对最近的浏览器对您来说不是问题,您可以通过仅使用 CSS 过滤器来实现相同的效果,节省一个网络请求:

const svg = `<svg width="34" height="26" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 34 26">
<path d="M0,0h34v4H0V0z M0,22h34v3.9H0V22z M0,11h34v4H0V11z"/>
</svg>`;
// This time we generate only a single black url
const url = 'url(data:image/svg+xml,' + encodeURIComponent( svg ) + ')';
document.querySelector( '.burger' ).style.backgroundImage = url;
.burger {
  height: 30px;
  width: 100px;
  background-position: center;
  background-repeat: no-repeat;
  transition: filter .2s linear;
}
.burger:hover {
  /*
    Using formula from 
    https://stackoverflow.com/a/43959856/3702797
    to safely fallback on black for browsers withtou support for filters
  */
  filter: invert(10%) sepia(100%) saturate(10000%) ;
}
hover the icon to change its color.
<div class="burger">
</div>

【讨论】:

  • 这很棒,非常全面且有多种选择。我选择了最后一个选项,因为 IE11 支持没什么大不了的。再次感谢!
猜你喜欢
  • 2018-07-20
  • 1970-01-01
  • 2013-10-11
  • 1970-01-01
  • 1970-01-01
  • 2011-04-20
  • 1970-01-01
  • 2017-04-10
  • 2022-01-12
相关资源
最近更新 更多