Fixed Positioning in Mobile Browsers

Fixed positioned elements (typically headers or footers) are extremely common conventions for native mobile platforms, so naturally fixed elements found their way into mobile browsers. Web designers are used to fixing elements to the window using CSS’s position: fixed, however, in the land of mobile browsers, support for fixed positioning is far less universal and is way more quirky.

I set up a demo to test fixed positioning support across mobile browsers. You can view the demo here. I was particularly curious to see how fixed positioning worked without disabling the user’s ability to scale the page.

The Test

The actual test is as absurdly simple as you can get.

header {
     position: fixed;
     top: 0;
     left: 0;
     width: 100%;
}

Talk about basic. Let’s see how this is supported on mobile browsers.

Mobile CSS Fixed Positioning Support

  • Mobile Safari – iOS5 and after has strong support for fixed positioning. iOS4 and below simply treats elements as static and scrolls them along with the rest of the page.
  • Android
    • Android 2.1 and below no fixed positioning.
    • Android 2.2 awkwardly snaps fixed elements back into position once scrolling is complete.
    • Android 2.3 supports fixed positioning, but disabling page scaling is required.
    • Android 3 and 4 supports fixed positioning (even without disabling page scaling). Does pretty well performance-wise.
  • Blackberry 5.0 supports fixed positioning, although fixed elements are jittery
  • Blackberry 7.0 – supports fixed positioning (I could only test on a simulator)
  • Blackberry Playbook (1.0.7)- supports fixed positioning. The biggest WTF bug is that it appears the BITMAP all the text inside the fixed positioning element, leaving the text fuzzy and jagged.
  • Firefox Mobile – Supports fixed positioning as of 6.0 (many thanks to @alex_gibson for testing this). On older versions, fixed positioned elements scroll with page and then awkwardly snap back into position once scrolling is complete.
  • Opera Mobile – Fixed positioned elements scroll with page and then awkwardly snap back into position once scrolling is complete. WTF bug: Opera miscalculates positioning and awkwardly places fixed headers further down the page.
  • Opera Mini – nope.
  • Windows Phone 7 – both pre and post-Mango ignore fixed positioning and render fixed elements as position: static. (Big thanks to @wilto for testing on Mango)
  • WebOS – 2.0+ supports fixed positioning
  • Amazon Kindle Fire – similar to Android 2.3 in that it supports fixed positioning, but disabling page scaling is required.
  • Amazon Kindle (Netfront) – YES!, which is hilarious. Kindle’s browser doesn’t even support color but does a better job at fixed positioning than other mobile browsers.
  • Nook Color (1st and 2nd gen) – Performs like Android 2.3: supports fixed positioning, but disabling page scaling is required.

Maximiliano Firtman’s amazing Mobile HTML5 site features a chart of fixed width mobile browser support, but (as you can see from the above results) “support” isn’t exactly binary.

Twitter's mobile site on iOS and Android

Twitter's mobile site features a fixed header for iOS but not for Android

Javascript Solutions

Because mobile browsers lacked of CSS fixed positioning, some very smart people developed Javascript-based fixed-positioning solutions. Here are just some of the more popular ones:

  • iScroll 4 is relatively mature and performs decently well on platforms other than iOS.
  • Scrollability was created by Joe Hewitt and is targeted at iOS but also roughly works on Android.
  • Sencha Touch is more than just a Javascript library, but rather a mobile app framework. Targeted primarily at iOS, they’ve made a lot of effort to improve performance on Android and Webkit Blackberry.
  • Jquery Mobile is another framework that includes a version of fixed elements, although it’s not persistent fixed positioning. Fixed elements fade out when the page is scrolled, then fade back in when scrolling ends. Check out a demo.

Problem solved, right? Well, not exactly. Overriding the browser’s default scrolling behavior introduces a whole lot of complexity, and that has implications. First, JS solutions definitely don’t work across the board. Consider the vastly different results of the three lines of CSS in my test, and picture how a complex Javascript calculations might fare. Performance is key, and heavy JS usage can take it’s toll when combined with the rest of the logic on the site/app. Also, the platforms that best support these solutions are also the ones that best support CSS fixed positioning (iOS5 being the poster child here).

I’m going to pick on Paper.li’s mobile site as a great example of what not to do. Their JS scrolling is clunky, entirely unnecessary and introduces a whole bunch of usability issues (i.e. I couldn’t get to to Android’s address bar because of the custom scrolling logic). In essence, they make it a whole lot harder to view their content.

