Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

IPad Scroll Issues with Fixed Content


:P
On this page:

I’ve run into problems with scrolling <div> tags with iOS Safari on a number of occasions and each time, I end up wasting untold amounts of time. In typical mobile apps I create, I tend to have a header area, a content area and in some cases a footer area. The content area is wedged between the header and the footer (or the bottom of the document if there is no footer) and the content needs its own scroll functionality rather than what the built-in browser scrollbar provides.

To make this work I use absolutely positioned headers and footers (if used – typically for phone sizes only) using ‘fixed’ styling.

All of this works great in desktop browsers and just about any mobile browser. It works fine even on an iPhone, but when running on an iPad more often than not (but not always – apparently it depends on the type of content) the content area will simply not scroll.

When it happens the content appears to ‘stick’ where the page behaves as if there where no scrollbars at all – not on the page or the content area. No amount of rotating and refreshing makes it work. Oddly though it’s not every page using the same scrollable content container layout. The content styling on the container is applied to most pages in the application, yet frequently the failure occurs only on a few or even just one of the content pages – even though the content is hosted in the same freaking scrolling container.

position:fixed and –webkit-overflow-scrolling

As I’ve written about before, iOS doesn’t do smooth <div> tag scrolling by default. In order to get a div to scroll you have to use the –webkit-overflow-scrolling: touch style to force scrolling to work smoothly. Most reasonably modern mobile browsers (ie. Android 4.x and newer and even Windows Phone) do just fine with smooth scrolling by default, but iOS and old Android browsers need this special CSS hint to avoid the extremely choppy default scrolling.

According to rumors Apple does this on purpose to discourage custom scroll schemes in browsers to more or less force usage of the stock browser scrollbar. The reasoning is that the stock scrolling is very efficient while custom scrolling is supposed to be confusing and also is a resource hog for battery life. Whatever the reasoning – the behavior sucks when you run into it and while I can appreciate the ideology behind it, it’s just not realistic to expect that you won’t need quality custom scrolling in a mobile Web app.

The problem with using ‘stock’ scrolling is that applications that use sticky headers can’t effectively use the stock scrollbar, especially if the app also has to run on the desktop where the scrollbar is a big content hogging control and it just looks plain wrong to have a scrollbar next a non-scrolling region.

So in most applications headers tend to be created as ‘sticky’ elements that take up the width of the viewport, with a scrollable content area that contains the relevant content for the application.

For typical content that might look like this:

.content-container {
    position: absolute;
    left: 0;
    top: 80px;
    bottom: 1px;
    width: 100%;
    z-index: 11;
    overflow-x: hidden;
    overflow-y: scroll;
    -webkit-overflow-scrolling: touch;
}

Now if you also end up using a fixed header you might add something like this:

