【问题标题】:How to fix flicker on iOS caused by CSS transition and transform?如何修复 iOS 上由 CSS 过渡和变换引起的闪烁?
【发布时间】:2022-01-10 23:08:55
【问题描述】:

我正在我的网站上开发一个灯箱,并注意到它在我拥有的所有浏览器(Brave、Chrome 和 Safari)的 iOS 上都会闪烁。但是,它不会闪烁总是,只是当我将图像向左移动时,它才会离开视口。

那里有dozens of answers 建议属性,例如:

-webkit-backface-visibility: hidden;
-webkit-transform-style: preserve-3d;
-webkit-transform: translate3d(0, 0, 0);
-webkit-perspective: 1000;

我已经尝试了所有这些,但都没有奏效。这是意料之中的,因为这些问题已经很老了,我认为这些问题早已不复存在。然而,情况似乎并非如此。

在测试了 CSS 属性和 DOM 更改的各种组合之后,我将我的代码归结为一个可重现的最小示例:

let box = document.querySelector(".lightbox");
let img = box.querySelector("img");
let rx = 0;
let ry = 0;
let x = 0;
let y = 0;

let render = () => {
  img.style.transform = `translate(${rx}px, ${ry}px) scale(2)`;
};

let onDown = (e) => {
  x = e.clientX;
  y = e.clientY;
  box.addEventListener("pointermove", onMove);
};

let onMove = (e) => {
  let lastX = x;
  let lastY = y;
  x = e.clientX;
  y = e.clientY;
  if (lastX && lastY) {
    rx += x - lastX;
    ry += y - lastY;
  }
  render();
};

let onUp = (e) => {
  box.removeEventListener("pointermove", onMove);
};

box.addEventListener("pointerdown", onDown);
box.addEventListener("pointerup", onUp);
box.addEventListener("pointerleave", onUp);
box.addEventListener("pointercancel", onUp);

render();

setInterval(() => {
  box.classList.remove("test");
  setTimeout(() => {
    box.classList.add("test");
  }, 100);
}, 1e3);
img {
  max-width: 100%;
  height: auto;
}

.lightbox {
  width: 100%;
  height: 100%;
  touch-action: none;
}

.lightbox img {
  transition: transform 0.8s cubic-bezier(0.16, 1, 0.3, 1);
}

.lightbox.test img {
  transition: none;
}
<div class="lightbox">
  <img width="1280" height="720" style="background-image: linear-gradient(-45deg, #cc8888, #88cc88)" />
</div>

如果你想知道为什么我有一个 setInterval 来添加和删除一个类,那是因为它会触发错误。例如,如果没有间隔,并且类只是在 pointerup 事件之后添加/删除,则它不会闪烁。 transform 中的 scale(2) 也是问题的一部分。如果我删除它,闪烁就会停止。

我已经创建了一个demo site on Netlify 和一个demo video

编辑:我已设法进一步简化:

let box = document.querySelector("div");
let rx = 0;
let ry = 0;
let x = 0;
let y = 0;

let render = () => {
  box.style.transform = `translate(${rx}px, ${ry}px) scale(2)`;
};

let onDown = (e) => {
  x = e.clientX;
  y = e.clientY;
  box.addEventListener("pointermove", onMove);
};

let onMove = (e) => {
  let lastX = x;
  let lastY = y;
  x = e.clientX;
  y = e.clientY;
  if (lastX && lastY) {
    rx += x - lastX;
    ry += y - lastY;
  }
  render();
};

let onUp = (e) => {
  box.removeEventListener("pointermove", onMove);
};

box.addEventListener("pointerdown", onDown);
box.addEventListener("pointerup", onUp);
box.addEventListener("pointerleave", onUp);
box.addEventListener("pointercancel", onUp);

render();
div {
  width: 200px;
  height: 200px;
  touch-action: none;
  transition: transform 0.1s ease;
  background-image: linear-gradient(-45deg, #cc8888, #88cc88);
}
&lt;div&gt;&lt;/div&gt;

在这个 sn-p 中,没有 setInterval 和类切换。相反,transition 始终处于活动状态。现在,只要您移动图像并且它位于屏幕的左侧,该元素就会被隐藏。看来只有当我删除转换的 scale() 部分时,问题才会消失,即从这里更改它:

box.style.transform = `translate(${rx}px, ${ry}px) scale(2)`;

...到这个:

box.style.transform = `translate(${rx}px, ${ry}px)`;

但是,在我的原始应用程序中,这个比例是动态变化的,所以我需要它。

【问题讨论】:

    标签: javascript css webkit css-transitions css-transforms


    【解决方案1】:

    使用transform matrix() 似乎可以解决问题。如果我切换这一行:

    box.style.transform = `translate(${rx}px, ${ry}px) scale(2)`;
    

    用这个:

    box.style.transform = `matrix(2, 0, 0, 2, ${rx}, ${ry})`;
    

    问题消失了。在 iOS Brave、Chrome 和 Safari 上测试。

    【讨论】:

      猜你喜欢
      • 2021-02-14
      • 1970-01-01
      • 1970-01-01
      • 2018-05-14
      • 2016-10-18
      • 1970-01-01
      • 2017-07-03
      • 2015-08-05
      • 2019-05-06
      相关资源
      最近更新 更多