I recommend taking it on a case-by-case basis. I think JS solutions serve their purpose, but I don’t know if sites deployed on the web is the best place for them. I think they make more sense for Phonegap projects or other projects where you have tighter control over device access.

Considerations

So what are you to do? Here’s some things to think about as you approach this sticky situation (pun intended in the worst way possible):

  • Take a step back and understand why you need fixed positioning in the first place. Ask this very important question: Is it essential to the experience?
  • Don’t assume support for fixed positioning by default.
  • Beware of a whole host of false positives and quirky bugs.
  • Rewriting scrolling logic with Javascript can introduce more problems than it solves if you’re deploying your site/app across the web.
  • Conditionally include JS-based solutions as to not deliver a broken experience to non-optimized platforms.
  • Maybe consider sniffing user-agent strings for capable in order to optimize the layout without breaking the experience in other browsers.
  • Disable viewport scaling when incorporating fixed-positioned elements to avoid awkward behavior.
  • What happens on orientation change? Consider screen real estate issues for landscape mode and devices with different screen heights (such as Blackberry Curve).

Takeaway

Ultimately, I think this little exercise is another example of why we need to consider diversity in our designs. Removing comfortable assumptions, even for something seemingly as harmless as a fixed header, can help us design better, more adaptive experiences. I believe that we can create great, innovative mobile experiences for best-of-breed devices without giving the middle finger to everything else.

