Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Absolute Positioned Floating Header Jitters in Safari

I have a simple JSFiddle of a single floating header here:

http://jsfiddle.net/zT9KQ/

Basically, this uses translate3d to kick in the GPU and hardware accelerate the floating header so that it may be drawn more smoothly. The header jitters in the latest Safari but gets drawn perfectly fine in the latest Chrome, FF and Opera. The actual code that is being affected by this (the code that spurred this question) is code I've written that cannot be shared publicly but works in a similar manner where fixed positioning is, unfortunately, not a valid solution.

I have tried:

  1. Setting the backface-visibility CSS property to none.
  2. Setting the perspective CSS property to 1000.
  3. Playing with requestAnimationFrame during the animation logic.
  4. Throttling the scroll event callback.
  5. Setting the translateZ transform to something higher than 0px.

But none of this has worked (or at least - it seems reasonable to assume the GPU has kicked in but the jittering persists). I noticed that two questions are already open that are identical this one I'm raising but no one has answered them:

  • Jitter in Sticky Header in Safari
  • Implementing fixed position in javascript causes jitter in Safari when scrolling

Is this a known bug? Is there a performance hole I'm not sealing up?

EDIT

I have been receiving a lot of questions as to why position: fixed is not a valid option. To directly reply to Antony's comment on the question itself:

I'm not emulating/reinventing position: fixed. If you look at the top-voted answer (as of this comment), you will see that this seems to be a Safari issue. The reason position: fixed is undesirable in this case is because the code in question must be able to support multiple floating headers that sit below each other and have a "container" range where there may be infinitely nested containers. Using fixed positioning not only makes the code more complicated in the case where these floating headers live in a container that horizontally scrolls but also makes the component more brittle overall (calculating offsets when the widget needs to sit within another container somewhere else on the page). So, semantically, absolute positioning fits my needs better than fixed.

SECOND EDIT

Upon thinking about what Antony had been telling me (that I may be reinventing the wheel), and after hearing about -wekbit-sticky from user3716477, I would like to update the question to show what I'm trying to do. You can see how my code behaves in every browser other than Safari here:

http://cl.ly/3y1i3C473G2G

I have learned:

  1. You cannot rely on the scroll or really any scroll-like events (such as mousewheel) since they are asynchronous in nature. I submitted a bug to Apple detailing what was happening and they closed the bug for this reason.
  2. There is no real way to do what I want as of now - to have multiple floating headers that stack and replace each other. I guess I'll have to wait for something like -webkit-sticky to come out.
  3. I should include all relevant information in SO questions from here on out. :-P

Thanks for playing guys! Here's the exact response I received from Apple:

Apple Developer Relations09-Jun-2014 01:16 PM

Engineering has determined that there are no plans to address this based on the following:

Code is using scroll events, which are asynchronous.

We are now closing this bug report.

If you have questions regarding the resolution of this issue, please update your bug report with that information.

Please be sure to regularly check new Apple releases for any updates that might affect this issue.

like image 913
Vinay Avatar asked Jun 02 '14 08:06

Vinay


People also ask

How do you get a header to stay in place?

Answer: Use CSS fixed positioning You can easily create sticky or fixed header and footer using the CSS fixed positioning. Simply apply the CSS position property with the value fixed in combination with the top and bottom property to place the element on the top or bottom of the viewport accordingly.

How absolute positioning works?

Absolute positioningElements that are relatively positioned remain in the normal flow of the document. In contrast, an element that is absolutely positioned is taken out of the flow; thus, other elements are positioned as if it did not exist.

Why position sticky is not working?

Sticky Element Has Parent(s) with overflow PropertyIf the sticky element has a parent or ancestor with overflow: hidden , overflow: auto , or overflow: scroll , then position: sticky will not work properly.

What is position fixed?

A fixed position element is positioned relative to the viewport, or the browser window itself. The viewport doesn't change when the window is scrolled, so a fixed positioned element will stay right where it is when the page is scrolled.


1 Answers

Since there is an apparent delay between scrolling with the trackpad and the scroll event firing, you can attach the handler to an additional mousewheel event to smoothen things up.

$scrollContainer.on('scroll mousewheel', function () {
    // reinvent the wheel here
});

You can see in this demo here that jittering is far less likely to occur when you scroll with the trackpad. In the demo, I have invoked the handler on load to eliminate the flash when you first scroll on Safari. There may still be some occasional jitter, but if you want to minimize that, you can go the resource intensive way of using setInterval and requestAnimationFrame.

This might fix the problem for now, but as I have said before, this emulation approach is not ideal and you are very likely to run into more trouble down the road.

like image 59
Antony Avatar answered Sep 28 '22 03:09

Antony