iOS 9 Safari: changing an element to fixed position while scrolling won't paint until scroll stops
Asked Answered
M

5

68

I've been developing a site and taking advantage from the rather good jQuery Sticky Kit plugin. It operates by switching the position property to fixed and back when appropriate. Runs very smoothly in desktop and acceptably so in mobile.

Or at least it used to. iOS 9 comes with a new behavior: if the position of an element changes from static/relative/absolute to fixed while the scroll animation is ongoing the element becomes invisible until after the scroll has come to a stop. Oddly enough the opposite change (from fixed to whatever else) is performed without issues.

A working example can be found on the plugin's homepage. The black navigation bar ("Examples Reference") is supposed to be sticky. Originally it's staticly positioned in mid-page. As you scroll down it becomes fixed and (in iOS 9) disappears until scroll stops. Behavior in desktop browsers and iOS 8 is correct.

I was kind of hoping for the typical CSS workarounds: forcing a 3D transform, disabling backface visibility and the like, obscure proprietary properties, ... But nothing seems to work.

Are we about to forget "stickable" elements altogether now that it was working?

Multiplex answered 30/9, 2015 at 20:29 Comment(3)
If you're developing for iOS you should use the better solution, position: sticky in CSS, albeit behind a prefix. You can keep your jQuery plugin for everything else and use the native CSS solution for iOS where it supports it (7+, if I recall correct).Kobe
Well, I'm developing for everything, but this allows for a mixed approach. Thanks!Multiplex
A few hours into trial and error, I can conclude that support for sticky headers in iOS is pretty good, but everything goes haywire when you get to sticky columns. A bit too green still.Multiplex
T
80

I had this same issue and was able to hack around it using the old "force a 3D transform" trick. Just set the element you are going to switch the position of to have a transform property of translate3d(0px,0px,0px). Make sure this is done before the position property is changed.

Terence answered 1/10, 2015 at 15:13 Comment(5)
translate3d() caused some layout issues for me, but translateZ(0) worked a charmRyals
I had translate3d() on the same CSS class, the trick is that it should be there BEFORE changing the position or adding the new class. Thanks for that!Parang
this doesn't seem to work for me on iOS 10... well it works but I can break it by dragging such as the fixed element 'sticks' and then changing the direction of my drag in the other direction :-(Delaney
Sadly this doesn't seem to work for me, on Safari 9.0. Nothing does. hide/show, adding an element, adding a CSS animation, accessing offsetHeight. I've tried every trick I can find, and still that header bar won't repaint in the fixed position until I remove my scrolling finger from the screen :(Enenstein
I literally spent days trying to figure out how to fix styling changes in my sticky header not taking affect until the scrolling completely stopped, making the whole thing look clunky and odd. Adding transform: translateZ(0); to the default element style fixed this and now the style transitions happen smoothly during scrolling. Wonderful! Thanks everybody! (Tested in Chrome and Safari on iPad Mini with iOS 10.0.2)Snuck
R
19

The only solution that I found to work correctly was to disable z-index translations on direct children of the fixed item, e.g.:

.is-sticky > * {
    -webkit-transform: translateZ(0);
}
Radium answered 3/4, 2017 at 15:4 Comment(0)
C
4

I fixed this problem with an extra fixed element. After some testing I found out that it's the first element that becomes fixed has this problem. The 2nd, 3rd, etc works fine on iOS devices.

So, put right after your body openingtag a div.fixed-fix:

.fixed-fix {
    position:fixed;
    top:-1px; 
    height:1px; 
    width:100%; 
    background:white;
}

now it works! The fixed-fix div MUST have a backgroundcolor, because otherwise it wont work...

Churchill answered 9/8, 2016 at 8:46 Comment(1)
this doesn't seem to work for me on iOS10. Maybe they 'fixed' it ? I was really hoping it would because I am finding the translate option very glitchyDelaney
E
3

jQuery Sticky Kit and other similar plugins, even being well coded, are presenting this kind of behavior on iOS 9, and it is not the first time that something like this happens. The main point here is that Firefox Safari and Safari Mobile support the experimental position: sticky;, so did Google (Chromium) but, due to integration problems, has had to temporarily disable it, you can read more about it here. Having said that, my guess is that, very soon, position: sticky; will be part of the CSS specification and supported by all major browsers, thus I think the best approach to solve this issue is to use a polyfill instead of a plugin. Of course, a polyfill will not cover all the features and functionalities that these plugins offer. Nevertheless, in many situations, using a polyfill will do the work, as a robust and effective solution supported by all major browsers. In my opinion it is the way to go, for now. I personally use stickyfill although I am sure other polyfills in the wild will do the trick. All I can say is that, since I started using a polyfill instead of plugins, I have not had any browser compatibility issues.

Ephrem answered 19/11, 2015 at 7:53 Comment(0)
M
0

Add this to your fixed element
Using a Mixing: @include transform(translate3d(0px,0px,0px))
Using CSS: translate3d(0px,0px,0px)

Masuria answered 7/2, 2016 at 10:36 Comment(3)
Using "SCSS" is just wrong. What you recommend to use is a mixin, probably from compass...Possibility
Using SCSS is not wrong it's simply a way of saving yourself the trouble of having to type in every single browser prefix.Lafreniere
.... urm.... except this is [probably] just an iOS '.issue' and therefore you don't need to worry about any prefixesDelaney

© 2022 - 2024 — McMap. All rights reserved.