Hacking CSS position:fixed with position:absolute

Objective: Create a fixed position header and footer while maintain the scrolling functionality cross-browser.

Looking at tables for position:fixed support you can notice, the support is fairly good these days. Still I meet people with Android running version Android < v3 and (maybe fewer) iPhones running version of iOS <5.

Point of having a website, not an app is to be accessible as much as possible. But what if you still want to have cutting edge design, even just to wow your customers.

Hacking position fixed

There’s a way, however it’s not so smooth. It’s possible to hack position:fixed using just position:absolute, however overflow-y:auto is required. It’s tricky to say what’s the browser support for this:

According to some, the overflow scrolling has following support:

  • Android Browser from Android v3+
  • Blackberry Browser v6+, momentum scrolling since v7
  • IE Mobile 9+, momentum scrolling since v10
  • Opera mini – NO, but hackable
  • Opera Mobile – yes, but requires absolutely position, top & bottom values
  • two finger scroll: iOS <=v4, yes: iOS 5 (momentum should work with CSS declaration -webkit-overflow-scrolling: touch)

Source: Overflow Scrolling

Q: What is 2-finger scrolling?

iOS 5 provides 1 finger scrolling when an element has the following CSS property:

-webkit-overflow-scrolling:touch;

iOS 4 can use 2 finger scrolling (which is near worthless since users don’t know that they have this option) on elements that have, I believe, a set height and overflow: scroll.

Source: Two finger iPhone scrolling

Outtake: Desktop seems solid, old Internet Explorers are buggy. On mobile, new devices are all OK, old-ones are buggy. From my own experience, I remember 2 finger overflow scroll on iOS<=5, I experience lost of momentum even with -webkit-overflow-scrolling: touch. I got my hands on some Androids, I guess it even one of the first Samsung Galaxy line, without overflow-y support.

Testing the feature is probably impossible, if you know a way please leave a comment.

Note: CSS Overflow property explained

Yet Another Scroller Script

Ever heard about the iScroll script the fake-scrolling script, right? Taken from the post about first version:

iScroll was born because mobile webkit (on iPhone, iPod, Android and Pre) does not provide a native way to scroll content inside a fixed width/height element. This unfortunate situation prevents any web-app to have a position:absolute header and/or footer and a scrolling central area for contents.

Luckily mobile webkit offers a powerful set of hardware accelerated CSS properties that can be used to simulate the missing functionality, so the iScroll development started…

The thing about the mobile, webKit and hardware accelerated CSS properties bugs me. And another thing: there’s a download PFD manual button in the menu. Yeah, obviously it’s not that a simple script to use for a feature that is that simple.

I’ve created a scrolling script in < 300 lines of commented javaScript compared to ~1000 lines of Lite version or ~2000 lines of full iScroll version mostly without comments. (It’s still in the proof-of-concept stage supporting vertical scrolling and mobile touch events, sorry IE).

Udate: The script has evolved, see the scrollPolyfill.js repository on GitHub

Other scrolling scripts:

It requires:

  • javaScript to be turned on; conditional Modernizr styling using .js and .no-js class on HTML element is pretty straight-forward;
  • NO hardware acceleration; no support for transition:translate3d,…;
  • NO setup at all, just include the script

Try the scroll on your mobile device and compare version A with version B. There’s an inner scroll area starting with the header:

A version with the script (try on touch mobile device):
B version without the script (try on touch mobile device):
How does the script work

Script changes the native element.scrollTop value. That’s why it does not require hardware accelerated support. Most of all it fixes a nasty behaviour of the most devices: delayed scroll event firing on mobile devices when the scroll event is delayed until the momentum scrolling is finished causing stutter making any parallax on mobile devices unusable.

Where to optimise:

Note: If you are interested in co-authoring the script, please leave a comment.

The Hack: position:fixed using position:absolute

Demo of the principle. On mobile however, it might not work as expected. Please try desktop browser.

Header

↓ Scroll down ↓

Footer
<section class="demo-container">
  <header class="demo-header">Header</header>
  <article class="demo-article">
    <p> ↓ Scroll down ↓</p>
    <div class="demo-long-content"></div>
  </article>
  <footer class="demo-footer">Footer</footer>
</section>
/* We need to force maximum height and overflow hidden on body element */
html,
body {
    height: 100%;
    margin: 0;
    overflow: hidden;
    padding: 0;
    width: 100%;
}
.demo-container {
    background: yellow;
    height: 400px;
    margin: 0;
    overflow: hidden;
    padding: 0;
    position: relative;
    text-align: center;
    width: 100%;
}
.demo-header,
.demo-footer,
.demo-article {
    left: 0;
    position: absolute;
    right: 0;
}
.demo-header,
.demo-footer {
    background: red;
    color: white;
    height: 10%;
}
.demo-header { top: 0 }
.demo-footer { bottom: 0 }
.demo-article {
    bottom: 10%;
    overflow: hidden;
    overflow-y: auto;
    top: 10%;
}
/* Force scrollbars */
.demo-long-content { height: 400% }

Accessibility of Content

That’s it. It’s that simple. There’s however accessibility concern, whether the hidden content can be accessed by the user, if the overflow-y:auto is not supported.

By adding my scroller script we could say, the scrolling is polyfilled for those without native support, and since we use javaScript to polufill native feature, we can conditionally set CSS to prevent from hiding content unless javaScript can fill the blanks.

The CSS rules are applied only when [condition that] some parent (usually the HTML node) has a .js class applied, therefor no content gets hidden, unless we can support polyfilled experience. See modified CSS:

/* We need to force maximum height and overflow hidden on body element */
html,
body {
    height: 100%;
    margin: 0;
    padding: 0;
    width: 100%;
}
.js body {
    overflow: hidden;
}

.demo-container {
    background: yellow;
    margin: 0;
    padding: 0;
    position: relative;
    text-align: center;
    width: 100%;
}
.js .demo-container {
    height: 400px;
    overflow: hidden;
}

.js .demo-header,
.js .demo-footer,
.js .demo-article {
    left: 0;
    position: absolute;
    right: 0;
}

.demo-header,
.demo-footer {
    background: red;
    color: white;
}
.js .demo-header,
.js .demo-footer {
    height: 10%;
}

.js .demo-header { top: 0 }
.js .demo-footer { bottom: 0 }
.js .demo-article {
    bottom: 10%;
    overflow: hidden;
    overflow-y: auto;
    top: 10%;
}

/* Force scrollbars */
.demo-long-content { height: 400% }

The .js class conditional can be used e.g. while using Modernizr based on Paul Irish technique.

Let me know what you think in the comments below.

*Cheers