Webkit animation is leaving junk pixels behind on the screen

17,745

Solution 1

The solution

box-shadow: 0 0 1px rgba(0, 0, 0, 0.05);

You can use the background colour of your box as the box-shadow colour if you feel this is too noticeable.

Alternatively, according to this answer on a similar issue in Chrome (thanks to Sebastian in the comments for the tip-off), you may want to try:

outline: 1px solid transparent;

What's going on?

I've given a fairly lengthy explanation elsewhere, but here's the short version. For performance reasons, WebKit only repaints those part of a page that it thinks might have changed. However, the iOS (pre-7) Safari implementation of border radius anti-aliases a few pixels beyond the calculated dimensions of a box. Since WebKit doesn't know about these pixels, they don't get redrawn; instead, they are left behind and build up on each animation frame.

The usual solution—as I suggested in my other answer—is to force that element to require hardware acceleration so that it gets painted as a separate layer. However, too many small elements or a few large ones will result in a lot of tiles getting pushed to the GPU, with obvious performance implications.

Using box-shadow solves the problem more directly: it extends the repaint dimensions of the box, forcing WebKit to repaint the extra pixels. The known performance implications of box-shadow in mobile browsers are directly related to the blur radius used, so a one pixel shadow should have little-to-no effect.

Solution 2

What I would do:

  • -webkit-backface-visibility: hidden
  • animate with -webkit-transform:translateX(left value here) // or translate-3d(x,y,z), left should be disabled [*]

Be sure to check if enabling hardware acceleration on parent does make any difference.

There are also simple ways to force repaint - let me know if you would need info about them as well.

[*] relying on 3d transforms is a hack and should be used with caution, and it's a tradeoff between GPU and memory, in some cases it might cause animation jank or memory issues (think - mobile, forcing GPU acceleration on large areas).

CSS will-change property will be a correct place to mark properties that could be optimised in advance.

Share:
17,745
Joshua Smith
Author by

Joshua Smith

Updated on June 12, 2022

Comments

  • Joshua Smith
    Joshua Smith almost 2 years

    The following code puts a white box on the screen. If you run this on an iPad (you can adjust the pixels to run it on an iPhone, too), when you touch the box, it will scoot off the screen, and leave a trail of white-ish pixels along its bottom edge.

    <!DOCTYPE HTML>
    <html>
      <head>
        <meta http-equiv="content-type" content="text/html; charset=utf-8" />
        <meta name="viewport" content="width=device-height, user-scalable=no, maximum-scale=1, minimum-scale=1" />
        <title>Line Bug Demo</title>
        <style>
    body {
      background: black;
    }
    .panel {
      background: white;
      position: absolute;
      z-index: 2;
      width: 1000px;
      height: 500px;
      top: 34px;
      left: 12px;
      -webkit-border-radius: 20px;
      -webkit-transition: left 0.333s ease-in-out;
    }
    .panel.hide {
      left: -1000px;
    }
        </style>
      </head>
      <body>
        <div class="panel" onclick="this.setAttribute('class', 'panel hide')"></div>
      </body>
    </html>
    

    The key to getting the bug is using a border radius, and doing animation. If you just pop it off the screen, no trail. If there is no border radius, no trail.

    Here are the work-arounds I've found so far:

    .panel.hide { -webkit-border-radius: 0; }
    

    Ugly, and not really practical for my application, because I'm animating the panel both in and out, and I really want the rounded corners when it is on screen.

    Another:

    .panel { -webkit-transform: translateZ(0); }
    

    That puts the panel into the hardware pipeline, which does the compositing correctly. Although this works with this simple demo, using the hardware pipeline in my real web app causes out-of-memory errors. (Of the drastic, huge, immediate variety.)

    Any other ideas of how I might get rid of this trail?

  • Joshua Smith
    Joshua Smith almost 11 years
    This works. I saw no performance degradation. Note that in chasing down the links in your answer, I learned that iOS 7 has allegedly fixed the underlying quartz bug.
  • Jordan Gray
    Jordan Gray almost 11 years
    @jesmith I saw someone observe as much in a comment on the other question, though I couldn't find a good link to reference—if you have one, I'd be really grateful! As an aside, I ventured a little deeper into the WebKit source and read up on Quartz anti-aliasing to see if I could narrow it down further, but I'm not yet at a point where I could give a confident and accurate exposition.
  • Joshua Smith
    Joshua Smith almost 11 years
    Since iOS 7 is in Beta, and under non-disclosure rules, I think we'll just have to wait.
  • iMoses
    iMoses about 10 years
    -webkit-backface-visibility: hidden worked like a charm! Many thanks.
  • Wesley Brian Lachenal
    Wesley Brian Lachenal about 9 years
    Thanks to this one, I earned myself a Mango Milk Tea from my friend. LOL!
  • Sebastian
    Sebastian about 9 years
    I'm already using the box shadow, but another trick did it for me: Thanks to this post: stackoverflow.com/a/12352196/807397 I'm using outline: 1px solid transparent; which works like a charm!
  • Jordan Gray
    Jordan Gray about 9 years
    @Sebastian That's neat, and more concise—thanks for the heads up! I considered that outline might work, but never got around to testing it. Perhaps I should update my answer to link to that solution.
  • Cari
    Cari over 8 years
    Oh my god. This is amazing. Thank you!
  • nodws
    nodws over 6 years
    outline made it worse, old -webkit-backface-visibility: hidden worked on Chrome v60
  • Jordan Gray
    Jordan Gray over 6 years
    @nodws Hmm, interesting! Did you try the box-shadow approach? Setting backface-visibility will certainly remove the artifacts, but it does so by enabling hardware acceleration which the OP hoped to avoid. If that's not a problem for you, it makes perfect sense! :)
  • nodws
    nodws over 6 years
    yes tried that, I'm scratching my own back here this solution is just for my case, so dont try this in production folks :P
  • Rodolphe
    Rodolphe almost 3 years
    2021 and the issue is still there. The outline solution worked for me.