繁体   English   中英

SVG 在 margin-left 变化时摇晃(轻弹)(选取框效果)

[英]SVG is shaking (flicking) on margin-left change (marquee effect)

我正在尝试对 vanilla JS 使用选取框效果。 效果有效,但 svg(和图像)在移动时摇晃。

<div class="marquee">
  <h1>Nepal <svg version="1.1" viewBox="0 0 36 31" xmlns="http://www.w3.org/2000/svg"><path d="M8.80476 8.17844V12.3988H3.9993V4.25693H8.79846V8.17844H8.80476ZM32.4101 3.87271V0H20.0028V3.87271H16.0035V0H3.60252V3.87271H0V15.497H3.60252V19.76H7.60182V23.2485H11.6011V27.5115H15.6004V31H20.3996V27.5115H24.3989V23.2485H28.3982V19.76H32.3975V15.497H36V3.87271" fill="#DA2269"/></svg> Himalayas <svg version="1.1" viewBox="0 0 36 31" xmlns="http://www.w3.org/2000/svg"><path d="M8.80476 8.17844V12.3988H3.9993V4.25693H8.79846V8.17844H8.80476ZM32.4101 3.87271V0H20.0028V3.87271H16.0035V0H3.60252V3.87271H0V15.497H3.60252V19.76H7.60182V23.2485H11.6011V27.5115H15.6004V31H20.3996V27.5115H24.3989V23.2485H28.3982V19.76H32.3975V15.497H36V3.87271" fill="#DA2269"/></svg> Mountains <svg version="1.1" viewBox="0 0 36 31" xmlns="http://www.w3.org/2000/svg"><path d="M8.80476 8.17844V12.3988H3.9993V4.25693H8.79846V8.17844H8.80476ZM32.4101 3.87271V0H20.0028V3.87271H16.0035V0H3.60252V3.87271H0V15.497H3.60252V19.76H7.60182V23.2485H11.6011V27.5115H15.6004V31H20.3996V27.5115H24.3989V23.2485H28.3982V19.76H32.3975V15.497H36V3.87271" fill="#DA2269"/></svg> Everest</h1>
</div>

<style>
.marquee {
  overflow: hidden;
  border-top: 1px solid #000;
  border-bottom: 1px solid #000;
  display: flex;
}

.marquee h1{
  font-size: 5em;
  white-space: nowrap;
  text-transform: uppercase
}

.marquee h1 svg {
  width: auto;
  height: 60px;
}
</style>

<script>
function Marquee(selector, speed) {
  const parentSelector = document.querySelector(selector);
  const clone = parentSelector.innerHTML;
  const firstElement = parentSelector.children[0];
  let i = 0;
  console.log(firstElement);
  parentSelector.insertAdjacentHTML('beforeend', clone);
  parentSelector.insertAdjacentHTML('beforeend', clone);

  setInterval(function () {
    firstElement.style.marginLeft = `-${i}px`;
    if (i > firstElement.clientWidth) {
      i = 0;
    }
    i = i + speed;
  }, 0);
}

//after window is completed load
//1 class selector for marquee
//2 marquee speed 0.2
window.addEventListener('load', Marquee('.marquee', 0.2))

</script>

示例: https://codepen.io/diegosomar/pen/dyKBGWg

有人知道有没有办法防止 svg 抖动?

如果您将间隔设置为在 100 毫秒内更新,如下所示:

setInterval(function () {
    firstElement.style.marginLeft = `-${i}px`;
    if (i > firstElement.clientWidth) {
      i = 0;
    }
    i = i + speed;
  }, 100);

你会清楚地看到发生了什么。 不仅图像会抖动,单个字母也会抖动。 这种抖动效果似乎是浏览器(至少是 Chrome)呈现图像/字母的方式。

但是,在查看 CSS 时我注意到了一些事情。当我将宽度更改为width: 70px时,“摇晃”似乎停止了(我选择 70px 是因为它更接近初始心脏图像的大小)。 当我在 Inspector 上检查 Heart SVG 元素时,我看到当它被设置为width: autowidth: 70px相比,宽度的变化过程有延迟。 这使它看起来更抖动。