.banner {
    position: fixed;    top: 0;     left: 0;     height: 58px;     width: 100%;    background: #7b0105;
    background-image: linear-gradient(to bottom, #7b0105 0%, #b8282c 100%);
    color: #e1e1e1;
    border-bottom: solid 1px #7b0105;    
    padding-top: 7px; 
    z-index: 9999;
}

Notice the position: fixedstyle, which would appear to be the most obvious thing for sticky headers.

Now all issues of positions fixed aside, the above actually worked just fine for my application on every browser except on an iPad. And then only on a few content pages. The above is basically a base container layout into which other content is loaded for each page. In this case Angular views inside of the content-container element. Out of 10 pages though 2 of them would fail to scroll properly. Bah…

Remove or Override –webkit-overflow-scrolling

After doing a bit of research I’ve found that there are many problems with scrolling on iOS and most of them are related to the use of –webkit-overflow-scrolling. Countless questions regarding the ‘sticky’ scrolling and ‘stuck’ scrolling which I’m referring to here where you try to scroll the div and instead the entire page tries to move up – it appears as if the entire document is clipped without scrolling enabled at all.

The first – unsatisfactory – solution was to remove the –webkit-overflow-scrolling style (or setting it to auto) from the CSS class and the problem pages would become ‘un-stuck’. But unfortunately the scroll behavior went to shit as well as the nasty choppy scrolling returned.

This might be a reasonable solution if the content you’re trying to work with doesn’t need to scroll very much. If you only need to scroll a single screen or less, this might be just fine. However, if you have longer content that scrolls more than a screen the default scroll choppiness is really unacceptable so this is not going to work.

Use position:absolute instead

The better solution however is to  simply replace position:fixed with position:absolute if possible.

Position fixed and absolute are somewhat similar in behavior. Both use x,y positioning in the view port and both are outside of the DOM document flow so other content is not affected by the placement of containers. Both require zindex positioning to determine vertical priority in the view stack.

Position fixed keeps the element pinned at whatever position you set it to regardless of the scroll position of the browser. This makes sense in some scenarios where you actually want to scroll the entire page but leave content in place. The key to remember is to not use it when you build have your own scrollable content on the page.

It turns out in my case I don’t really need position:fixed because I manage the position and size of the container and toolbar headers and footers myself anyway. I know where everything is positioned and keep the content area effectively wedged in the middle of the statically sized elements. By way of CSS and media queries I can force the header to the top and the footer on the bottom using fixed sizes which means I can safely use position:absolute.

And yes by simply changing the position:fixed to position:absolute in the header:

.banner {
    position: absolute;
    …
}

My problem that I spend an hour trying to work around was resolved.

It’s a simple, but non-obvious solution and I’m not the first to discover it. But it also wasn’t one of the solutions I ran into while searching either at least not an easily discovered one.

In most cases when you’re doing mobile layouts you can probably get just fine by using position:absolute instead of position:fixed because you’re bound to control the viewport positioning of the top level container elements yourself. And if you really need fixed positioning, you can often use JavaScript to force the content to stay in position. And anywhere else but at the top level position:fixed doesn’t really make sense.

One place where position:fixed comes up a lot  is with the Bootstrap CSS framework. Bootstrap uses position:fixed for header and footer navbars and you can easily run into the issues described here using default Bootstrap layouts. I avoid the Bootstrap headers and footers, but the fixed positioning is just one of the many problems I’ve had with them. However, I have fallen prey to copying part of the Bootstrap header styling which is probably why I ended up with position:fixed in the first place when I created my custom headers. Live and learn.

I hope by writing this down this time I might burn this lesson into my brain as I’ve discovered this very problem before and forgot it about it, only to struggle with it again. Hopefully this post will jog my memory next time, and maybe some of you find this a useful reminder as well…

this post created and published with Markdown Monster
Posted in CSS  HTML5  

The Voices of Reason


 

Philip
December 30, 2015

# re: IPad Scroll Issues with Fixed Content

Thanks for this post! Written in June 2015 so still relevant today because users may not update their iPads to the latest iOS version. I'm deciding on using a position:absolute scolled container layout or scroll body with position:fixed for header and flyouts. I wanted to use scroll body layout so that the address bar will hide when scrolling down on most mobile browsers. But now I'm not sure it's worth it. I'm leaning towards position:absolute layouts. I wonder how much of a performance hit webkit-overflow-scrolling css actually is, especially in iOS 8 and above. Not much out there on the internet.

While looking up mobile scroll performance I stumbled across this article which is helpful: http://www.mikedellanoce.com/2012/09/10-tips-for-getting-that-native-ios.html

Thanks!
Philip

Stefan Vojnovic
October 13, 2016

# re: IPad Scroll Issues with Fixed Content

Thank you very much for in depth description of all the problem with shaby "-webkit-overflow-scrolling: touch;"

Mario Herak
October 04, 2017

# re: IPad Scroll Issues with Fixed Content

It's 2017 and iOS 10.3 on iPad still have bugs in Safari rendering engine. Thank you very much to point me at the possible solution of my problem. More than a week I had a problem regarding -webkit-overflow-scrolling: touch; CSS style. I have a modal displayed with jQuery slideDown() function. Modal had position: fixed; style and when scrolling on iPad vertically or horizontally, first time when modal is displayed, everything is OK. But when I close modal with jQuery slideUp() function and then display it again, the modal content disappear when trying to scroll the content. I can't point at the web (it's corporate web based application). After many hour and many many attempts to fix the problem, suddenly I found your article! The fix was easy as... 😉 Replacing position: fixed; with position: absolute; simply fixed my problem. Work like a charm. Thank you many many times. God bless you.


Chris@CCN
November 17, 2017

# re: IPad Scroll Issues with Fixed Content

THANK YOU!!!

I use Google Apps Script and have had zero success with fixed elements in their Web Apps on ios Safari. This is the ONLY solution I have found that has worked.

Was soooo close to giving up. I now feel re-energised!


Adam
October 08, 2019

# re: IPad Scroll Issues with Fixed Content

I wish I could force fixed position in safari due to being on relatively slow (satellite) internet, long scrolling web pages (Arstechnica = example) will continuously reposition the screen as images start coming in, so I have to wait up to a minute before I can actually read an article without it popping all over the place. extremely annoying having to keep finding my place time after time, as it moves me two screens or more from where I was reading.

This article obviously wasn’t speaking to this particular issue - but it sounds like you might know the answer - are there any Safari settings - perhaps in the experimental section, that’ll fix this?


Nithya
June 19, 2020

# re: IPad Scroll Issues with Fixed Content

I used content="width=device-width, initial-scale=1.0,maximum-scale=1.0,shrink-to-fit=no,user-scalable=0" this in my meta tag at section and put style like this html,body{ overflow:hidden;} but it works for me...I don't know it will work for you

Thanks..```


West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024