Web Designer Pro Bundle - $500 of Site Templates, Stock Photos, Code, Graphics and more for only $20
iOS 5: Fixed Positioning and Content Scrolling

iOS 5: Fixed Positioning and Content Scrolling

Tutorial Details
  • Technology: iOS 5 + Mobile Safari
  • Difficulty: Beginner
  • Completion Time: 15 - 30 Minutes

Two of the most celebrated enhancements to Safari on iOS 5 are fixed positioning and content scrolling support. This tutorial will teach you how to take advantage of this change and what the implications are for stop-gap JavaScript libraries like iScroll.


In a previous tutorial, I talked about iScroll and how this great little plugin helped fix an issue with iOS Webkit (5.0 and below) and Android Webkit (2.1 or below), in which there was no native support for fixed positioning or scrollable content areas.

So, after a weekend of running various tests, it’s nice to confirm that the iOS 5 Safari update now tackles both of these issues and we now have full native support for them. It has been in the pipeline for some time in terms of the beta releases for iOS 5, but you can never guarantee that these things will make it to the final release.

In this tutorial, I will discuss this change at length and also teach you how to convert the iScroll project from our previous tutorial to using the new CSS properties.


What Does This Change Mean?

To be explicit, we now have the ability to build web apps that have fixed headers and footers using position:fixed as well as scrollable content in between using -webkit-overflow-scrolling. This allows us to build applications with a more native feel without needing to resort to a third party plugin, such as iScroll. As you will see though, for now there are still some good reasons to depend on third party libraries like iScroll.


The Caveats

While this change is great news for web developers, there are a few caveats worth discussing.

First, the most obvious one is that this feature is currently only supported in Safari 5.1. While the new 4S has seen record pre-orders, and many past users have already upgraded to iOS 5, there are still going to probably be a substantial amount of iOS device users on 5.0 or lower.

Next, there is currently no way to remove the scrollbar that appears in the side of the content area. You could try doing something with the webkit-scrollbar CSS method to change colors etc, but I don’t see this as a massive issue. The scrollbar is a nice UI element that makes the user aware of where they are in the document. Why bother removing it?

Another issue: there’s no way to define the ‘rubber banding’ area of the browser, as it will just rubber band at the very top and bottom of the screen area, including the address bar. I had begun working on a bit of JavaScript to manually offset the scrollTop value at either end by 1, but then I found Joe Lambert had already done this with scrollFix.js.

Finally, the scrolling momentum currently has no speed control. This would be more of a nice-to-have.

That’s enough with the issues, let’s take a look at how we can begin using the newly supported CSS!


Step 1. Remove the JavaScript

Let’s take a look at how to convert our past project to using the new CSS rules. We’ll use our previously built page with iScroll for demonstration.

The first thing to do is to remove the JavaScript include and the iScroll call from the bottom of the document, so you end up with a plain HTML and CSS file like the one below:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
<meta name="apple-mobile-web-app-capable" content="yes" />
<title>Web App Template</title>

<style type="text/css" media="all">
body,ul,li {
	padding:0;
	margin:0;
	border:0;
}

body {
	font-family:helvetica;
}

header{
	background-color:#deb500;
	position:absolute;
	z-index:2;
	top:0; left:0;
	width:100%;
	height:45px;
	padding:0;
}

footer {
	background-color:#c27b00;
	position:absolute;
	z-index:2;
	bottom:0; left:0;
	width:100%;
	height:48px;
	padding:0;
	border-top:1px solid #444;
}

header, footer{
	font-size:20px;
	text-align:center;
	color:#f3f3f3;
	font-weight:bold;
	text-shadow:0 -1px 0 rgba(0,0,0,0.5);
	line-height:45px;
}

#wrapper {
	position:absolute;
	z-index:1;
	top:45px; bottom:48px; left:0;
	width:100%;
	background:#aaa;
	overflow:auto;
}

#scroll-content {
	position:absolute;
	z-index:1;
	width:100%;
	padding:0;
}

ul {
	list-style:none;
	padding:0;
	margin:0;
	width:100%;
	text-align:left;
}

li {
	padding:0 10px;
	height:40px;
	line-height:40px;
	border-bottom:1px solid #ccc;
	border-top:1px solid #fff;
	background-color:#fafafa;
	font-size:14px;
}
</style>
</head>
<body>

<header>
	Web App Template
</header>
<div id="wrapper">
	<div id="scroll-content">
		<ul>
		<li>Some Stuff</li>
		<li>More Stuff</li>
		<li>Big Stuff</li>
		<li>Small Stuff</li>
		<li>Geek Stuff</li>
		<li>Nerd Stuff</li>
		<li>Fast Stuff</li>
		<li>Slow Stuff</li>
		<li>Good Stuff</li>
		<li>Bad Stuff</li>
		<li>Your Stuff</li>
		<li>My Stuff</li>
		<li>Their Stuff</li>
		<li>Our Stuff</li>
		<li>Super Stuff</li>
		<li>Uber Stuff</li>
		<li>Stuff Stuff</li>
		<li>French Stuff</li>
		<li>German Stuff</li>
		<li>English Stuff</li>
		<li>American Stuff</li>
		<li>Stuff</li>
	</ul>
	</div>
</div>
<footer>
	Some Footer Content
</footer>

</body>
</html>

Step 2. Adjust the CSS

We don’t need to change our HTML at all. We just need to adjust some of our CSS and add one new class.

-webkit-overflow-scrolling : auto;

This is the new class that was introduced around beta 2 of iOS 5, and it is the one that gives us the nice momentum scrolling. By default, it is set to auto, which gives the scrolling a rigid look and feel. To give your scrolling area a more native feel, set this property to touch.

-webkit-overflow-scrolling : touch;

Now, apply this style to the scroll-content div and we are going to remove some of the styles from the wrapper, mainly the positioning and overflow. In fact, we really don’t need the wrapper div at all, so you can remove it if you wish, but I like to have a div around just to wrap anything if need be. The two CSS rules should look like below:

#wrapper {
	z-index:1;
	width:100%;
	background:#aaa;
}

#scroll-content {
	position:absolute;
	top:0;
	z-index:1;
	width:100%;
	padding:0;
	-webkit-overflow-scrolling:touch;
	overflow:auto;
}

Step 3. Fixing the Header and the Footer

Before, we had the header and footer set to absolute (as fixed was not supported). We can now go ahead and position these in the CSS using the fixed rule to stop them from scrolling away on the screen.


header{
	background-color:#deb500;
	position:fixed;
	z-index:2;
	top:0; left:0;
	width:100%;
	height:45px;
	padding:0;
}

footer {
	background-color:#c27b00;
	position:fixed;
	z-index:2;
	bottom:0; left:0;
	width:100%;
	height:48px;
	padding:0;
	border-top:1px solid #444;
}

If you don’t know the difference between fixed positioning and absolute positioning, the short version is that absolute positioning is a defined position relative to its parent element. Fixed positioning is a position fixed within the viewport.

You will now have a scrolling area with a fixed header and footer, without the use of Javascript!


The Future

It’ll be nice when other browsers play catch up (Window phone I am looking at you!) and the majority of users are on an Android OS higher than 2.1, but the near future should see some nice improvements on the webkit based browsers. With speed increasing on each iteration, apps made with web-based technologies might quickly overtake native applications. All we need now are more native APIs!


Where Does This Leave iScroll?

iScroll still has a place at the moment. There are many parameters we can pass through to the scrolling method to give some additional options to the way our scrolling works and looks that can’t currently be achieved without writing custom JavaScript…so why not use what is already available?

There is also the issue of browser support. Maybe you really need the fixed toolbars for you project in older implementations of the webkit browser. Well, no problem. If it’s the best thing for the project, then there is no shame in using one of the existing JavaScript libraries to achieve it. However, I would suggest using the native implementation whenever possible.

Going beyond the simple scrolling functionality, the iScroll library also offers some great supplemental functionality such as “Pull To Refresh”, “Pinch / Zoom”, and “SNAP / Snap to Element”. We can cover these in a later iScroll tutorial, as they are still useful and relevant features.

Add Comment

