Advertisement

iOS 5: Fixed Positioning and Content Scrolling

by
Student iconAre you a student? Get a yearly Tuts+ subscription for $45 →

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.

Advertisement