如何避免我的触摸可拖动border-radius元素在iPad上的动画制品? [英] How can I avoid animation artifacts on my touch-draggable border-radius element on iPad?

查看:383
本文介绍了如何避免我的触摸可拖动border-radius元素在iPad上的动画制品?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了一个示例页面,其中包含可在触摸设备上拖动的元素(基于不会将消除锯齿的线剪裁到形状的边缘,以及WebKit在部分更改后如何重绘网页。



绘制网页



首先,快速和(过)简化WebKit从DOM节点树到表示渲染网页的位图图像的运行。



你已经知道一个网页被解析成一个称为DOM的元素树。 DOM中的每个节点都以某种方式呈现,具体取决于应用于它的样式。根据z顺序,透明度,溢出,定位等事物,节点可能与其他节点重叠或重叠。



这大致类似于如何在引擎盖下工作。 WebKit将每个DOM节点映射到相应的 RenderObject ,它具有绘制单个DOM节点所需的所有信息。每个 RenderObject 映射到自己的或者祖先的 RenderLayer ,这是处理节点如何分层 -



要渲染网页,每个 RenderLayer 都是从背面到前面通过z顺序。孩子背后的第一层,其次是层本身,其次是孩子在它的前面。要绘制自己, RenderLayer 在其相应的 RenderObject 上调用paint方法。



WebKit有两个代码路径,用于渲染给定的 RenderLayer :软件路径和硬件加速路径。软件路径将每个 RenderObject 直接映射到您在浏览器中看到的渲染网页的图像,而硬件路径允许某些 RenderLayer 被指定为合成层,这意味着它和它的孩子被分开绘制并且最终由GPU合成为单个图像。当页面上的 RenderLayer 中的一个或多个需要硬件加速时,或者当浏览器中的标志(例如Chrome)明确要求时,使用硬件路径。



更新网页的一部分



当动画或其他事件改变页面部分的外观时,您不想重绘整个网页。相反,WebKit在改变的区域绘制一个框 - 损坏的直方图,只重画每个 RenderLayer 与那个框重叠的位。



如果您是通过软件渲染的,那么路径,WebKit直接将损坏rect重构到完整呈现的页面的位图图像,留下图像的其余部分不变。



出错了











$ b

translateZ 修复会对元素应用3D变换。这迫使绘制球的 RenderLayer 需要硬件加速,这意味着WebKit将使用硬件路径而不是软件路径。这意味着问题与使用软件路径有关。



当球被画时,边界半径意味着边缘是消除锯齿的。由于与Quartz相关的已知问题,形状是反锯齿的,使得一些像素落在损坏直线之外,当您更改球的位置在页面上计算。使用软件路径,浏览器仅重绘绘制的页面图像的变化区域,使图像的其余部分保持不变。



相比之下,硬件(硬件)路径单独重绘该图层(及其子图层),然后重新合成页面。



TL; DR



当WebKit使用软件渲染路径时,对页面的一部分的改变直接对表示整个页面的图像进行。出于性能原因,WebKit仅重绘图像中已更改的那些部分。然而,当Quartz绘制一个圆角矩形时,它反边缘的边缘,使一些像素落在WebKit知道要重绘的区域之外。修复是通过应用3D变换强制该图层需要硬件加速,这意味着该元素将与页面的其余部分分开绘制,然后重新组合。




I’ve written a little example page with elements that are draggable on touch devices (based on code by Peter-Paul Koch).

I have two draggable <div> elements: a green block, and a red ball (made ball-shaped with border-radius). The dragging is implemented with ontouchstart, ontouchmove and ontouchend, and the "animation" is done by changing the top and left CSS properties of these elements.

When I drag the green one, all is roses and ponycorns.

But when I drag the red one in Safari on an iPad 1 (running iOS 5.1.1) or an iPad 3 (6.0.1), I get little light red trails where the rear edges of the circle were (see screenshot below).

I don’t, however, see these trails on my iPhone 5 (6.1.4).

Is there a way to get rid of these trails?

(Bonus question: is there a term for this effect? "Ghosting"? "Artifacts"?)

解决方案

The fix

Add this rule to your #bawl { … } ruleset:

-webkit-transform: translateZ(0);

(If you need to avoid hardware acceleration, you can use outline: 1px solid transparent—for more details, see my answer to a similar question.)

This removes the trailing artefacts, but why? It's a combination of Quartz (the drawing engine in iOS) not clipping anti-aliased lines to the edges of a shape and how WebKit repaints a web page after part of it changes.

Drawing a webpage

First, a quick and (over)simplified run down of how WebKit gets from a tree of DOM nodes to a bitmap image representing the rendered webpage.

You already know that a webpage gets parsed into a tree of elements, called the DOM. Each node in the DOM is presented in a certain way depending on the styles applied to it. It is possible for nodes to overlap, or be overlapped by, other nodes depending on things like z-order, transparency, overflow, positioning etc.

This is broadly similar to how things work under the hood. WebKit maps each DOM node to a corresponding RenderObject, which has all the information it needs to paint an individual DOM node. Each RenderObject is mapped to either its own or an ancestor's RenderLayer, which is a conceptual way of dealing with how nodes are "layered"—i.e. painted over or under other nodes.

To render a webpage, each RenderLayer is painted from back-to-front by z-order. Children behind that layer painted are first, followed by the layer itself, followed by children in front of it. To paint itself, the RenderLayer calls the paint method on its corresponding RenderObjects.

WebKit has two code paths for rendering a given RenderLayer: the software path and the hardware accelerated path. The software path paints each RenderObject directly to the image of the rendered webpage that you see in your browser, whereas the hardware path allows certain RenderLayers to be designated as compositing layers, which means that it and its children are drawn separately and finally composited into a single image by the GPU. The hardware path is used whenever one or more of the RenderLayers on a page require hardware acceleration, or when it is explicitly required by a flag in the browser (e.g. Chrome).

Updating part of a webpage

When an animation or some other event changes how part of a page looks, you don't want to redraw the entire webpage. Instead, WebKit draws a box around the changed area—the damage rect—and only redraws bits of each RenderLayer that overlap with that box. A RenderLayer that doesn't overlap the damage rect is skipped entirely.

If you're rendering via the software path, WebKit directly recomposes the damage rect onto the bitmap image of the full rendered page, leaving the rest of the image unchanged. The hardware path, however, repaints each compositing layer separately and recomposites them into a new image.

What is going wrong

The translateZ fix applies a 3D transform to the element. This forces the RenderLayer that paints the ball to require hardware acceleration, meaning that WebKit will use the hardware path instead of the software path. This implies that the problem is related to using the software path.

When the ball is painted, the border radius means that the edges are anti-aliased. Because of a known issue related to Quartz, the edges of the shape are anti-aliased such that some pixels fall outside of the damage rect calculated when you change the ball's position on the page. Using the software path, the browser redraws only the changed region of the rendered page image, leaving the rest of the image untouched. The semi-transparent pixels that fall outside of this area won't be updated, which accounts for the artefacts left behind when you move the ball.

By contrast, the hardware path redraws that layer (and its child layers) separately then recomposites the page. No "ghost pixels" are left over from the last time that layer was rendered.

TL;DR

When WebKit uses the software rendering path, changes to part of a page are made directly to the image representing the whole page. For performance reasons, WebKit only redraws those parts of an image that have changed. However, when Quartz draws a rounded rectangle, it anti-aliases the edges such that some pixels fall outside the region that WebKit knows to redraw. The fix is to force that layer to require hardware acceleration by applying a 3D transform, meaning that element is drawn separately from the rest of the page and recomposed after.

这篇关于如何避免我的触摸可拖动border-radius元素在iPad上的动画制品?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