使用以像素为单位的固定width大小是解决该问题的一种 hacky 解决方案,但有一种更好、更简单的方法来实现 CSS 的效果,这可能会解决该问题。

您可以简单地每秒更改一次,而不是每毫秒更改一次margin-left ,并让平滑过渡由 CSS 处理。您可以在此处了解CSS 过渡

<style>
.marquee h1 {
  transition: margin-left 1s linear;
}
</style>

<script>
function Marquee(selector, speed) {
  const parentSelector = document.querySelector(selector);
  const clone = parentSelector.innerHTML;
  const firstElement = parentSelector.children[0];
  let i = 0;
  console.log(firstElement);
  parentSelector.insertAdjacentHTML('beforeend', clone);

  setInterval(function () {
    firstElement.style.marginLeft = `-${i}px`;
    if (i > firstElement.clientWidth) {
      i = 0;
    }
    i = i + speed;
  }, 1000); //update every second
}

window.addEventListener('load', Marquee('.marquee', 100)) //every second -100 pixels will be added to `margin-left` of the element
</script>

通过将transition添加到.marquee h1样式,您可以立即看到差异。 请注意,您可能希望在i = 0之后处理transition ,以防止从 -2000px( firstElement.clientWidth大小)突然平滑地跳到 0px。

setInterval()替换为requestAnimationFrame()

正如@Jefferson 的回答中所指出的,您当前的setInterval()调用具有零毫秒延迟,导致动画/过渡不稳定。
此外,它会导致时间不一致,例如 Firefox 和 Chromium。

requestAnimationFrame()确保您的样式更改每帧应用一次– 而setInterval()可能会尝试更改“帧之间”的样式属性(如果以毫秒为单位的间隔与帧不匹配)。

示例片段

 function Marquee(selector, speed) { const parentSelector = document.querySelector(selector); const clone = parentSelector.innerHTML; const firstElement = parentSelector.children[0]; let i = 0; parentSelector.insertAdjacentHTML('beforeend', clone); parentSelector.insertAdjacentHTML('beforeend', clone); function scrollMarquee(timestamp) { timestamp = timestamp || new Date().getTime(); firstElement.style.marginLeft = `-${i}px`; if (i >= firstElement.clientWidth ) { i = 0; } i += speed; requestAnimationFrame(scrollMarquee); } requestAnimationFrame(scrollMarquee); } //after window is completed load //1 class selector for marquee //2 marquee speed 0.2 window.addEventListener('load', Marquee('.marquee', 1))
 .marquee { overflow: hidden; border-top: 1px solid #000; border-bottom: 1px solid #000; display: flex; }.marquee h1{ font-size: 5em; white-space: nowrap; text-transform: uppercase }.marquee h1 svg { width: auto; height: 60px; }
 <div class="marqueeOuter"> <div id="marquee" class="marquee"> <h1> Nepal <svg viewBox="0 0 36 31"> <path d="m9 8v4h-5v-8h5v4l0 0zm23-4v-4h-12v4h-4v-4h-12v4h-4v11h4v5h4v3h4v5h4v3h4v-3h4v-5h4v-3h4v-5h4v-11" fill="#DA2269" /> </svg> Himalayas <svg viewBox="0 0 36 31" xmlns="http://www.w3.org/2000/svg"> <path d="m9 8v4h-5v-8h5v4l0 0zm23-4v-4h-12v4h-4v-4h-12v4h-4v11h4v5h4v3h4v5h4v3h4v-3h4v-5h4v-3h4v-5h4v-11" fill="#DA2269" /> </svg> Mountains <svg viewBox="0 0 36 31" xmlns="http://www.w3.org/2000/svg"> <path d="m9 8v4h-5v-8h5v4l0 0zm23-4v-4h-12v4h-4v-4h-12v4h-4v11h4v5h4v3h4v5h4v3h4v-3h4v-5h4v-3h4v-5h4v-11" fill="#DA2269" /> </svg> Everest</h1> </div> </div>

首选 integer 动画值——如果可行的话

通过浮点数递增样式属性会导致舍入错误——也会导致不希望的抖动转换和性能问题。
这也适用于这篇代码笔文章中描述的 svg。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM