使用 Webkit 转换和转换时如何修复闪烁
Posted
技术标签:
【中文标题】使用 Webkit 转换和转换时如何修复闪烁【英文标题】:How to fix flicker when using Webkit transforms & transitions 【发布时间】:2011-02-27 20:20:15 【问题描述】:我有一个非常简单的演示工作,它使用 Webkit 转换和转换在“面板”(div)之间实现平滑的水平滚动。
我想走这条路线而不是 javascript 驱动系统的原因是它适用于 iPad 并且 Javascript 性能很差,但是 css 转换和过渡非常流畅。可悲的是,我的演示在 iPad 上出现了很多闪烁。
你可以看到the demo here
您需要 Safari 或 iPad 才能看到它的实际效果。我从未在任何转换和过渡的演示中看到这种情况发生,所以我希望这是可以修复的。
不管怎样,这就是驱动这个东西的代码......
html 看起来像这样。
<html>
<head>
<title>Swipe Demo</title>
<link href="test.css" rel="stylesheet" />
<link href="styles.css" rel="stylesheet" />
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="functions.js"></script>
<script type="text/javascript" src="swiping.js"></script>
</head>
<body>
<div id="wrapper">
<div class='panel one'>
<h1>This is panel 1</h1>
</div>
<div class='panel two'>
<h1>This is panel 2</h1>
</div>
<div class='panel three'>
<h1>This is panel 3</h1>
</div>
<div class='panel four'>
<h1>This is panel 4</h1>
</div>
</div>
</body>
</html>
CSS 看起来像这样
body,
html
padding: 0;
margin: 0;
background: #000;
#wrapper
width: 10000px;
-webkit-transform: translateX(0px);
.panel
width: 1024px;
height: 300px;
background: #fff;
display: block;
float: left;
position: relative;
而 javascript 看起来像这样
// Mouse / iPad Touch
var touchSupport = (typeof Touch == "object"),
touchstart = touchSupport ? 'touchstart' : 'mousedown',
touchmove = touchSupport ? 'touchmove' : 'mousemove',
touchend = touchSupport ? 'touchend' : 'mouseup';
$(document).ready(function()
// set top and left to zero
$("#wrapper").css("top", 0);
$("#wrapper").css("left", 0);
// get total number of panels
var panelTotal;
$(".panel").each(function() panelTotal += 1 );
// Touch Start
// ------------------------------------------------------------------------------------------
var touchStartX;
var touchStartY;
var currentX;
var currentY;
var shouldMove = false;
document.addEventListener(touchstart, swipeStart, false);
function swipeStart(event)
touch = realEventType(event);
touchStartX = touch.pageX;
touchStartY = touch.pageY;
var pos = $("#wrapper").position();
currentX = parseInt(pos.left);
currentY = parseInt(pos.top);
shouldMove = true;
// Touch Move
// ------------------------------------------------------------------------------------------
var touchMoveX;
var touchMoveY;
var distanceX;
var distanceY;
document.addEventListener(touchmove, swipeMove, false);
function swipeMove(event)
if(shouldMove)
touch = realEventType(event);
event.preventDefault();
touchMoveX = touch.pageX;
touchMoveY = touch.pageY;
distanceX = touchMoveX - touchStartX;
distanceY = touchMoveY - touchStartY;
movePanels(distanceX);
function movePanels(distance)
newX = currentX + (distance/4);
$("#wrapper").css("left", newX);
// Touch End
// ------------------------------------------------------------------------------------------
var cutOff = 100;
var panelIndex = 0;
document.addEventListener(touchend, swipeEnd, false);
function swipeEnd(event)
touch = (touchSupport) ? event.changedTouches[0] : event;
var touchEndX = touch.pageX;
var touchEndY = touch.pageY;
updatePanelIndex(distanceX);
gotToPanel();
shouldMove = false;
// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
function updatePanelIndex(distance)
if(distanceX > cutOff)
panelIndex -= 1;
if(distanceX < (cutOff * -1))
panelIndex += 1;
if(panelIndex < 0)
panelIndex = 0;
if(panelIndex >= panelTotal)
panelIndex = panelTotal -1;
console.log(panelIndex);
// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
function gotToPanel()
var panelPos = getTotalWidthOfElement($(".panel")) * panelIndex * -1;
$("#wrapper").css("-webkit-transition-property", "translateX");
$("#wrapper").css("-webkit-transition-duration", "1s");
$("#wrapper").css("-webkit-transform", "translateX("+panelPos+"px)");
);
function realEventType(event)
e = (touchSupport) ? event.targetTouches[0] : event;
return e;
【问题讨论】:
【参考方案1】:我发现 translate3D 是比动画 left: 或 right: 类更好的解决方案。它在 safari 上运行良好并且更流畅。即使在 ios13 上,我也遇到了严重的闪烁问题。
这是一张幻灯片:
.cartout-enter-active
-webkit-animation: cartout 0.2s;
animation: cartout 0.2s;
.cartout-leave-active
-webkit-animation: cartout 0.2s reverse;
animation: cartout 0.15s reverse;
@-webkit-keyframes cartout
from
transform: translate3d(100%, 0, 0);
to
transform: translate3d(0%, 0, 0);
【讨论】:
【参考方案2】:基于@tobiasahlin WebExpo 上的演讲。
Safari 闪烁问题修复最佳解决方案是
transform: translateZ(0);
【讨论】:
【参考方案3】:如今,在 iOS8 中,另一个很好的解决方案是将 overflow: hidden
应用于被指控的元素(或其容器)。
【讨论】:
【参考方案4】:我首先让视图处于“3D”状态,从而使闪烁消失。首先,我所有的观点都启用了preserve-3D。然后我有这个代码,
MyNamespace.flickerFixer = function(children)
children.css(
"-webkitTransform": "translate3D(0px, 0px, 0px)",
"-webkit-transition": "1s ease-in-out"
);
然后我在做 webkit 动画之前初始化它:
MyNamespace.flickerFixer($this.parent(".ui-content"));
【讨论】:
【参考方案5】:@gargantaun 是对的,如果您要设置动画的元素大于屏幕,Webkit 会闪烁。但是有一个简单的解决方法。只需添加:
-webkit-backface-visibility: hidden;
到元素,你很高兴!
【讨论】:
我很好奇,你是怎么想出来的? 找到它here,我们的companies website 需要它(只需等待几秒钟的动画)。 使用风险自负!当 IOS7 出来时,我们的应用程序由于内存错误而开始崩溃。它通常使用 10-15 MB,但 IOS 崩溃日志报告使用约 600 MB。经过一番挖掘,事实证明这个背面可见性黑客(我们从源代码中确实有一个指向这个 SO 线程的链接)是原因,或者至少,删除它使崩溃消失了。不知道为什么,它只是IOS7。我认为Apple的Webkit分支中一定存在一些内存泄漏错误或某些东西。现在很多开发者都在抱怨 IOS7 Safari 崩溃了。 桌面(Chrome)上也会发生同样的情况。我只是尝试在带有图像的可滚动列表上使用它,结果导致严重的帧率下降。【参考方案6】:如上所述,最好使用 Translate3d,因为硬件加速可以实现更平滑的过渡。
但是,当被动画的 div 大于屏幕时会导致闪烁。所以,如果你有一个区域加起来最多 3.5 个屏幕宽度,你希望水平过渡,它应该像这样分成 4 个 div
[1][2][3][.5]
所有 div 都不应超过屏幕的高度或宽度。
很抱歉迟到了这个答案。在收到“热门问题”通知之前,我完全忘记了它。
【讨论】:
庞大 - 我遇到了同样的问题,但我不确定我是否理解这个答案。我有一个类似的布局 - 一个宽广的可视区域,其宽度是视口/屏幕的 300%,我正在为该区域左右设置动画。如果我将它分成 3 个 div,每个都与屏幕一样宽 - 那么您是否建议我单独为每个 div 设置动画?【参考方案7】:尝试使用 translate3d 而不是 translateX。似乎只有 translate3d 在 iPad 3.2 上进行了硬件加速。
【讨论】:
以上是关于使用 Webkit 转换和转换时如何修复闪烁的主要内容,如果未能解决你的问题,请参考以下文章
在 Android 上使用 jQuery Mobile 在页面转换时仍然存在闪烁/闪烁问题