如何修复 iOS 上由 CSS 过渡和变换引起的闪烁?
Posted
技术标签:
【中文标题】如何修复 iOS 上由 CSS 过渡和变换引起的闪烁?【英文标题】:How to fix flicker on iOS caused by CSS transition and transform? 【发布时间】: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($rxpx, $rypx) 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 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($rxpx, $rypx) 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);
<div></div>
在这个 sn-p 中,没有 setInterval
和类切换。相反,transition
始终处于活动状态。现在,只要您移动图像并且它位于屏幕的左侧,该元素就会被隐藏。看来只有当我删除转换的 scale()
部分时,问题才会消失,即从这里更改它:
box.style.transform = `translate($rxpx, $rypx) scale(2)`;
...到这个:
box.style.transform = `translate($rxpx, $rypx)`;
但是,在我的原始应用程序中,这个比例是动态变化的,所以我需要它。
【问题讨论】:
【参考方案1】:使用transform matrix()
似乎可以解决问题。如果我切换这一行:
box.style.transform = `translate($rxpx, $rypx) scale(2)`;
用这个:
box.style.transform = `matrix(2, 0, 0, 2, $rx, $ry)`;
问题消失了。在 iOS Brave、Chrome 和 Safari 上测试。
【讨论】:
以上是关于如何修复 iOS 上由 CSS 过渡和变换引起的闪烁?的主要内容,如果未能解决你的问题,请参考以下文章
这个堆栈跟踪表明了啥? iOS8 上由 Xamarin.Media.MediaPicker.TakePhotoAsync 引起的崩溃