iPad Safari scrolling causes HTML elements to disappear and reappear with a delay

105,987

Solution 1

I was using translate3d before. It produced unwanted results. Basically, it would chop off and not render elements that were offscreen, until I interacted with them. So, basically, in landscape orientation, half of my site that was offscreen was not being shown. This is a iPad web application, owing to which I was in a fix.

Applying translate3d to relatively positioned elements solved the problem for those elements, but other elements stopped rendering, once offscreen. The elements that I couldn't interact with (artwork) would never render again, unless I reloaded the page.

The complete solution:

*:not(html) {
    -webkit-transform: translate3d(0, 0, 0);
}

Now, although this might not be the most "efficient" solution, it was the only one that works. Mobile Safari does not render the elements that are offscreen, or sometimes renders erratically, when using -webkit-overflow-scrolling: touch. Unless a translate3d is applied to all other elements that might go offscreen owing to that scroll, those elements will be chopped off after scrolling.

(This is the complete answer to my question. I had originally marked Colin Williams' answer as the correct answer, as it helped me get to the complete solution. A community member, @Slipp D. Thompson edited my question, after about 2.5 years of me having asked it, and told me I was abusing SO's Q & A format. He also told me to separately post this as the answer. @Colin Williams, thank you! The answer and the article you linked out to gave me a lead to try something with CSS. So, thanks again, and hope this helps some other lost soul. This surely helped me big time!)

Solution 2

You need to trick the browser to use hardware acceleration more effectively. You can do this with an empty three-dimensional transform:

-webkit-transform: translate3d(0, 0, 0)

Particularly, you'll need this on child elements that have a position:relative; declaration (or, just go all out and do it to all child elements).

It is aot a guaranteed fix, but it is fairly successful most of the time.

Hat tip: iOS 5 Native Scrolling–Grins & Gotchas

Solution 3

Targeting all elements but html: *:not(html) caused problems on other elements in my case. It modified the stacking context, causing some z-index to break.

We should better try to target the right element and apply -webkit-transform: translate3d(0,0,0) to it only.

Sometimes the translate3D(0,0,0) doesn't work. We can use the following method, targeting the right element:

@keyframes redraw{
    0% {opacity: 1;}
    100% {opacity: .99;}
}

/* iOS redraw fix */
animation: redraw 1s linear infinite;

Solution 4

When the translate3d doesn't work, try to add perspective. It always works for me

transform: translate3d(0, 0, 0);
-webkit-transform: translate3d(0, 0, 0);
perspective: 1000;
-webkit-perspective: 1000;

Increase Your Site’s Performance with Hardware-Accelerated CSS

Solution 5

Adding -webkit-transform: translate3d(0,0,0) to an element statically doesn't work for me.

I apply this property dynamically. For example, when a page is scrolled, I set -webkit-transform: translate3d(0,0,0) on a element. Then after a short delay, I reset this property, that is, -webkit-transform: none This approach seems to work.

Thank you, Colin Williams for pointing me in the right direction.

Share:
105,987

Related videos on Youtube

codeBearer
Author by

codeBearer

Updated on August 19, 2022