Discussion 13 Comments

  1. Mike says:

    I just built a web app for the company I work for that uses iScroll. We are planning on getting rid of it and using the new fixed positioning update in iOS5. The iScroll method has been a pain. Certain input elements don’t work, and you have to put in a “hack” to get around it.

    Since it is an internal application, we can tell everyone to update to iOS5 or you will just have to scroll down to the bottom to get to the bottom tool bar.

    One potential problem with this new update, is when I build websites that have fixed positioning, I know that up until now, the iPhone changes it to absolute positioning basically. That is fine, but when I went back to a site that I built with ios5, the fixed element is now stuck in the middle of the screen which wasn’t expected.

    • Shaun says:
      Author

      iScroll can be a pain in certain circumstances, but I have also found it to be a blessing in others. It’s great that the Safari team have finally decided to support fixed positioning and even better when you are able to use it, such as with your internal application.

      Backward compatibility might be an issue for those looking to go ahead and remove iScroll from older applications. iScroll did require that certain elements to be positioned absolutely in order for the plugin to work, so my advice would be just to double check your containers / scroll area positioning. It sounds like something might be positioned absolute & not taking up any space in the document.

  2. Don says:

    Is this a bug in the implementation of position:fixed?
    http://db.tt/rJObqWZZ

    • Shaun says:
      Author

      There certainly seems to be some issue with this – which could be a big usability issue if not fixed. I will continue to look at it and see if it’s something that can be sorted, but nice find.

      Have you reported it to the Mobile Safari team?

  3. Argyle says:

    i’m livin in this same world right now, web apps, but i’m using jQuery Mobile. they’ve updated their build to include this support. finally!

  4. iScroll have problem with form elements so I don’t use it

  5. I created this demo using the code in tutorial. But why horizontall scrollbar is coming http://jsfiddle.net/jitendravyas/3Bqbf/show/

    • Shaun says:
      Author

      Hi Jitendra,

      I had a look at the page in an iPhone 4 running iOS5 and it seems that you probably need to make sure that you are using the meta viewport tag –

      the width=device-width is the one that doesn’t seem to be set.

      Thanks

  6. Will Morris says:

    I’ve found that if you have a text input in a position:fixed , when you focus on the input box, the iOS keyboard comes up and the entire header is moved to the center of the screen.

    This isn’t desirable behavior. If I have a header fixed to the top of the screen, I want it to stay there. Have you experienced this and do you know of a work-around?

    Thanks!

    • Verb says:

      @Will There is a jquery workaround that I implemented on one of my sites. It pretty much hides the fixed element when a user focuses on the input field and shows once unfocused.

      Example code:

      $(document).ready(function() {

      $(‘input’).focus(function() {
      $(‘.header_fixed’).css(‘display’, ‘none’);
      }).focusout(function() {
      $(‘.header_fixed’).css(‘display’, ‘block’);
      });

      });

      Hope this helps!

  7. We have a website with a fixed background image on the body. The content simply scrolls over this background image in all browsers, but the background-position:fixed property does not seem to work on the iPad. Any insight into this?

  8. Justin Avery says:

    I have a horizontal unordered list product navigation element that is 2300px wide. I have a wrapper div which only displays 600px of the navigation allowing the user to scroll through the different products.

    I updated the -webkit-overflow-scrolling : touch; because the standard scroll method was too static and rigid and I wanted the momentum on the scroll.

    Now there is an issue through, and the images disappear while the scroll is in momentum, and paint on the screen once the scroll momentum stops.

    Is this a know bug or an issue with my implementation?

    code can be seen http://dev.justinavery.me/colemanipad/index2.html

    • Ayko says:

      I’ve noticed that -webkit-overflow-scrolling : touch; has got some troubles with relative positioning.
      Maybe if you remove the position: relative on #productNav the scrolling will work without the disappearing images.

Add a Comment

To add a code snippet to your comment, please wrap your code like so: <pre name="code" class="html">YOUR CODE</pre>. You can replace the class name with "js," "css," "sql," or "php." If there are any "<" or ">" within your code, please search and replace them with: &lt; and &gt; respectively.