43 Comments

  1. You must know IScroll has a VERY ANNOYING bug : if you use an input boxes and click into it, you can’t type. I have tried on Android 2.3(HTC Desire) and on IPhone 4S, so be careful if you use it.

  2. Yeah, fake scrolling is horribly difficult to implement, and nobody ever likes how it turns out. For best results, push back on your designer and ask her to do something else.

    I was delighted to discover Android’s support for position:fixed while developing Netflix for the iPhone; unfortunately there’s a problem (at least in Android 2.2) with INPUT tags. When focused, they grow an extra completely unstyleable overlay, which floats away when you scroll. (StackOverflow help request is here, if you’ve got a fix: http://j.mp/tYOXel)

    Thanks for the post, and the pointer to Maximiliano’s site, which is awesome.

  3. Brad, this is a great! Thank you for the time taken to delve into this.

    In your experience, is it an acceptable practice to implement fixed position elements and revert them to static positioning using CSS media queries?

    • @Kyle, if anything, it should be the other way around. Assume static positioning by default then enhance up to fixed positioning. However, lots of platforms support media queries and mishandle fixed positioning so you’re still left with a lot of false positives. Check out PPK’s excellent table on media query support on mobile browsers: http://quirksmode.org/mobile/tableViewport.html#mediaqueries

  4. hey brad,

    i’m doing a mobile/tablet webapp right now, and i’m using modernizr to detect features. i was wondering if there is any kind of test we can add to detect position:fixed.

    i don’t really care if a browser supports it or not. what i do care is about the lousy experience android 2.2 offers, by positioning the header on top only after i stop scrolling. that looks buggy and doesn’t provide a good experience and that’s what worries me.

    thanks!

    • Unfortunately, there’s no cut and dry method of detecting fixed positioning and assuring that it works properly across the board. That’s why I recommend considering user agent sniffing in order to control what devices gets the fixed treatment. It’s definitely a hack but at the same time it avoids the jumpiness you see on Android 2.2, FF, Opera and others.

  5. Thanks for the mention Brad. We’ve solved Android scrolling performance in Sencha Touch 2 – it’s in preview now. @Kent – you’re right that scrolling is very difficult to get right – it took us 5 tries to get it working on iOS for Touch 1.0 and another 3ish for Android in Touch 2.-, but I have to say people seem to be happy with the final results.

  6. Very nice comprehensive review Brad. Just to point out — and I’m biased :) — Sencha Touch does accommodate for all the quirky input issues on Android, and I believe offers unmatched performance for Android — but yes, as you mention, we’re a complete app framework, not a drop-in scrolling solution.

    @kent — Why’s the designer got to be a girl, yo? :)

  7. Lukasz Fiszer

    Thank you a lot for this extremely useful article! I’ve recently spend few days exploring the position:fixed subject and this is the most complete knowledge source I’ve found. It will save me hours, if not days of work! Thanks once again!

  8. Thanks for this – been looking at this as a possibility so it’s nice to know the limitations. Also appreciate the link to the Mobile HTML5 site – another great resource (and much better than the Excel version I was maintaining).

  9. That’s a lot to take in, but great review. Hopefully with HTML5 there we might eventually see some kind of mobile standards established.

  10. There is also a tiny problem with iOS5 fixed:position ability. Using fake scrolling (scrollTop), the element does follow the scroll but, after the fake scrolling is complete, its children and itself will remain inactive (if links: not clickable) until you physically scroll with your finger a few pixels. That’s make it totally unusable for a one page nav menu.

  11. Correction, iScroll actually works fantastically on iOS devices (4.0+) especially playing with other scripts there seems to be no conflicts. I’m currently invested in developing a full web based iOS app, using iScroll as the core scrolling handler.

    Documentation is a bit rough but a highly recommended script.

  12. Bob Moore

    iScroll4 behaves quite well on iOS devices. Includes snap to element, pinch zoom option, etc. Recommended if your target is iOS.

  13. Hi Brad – Awesome research. We looked at using position:fixed for jQuery Mobile over a year ago and support wasn’t great, but this had made me re-test and it seems like a good option now, especially because it degrades so nicely.

    I ran through our test devices in the lab and summarized the results here so we can compare notes:
    https://github.com/jquery/jquery-mobile/wiki/Position:fixed-and-Overflow:-testing

    Interestingly, on our Android 2.2 device (Droid, version 2.2.20.A955.Verizon.en.US) didn’t have any issues with position:fixed when zoom is disabled. It stayed fixed.

    In BB6, fixed headers sort of work (either zoom setting). They scroll out of view, then re-appear when scrolling stops. When scrolling up, they look like they get stuck in the middle of the page during scroll, then re-position. This is probably the worst case scenario.

    BB5 is similar to 6 but re-positions more frequently, leading to the jitter you mention. Still not horrible, but far from true fixed. Overflow is busted.

    Playbook and BB7 both handle fixed nicely. Overflow is pretty bad in 7, but slickon Playbook.

    I can re-test if needed on specific devices.

  14. Great research. I was looking for this info. Thanks brad for testing on all devices. I’m wondering how Google’s web apps and Twitter mobile website are having the fixed scroll bar perfectly working?

  15. Timo

    I tested your demo on WP 7.5. Both header and footer are fixed in “scrollable region w/zoom” and “scrollable region w/out zoom”

  16. you mentioned “Twitter’s mobile site features a fixed header for iOS but not for Android” but on my Android 2.3 the top header is fixed. I’m checking in Android default browser

  17. Forgot to add screenshot in last comment it’s here http://twitpic.com/7vpb84

  18. Firefox 8 and 9 Beta both still has same behavior like 6.0

  19. Great research. I was looking for this info. Thanks brad for testing on all devices.

  20. Very nice! Thanks a lot!

  21. I’ve found iOS5 will jitter the fixed element, it’s more noticable on bigger elements but it definitely jumps around if you look at it. Kinda annoying.

  22. I’ve just spend 2 days over the position:fixed and now I see the light. I must do a different design :)

  23. I like games, very nice free online game

  24. I would have liked to see how the different devices behave when you change the orientation to/from landscape. We did some tests yesterday on some Android devices and not all of them resized the fixed elements to 100% in width. We also had a case on the Samsung Galaxy Nexus, where it would not always use the position correct, sometimes we had a single pixel line at the sides that was visible (imaging having a horizontal bar, but not on position 0 but on 1).
    Wish it would be possible to specify on the fixed elements if they should zoom or not.

  25. Hi Brad,

    Very useful article, I’m struggling with this issue myself at present and I think we’re going to provide fixed headers where the browser supports it as per your list.

    I added a link on the following stack overflow article.

    http://stackoverflow.com/questions/9269663/jquery-mobile-fixed-headers/10757111#10757111

    Regards,
    Steven

  26. Derrick

    Great post, one of the most frustrating things I have run into on the mobile web

  27. Something I just encountered that seems worth mentioning here is that if you have a container which has a transform applied to it (think translate3d), it will break the fixed effect.

    “Any value other than ‘none’ for the transform results in the creation of both a stacking context and a containing block. The object acts as a containing block for fixed positioned descendants.” (http://www.w3.org/TR/css3-2d-transforms/)

  28. hey man, awesome post. really summed up the problem well with good research. you also seem to have a serious case of gadget hoarding :P

  29. Quagnitia is a leading service provider of IT solutions and services, committed to assist businesses meet their challenges and business objectives since nearly a decade.application development for mobile

  30. I am using an overlay (width: 100%; height: 100%; position: fixed) works great on ios in safari. but ios chrome doesnt scroll with the page. :( Make sure to test on other browsers on each device.

  31. Lohith

    Hi.. Brad i have to create a mobile web application.. so is that enough your website html5Rocks.. can you suggest how to create a mobile web application step by step as am new to this…

  32. Brilliant research, web development is stressful at times and stuff like this very time consuming (which the client isn’t paying for)
    It helps so much when people like you put this kind of info out there, much appreciated.

  33. Milan

    Saw you fixed positioned header and footer div which is working perfectly. But there is one problem I am having with test page that If I got linked item inside the fixed positioned element they’re becoming inactive when scrolling the page. It works when my scrolling offset is top/left, but when you start scrolling x/y the link or buttons stop working?

  34. Dan Weaver

    Thanks for the research, awesome job.

    Seems to suggest that as long as the design doesn’t *rely* on a fixed element then just include it and worse-case scenario is that it will scroll away with the page. I’m thinking mainly about nav bars.

  35. Hi, there.
    I see fixed headers in mobile are very difficult to achieve. After spending many hours trying to solve problem, I decided to give up. No fixed headers in mobile for me. Maybe when fixed position is better supported I’ll change my mind. Anyway, great article!

  36. Great article.

    Its too bad that pinch-zoom isn’t simply treated as ctrl+wheel-zoom in the browser , then this would be easy to handle without ugly hacks.

    I have (kinda) fixed it, by setting for example: meta name=”viewport” content=”width=768″ in the header , and then using @media in css to only use position:fixed on larger screen-sizes than set in viewport.

    But this will be a problem as devices that obey the meta viewpost gets better screens.

  37. An alternative to using position:fixed is using overflow (with overthrow.js shim for older mobile browsers, see http://filamentgroup.github.com/Overthrow/ ).

    As you can imagine it’s the inverse approach… rather than keeping the header fixed and scrolling the entire page underneath this instead involves keeping the header position:static but putting the rest of the page in a scrollable overflow. This approach has some other benefits… because you’ve got distinct unscrolling and scrolling areas (rather than the entire page scrolling under a position:fixed header) the CPU/GPU can compose pages better and prevent tearing that you’ll often see on hardware accelerated mobiles. Position:fixed tearing is often visible as you scroll and bits of the header will ‘tear’ off during a scroll for a fraction of a second and then disappear … I think the CPU sends bitmaps to the GPU for scrolling but position:fixed and the underlying page as treated as a single layer which makes them both move until the CPU sends another frame to the GPU and so there’s visible tearing.

    You can see the overflow technique at MaoriTelevision.com’s TV Listings http://www.maoritelevision.com/tv/schedule . This mode is only used when you shrink your screen down to 768×578 or lesser.

  38. Matt

    Hi Brad,

    First off, thank you so much for all the effort you put into the research you do. I don’t have access to many devices, so what you are doing is just awesome for people like me.

    I just have a question for you that I would love your opinion on.

    What do you actually think about disabling the ‘pinch-to-zoom’ feature on mobile devices?

    There are so many valid arguments out there. I find myself leaning towards the argument that a well thought out, responsive website shouldn’t really need pinch-to-zoom, but then I hear arguments from people, who claim to be legally blind, that even with responsive websites we should not be disabling native features?

    I’m in a bit of a conundrum. I am trying my best to follow your lead and experiment with different ways of displaying complex navigation systems on mobile devices. My main problem is that, while I come up with what I think are great ideas, they mostly require me to use position:fixed somewhere in the execution.

    I hope I am not the only person to appreciate the irony of so called, Mega Menus, becoming popular with clients again, at the same time as responsive web development!

    Thanks

  39. On samsung wave 2 this works fine:
    http://filamentgroup.com/lab/overthrow/

  40. many thks for your testing, now I am clear about the situation of fixed Support in mobile broswers

Comments are closed for this post. If you've got something to add, feel free to reach out on Twitter.