Comments

  • codeBearer
    codeBearer over 1 year

    I'm currently developing a web application using HTML5 and jQuery for iPad Safari. I'm running into a problem wherein large scroll areas cause the elements that are offscreen to appear after a delay when I scroll down to them.

    What I mean by that is, if I have a row of images (or even a div with a gradient) that is offscreen, when I scroll down (or up) to it, the expected behavior is for the element to appear on screen as I am scrolling to it.

    However, the element does not appear until I lift my finger off the screen and the scroller finishes all its animations.

    This is causing a super noticeable problem for me, making the whole thing look choppy, although it is not. I'm guessing the iPad Safari is trying to do something to save memory. Is there a way in which I can prevent this choppy-ness from happening?

    Additionally, what is iPad Safari actually trying to do?

    • 75th Trombone
      75th Trombone about 11 years
      This problem/solution helped me fix an issue with jPanelMenu 1.3 CSS Transforms version, which turned everything on my site invisibie until I added the above snippet.
    • Jonathan Tonge
      Jonathan Tonge almost 10 years
      Using *:not(html) will apply the translate3d to all other aspects of your site and I do not recommend. It will cause images in tabs to disappear as you scroll down, etc, bugs that you might be use to seeing on just your 3d images will now be present in other aspects of your site.
    • Zephyr Mays
      Zephyr Mays over 9 years
      I had a few <svg> elements which were exhibiting similar delayed drawing/rendering. Unfortunately, *:not(html) { ... } led to all sorts of weird behaviors, as @JonathanTonge pointed out might occur. However, selecting only the <svg> elements and using translate3d(0, 0, 0,); seems to have solved my scrolling issues.
    • Stoutie
      Stoutie over 9 years
      Except for very specific use cases, this is garbage. Really messes up layouts that depend on absolute position elements.
    • Slipp D. Thompson
      Slipp D. Thompson over 9 years
      Please post answers as answers, not “EDIT”s in your question. I know you like your answer best, and that's fine, but StackOverflow has a Q&A format that works best when the Q's are distinct from the A's.
  • codeBearer
    codeBearer almost 12 years
    I tried that as well. Sadly, adding a translate3d is chopping off elements that were being displayed properly before. I also needed hardware acceleration for a couple of objects that were offscreen and had to be animated to "fly in" on screen. I was using jQuery's animate(), which was super slow. I switched over to using hardware acceleration. Although that sped up the animation, it produced erratic results, in the sense that some of the child elements of the parent (animating) div were chopped off. This was not happening when I was using animate().
  • Luke
    Luke almost 12 years
    @Colin Williams you just made my day! :D
  • Tim Down
    Tim Down almost 12 years
    Wow, that is horrible but effective. Thank you.
  • thinsoldier
    thinsoldier about 10 years
  • Bryan Johnson
    Bryan Johnson almost 10 years
    Gold freakin star man! I added it to all my li elements in a scrollable div. Poof. Worked.
  • sumitkm
    sumitkm over 9 years
    Fantastic! Saved my bacon. To people who are having issues on applying this globally, try to narrow it down and apply it to the container div that has the items (that are not being rendered). So instead of *:not(html), #myDivContainer:not(html){...} and then apply myDivContainer as the Id to the div. Ugly, but effective in narrowing down global issues. BTW I have had to do this for latest Safari on the lastest OSX (not mobile/ipad only).
  • anon
    anon almost 9 years
    Wow. Thanks for this. It saved me a huge amount of headache for my phonegap/cordova app. In my case I had to change *:not(html) to body *
  • fidev
    fidev over 8 years
    just applying -webkit-transform: translate3d(0, 0, 0); to the problem element worked for me. In my case I was using ScrollMagic
  • cbmtrx
    cbmtrx over 8 years
    None of this worked for me either. As soon as I scroll down to a certain point, the no-longer-visible stuff above the window gets munged, as well as some elements in the viewport. I notice a very slight but unmistakable "jolt" while it's scrolling after which the elements get hosed. (Ie: smooth--jittery--smooth behavior, like it's hiccuping during scrolling.) This is in on iPad.
  • cbmtrx
    cbmtrx over 8 years
    BTW I just discovered that on an iPad Air 2, when a specific on-screen element (a navbar, in this case) goes off screen, the device "reloads" that block--only using the large version, not the original medium one that the page loaded with. What the...
  • cbmtrx
    cbmtrx over 8 years
    In case anyone is experiencing the same weirdness as me--slightly different from what is described on this page--I found that using $(window).width() instead of window.innerWidth in jQuery made all the difference for iOS. Who knows.
  • Jake
    Jake over 8 years
    Thanks! Worked for me.
  • Windwalker
    Windwalker about 8 years
    This hint helped me a lot, since these styles bing some unwanted side effects, I usually want to avoid. So I use touchstart/touchend events to add and remove them. Thanks!
  • Adam Benedek
    Adam Benedek over 7 years
    Thank you, you just helped me solving a very similar and annoying problem!
  • Jeeva J
    Jeeva J about 7 years
    If we apply this for the page, the fixed elements are collapsed.
  • BumbleB2na
    BumbleB2na over 6 years
    I used this technique to solve a similar problem on Android Chrome. Vertical scrolling seemed to perform better than when I tried the translate3d fix. In my case <body> element is what I used for scrolling and a simplified version worked: body { position: relative; z-index: 0; }
  • lilbiscuit
    lilbiscuit over 6 years
    holy c$#@ finally a solution for angular/ionic. -webkit-perspective: 1000;
  • Omar Bahir
    Omar Bahir about 6 years
    Ahh Saved my day. +1 for you ;)
  • kunal
    kunal about 6 years
    I was facing same issue. You can use body * selector instead of *:not(html). It will solve you issue.
  • tony
    tony over 5 years
    It did nothing for me whereas the accepted answer did so probably a different scenario
  • Maciek Rek
    Maciek Rek over 5 years
    I have applied it only to the elements affected and it worked! In my case it was the images inside a container overflow:hidden and scrollable horizontally: .elem-affected{-webkit-transform: translate3d(0, 0, 0);} I didn't need the :not(html) bit, not sure if it makes sense when applying to a specific eg. html class anyway.
  • Maciek Rek
    Maciek Rek over 5 years
    Kudos for the suggestion to target the right elements rather than polluting everything with the *
  • Andreas Richter
    Andreas Richter about 5 years
    This made my iOS browser crash.
  • jHilscher
    jHilscher almost 5 years
    -webkit-perspective: 1000; did it for me - thank you
  • Inc33
    Inc33 about 3 years
    Thank You! Just saved me from a few hours of frustration.
  • Siniša
    Siniša almost 3 years
    5 years ago, same solution for the same problem today! Thanks for the tip, worked excellent in my case. I have WebGL canvas top of which some HTML elements (logo and such), which, to my great surprise, would suddenly disappear in the middle of interaction with 3D canvas. I suspected it's a bug in iOS Safari final image composition, but this was indeed a life savior!
  • craigpatik
    craigpatik almost 2 years
    Dynamically applying the style worked well for me. It's a React app so I made a hook that returns the className to apply to the scrolling container based on its children. Whenever the children change, or after the setTimeout has finished, the hook toggles the class between .ios-fix and an empty string so you can apply it with <div className={className}>.