Last week I reported on my tests using percentage to position background-images. Today’s post is a walk thru of where I put this research to work — published earlier in the week in the July 2007 Design View.
One of the nicest things about going to a real bricks ‘n’ mortar bookstore is the effortless pleasure of thumbing mindlessly through any book that takes your fancy — not that you actually read anything in particular, but it’s just a great way to get a general sense of its layout, style, and quality.
While it’s difficult to convey information about the paper and binding quality via a screen (compared to fingertips), our marketing manager Shayne and I started wondering whether it might be possible to reproduce some of that effortless “page flicking” feel, using a touch of JavaScript.
The result of our first take on the idea is here — promoting Kevin and Cam’s new JavaScript primer, fittingly enough, although not actually part of the book’s content.
Although you’re more than welcome to pick through the live version on our site to see how it’s done, I’m going to step through you through a slightly simplified, standalone version here.
It’s a little long winded, but it’s hard to cut it much shorter without leaving out potentially important stuff.

Part I: The Starting Point
There were a few decisions I made early on in the project:
- I wanted the final product to be as flexible as possible, so that I could add or subtract pages and alter the page sizes without having to make major changes to the code.
- I needed all of the individual book pages (between eight and 16 pages) to be contained in a single, large, flat rendered image (like this one). This meant that I could guarantee that all my page images were downloaded and “ready to rock” at the first sign of a click.
It also meant that I could overlay the rendered 3D elements of a turning page on a separate, reusable PNG layer (like the one shown below). This one is obviously setup for our blue and orange page head and footer, so you might need to generate a plain white version for use on other books.
Displaying just the central third of the page gives us only the shaded curves of the inner spine — great for adding some depth to the book sitting open. When our user attempts to “turn” a page forwards or backwards, we can then align this background image to either the right- or left-hand side of our book respectively. These three simple frames go a long way toward creating the illusion of a turning page.

- I wanted to base my solution on jQuery, because of its easy-to-learn syntax, small size (20k), and speed.
Part II: The Structure
The markup structure we’re going to use is a construction of four divs.
1. div#leftpage: the left-hand page
2. div#rightpage: the right-hand page
3. div#flip: the midway point between the pages
4. div#turner: a wrapper to hold the whole thing together

div#flip is set as ‘position:absolute’, so we can float it centrally over our spine region.
The other three divs are all set to position:relative, and floated to the left so that they stack together neatly. I’ve set my page dimensions to be 189px x 146px, but there’s nothing special about these dimensions — they just happened to be about the right size for the page area I had available.
Once our page inserts our images into their div backgrounds, our static book is ready, waiting for jQuery to make it dance.
Part III: The JavaScript
1) The setup
Time to get our hands dirty. The first thing we need to do is attach jQuery to our document and add a new script tag to contain our custom script.
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript>
/* our script goes here */
</script>
2) Setting up some useful variables
We have a handful of numbers that we’ll need to use several times, so it makes sense to store them in variables. That means we’ll only need to update our script in two places if we decide to change our page size later. The variable names do a fairly good job of describing what they are:
/* Page sizes*/
var $pageheight = 189; // our page height
var $pagewidth = 146; // our page width
var $pageYpos = 0; // current Y position of our bg-image
3) Setting up our ‘ready’ event
One of the things I like about jQuery is its simple document ready event, which is a souped-up replacement for the old-fashioned onLoad event.
Any code placed inside this ‘ready event’ will be executed as soon as the bits it needs are available. It looks something like this:
$(document).ready(function(){
// Your code here
});
The nice part is that jQuery’s ready event will begin working as soon as the parts it needs are downloaded — the old-school onLoad event had to wait until your page had completely finished loading. If you begin experimenting with jQuery some more, you’ll find yourself using this function quite a lot.
4) Making the #leftpage div clickable
The markup for our book image doesn’t contain any links, so at the moment there are no clickable “hooks” upon which to base our page-turning animation.
That’s no biggie, though — with a few lines we can tell jQuery to watch #leftpage for clicks, and then to perform a number of tasks every time it registers a click there. The code looks like this:
$("#leftpage").click(function(){
/* do stuff when they click on #leftpage */
});
5) Making a click re-position our background image
Okay, now we’re getting somewhere! For when a user clicks on #leftpage, we’ll first calculate how far we need to move the background image, and then we’ll move it. We set our starting Y position ($pageYpos) at the top as zero, so we just nee to add exactly one “page height” unit in order to move the background image to the next page position. We express this as $pageYpos = $pageYpos + $pageheight. After one click, the value of $pageYpos will be 189, after two clicks it will 278, and so on.
We then use that value to reposition our background image. Here’s the code snippet to perform that repositioning:
$("#leftpage").click(function(){
$pageYpos = $pageYpos + $pageheight;
$("#leftpage").css("background-position", "0px"+$pageYpos+"px");
});
In the code above, we’re selecting #leftpage and using jQuery’s built-in css function to reposition its background graphic.
If we were to try that code now, we’d see that things are finally starting to happen! Clicking the left side of #leftpage should instantly snap the background-image to display the next page. The neat thing about this sprite technique is that our background tiles automatically — when we arrive at the last frame, the first page rolls around and the loop continues. Nice!
6) Showing the page turn

Next we need to display the page-turning part of the graphic by telling jQuery to set the background-position of our div to the top right. It’s simple enough to add this to our click event:
$("#flip").css("background-position", "top right");
7) Removing the page turn and changing the right-hand page
If we follow the same logic, it’s not hard to predict what our next snippet of code will look like. First we need to return #flip to its default, central position:
$("#flip").css("background-position", "top center");
Next we need to display the next page on our right-hand page. We already know the new Y-position ($pageYpos) because we used it to reposition the left-hand page background earlier.
$("#rightpage").css("background-position", "146px"+$pageYpos+"px");
8) Delaying the page-turn effect
Okay, so now we have the correct animation sequence — change left-hand page, show page-turn graphic, hide page-turn graphic & change right-hand page.
The problem is, these steps all happens so quickly that we never even see the page-turning animation. We need a way to delay the script momentarily, before it clears the page-turning graphic and continues. The most common way to control time in JavaScript is via the ’setTimeout’ function.
’setTimeout’ requires two arguments: the action you want to take, and how long (in milliseconds) you want it to wait before taking that action. For instance, if you want an alert to pop up after five seconds, you might use the following code:
setTimeout ("alert('Five seconds has passed!)'", 5000);
All we need to do is place our last two CSS changes inside their own ’setTimeout’ functions. I’ve set the delay on both to 200 milliseconds, but you might like to adjust it to your taste. In fact, setting the right-hand page to animate a fraction later (300 milliseconds, for example) might be closer to what happens in the real world when we turn a page in a book.
/* return flip to default position */
setTimeout ('$("#flip").css("background-position", "top center");', 200);
/* change right page */
setTimeout ('$("#rightpage").css("background-position", "146px "+$pageYpos+"px");', 200);
There you have it — dropping that code into our script gives us a simple but relatively convincing animation, without having written a lot of code.
9) Making the right-hand page turn
In the interests of keeping this edition of this already sprawling post to a semi-reasonable length, I won’t step through the entire process of animating the right page here. Suffice to say it’s a mirror image of our left-hand page function. Instead of adding to our background Y-position, we subtract from it and we use the alternate page graphic. Have a go at working it out for yourself, or check out the finished demo here.
Now, if you’re thinking ‘hang on a minute, that doesn’t look quite the same as the version on sitepoint.com‘, you’re quite right. The production version:
- has an extra corner page curl part to the animation
- has an extra sliding animation effect that eases each page into place as it settles (it’s subtle, but you’ll notice it)
- is unobtrusive — meaning we actually load a garden-variety
IMGtag into the raw page, and then use jQuery to replace it on the fly with theDIVstructure outlined above. Anyone visiting the page without JavaScript enabled will at least have access to the raw page images
Of course, feel free to experiment with adding those parts into or improving the demo here. This was the our first cut, and I already have a raw concept of an improved version. Obviously there are currently built-in scaling limitations to the technique — keeping all the pages on one graphic ensures cached graphics but every page added increases the initial download requirement.
Perhaps a future version might load blocks of pages at time to strike a balance?
If you liked this blog, share the love:



July 20th, 2007 at 7:09 pm
This is downright sweet!
July 20th, 2007 at 10:49 pm
Sir(s), I salute you.
Well done!
July 21st, 2007 at 2:29 am
Safari 2.0.4 doesn’t show it as you intend. But it’s pretty cool in FF.
August 19th, 2007 at 4:32 pm
This code is awesome you guys are champions loads of thanks for the Script.
hats off
August 22nd, 2007 at 9:56 pm
if you click the right once, then the left… it’s not the same content that your expecting to see as you see in a REAL book
August 28th, 2007 at 11:11 pm
This is great… But, how would I set the book to “auto flip”?
August 29th, 2007 at 11:30 am
Jessy, it would take a little bit of rewriting, but I don’t think it would be terribly difficult.
I explain the ‘timeOut’ function above. I think you would need to use that to replace the ‘
.click(function())’ code — set with a longish delay. It would eliminate the need to be able to flip in both directions so you can completely remove the backward page turn functions.Almost everything you need is there. It just needs to be rearranged and trimmed up a little to work.
Give it a try and let me know how you go.
August 30th, 2007 at 7:32 pm
I think the easiest way to automate the page flip is this one: simply create a timeOut function, which clicks the page:
something like this
function autoPageFlip() {
$(”#rightpage”).click(); // I love jQuery :)
setTimeout(autoPageFlip, 4000);
}
and launch this by a first:
setTimeout(autoPageFlip, 4000);
Nothing else to do, no need to break this nice code, it should work fine ;-)
Feel free to ask if any question.
marc.bourlon _ at _ proxistep.com
September 6th, 2007 at 10:37 pm
if we use an image, rather than the stacked pages in the JPG
but how about if the size of each 2 pages are different, how to adjust it in the program
beside DEMO, any where , we could download full code??
November 27th, 2007 at 12:14 pm
This is a cool effect!
However, IE6 does not support alpha transparency of PNG image!
So that the effect is much better in Firefox then in IE6.
December 2nd, 2007 at 5:15 am
I would like to do this with my online bible here.
http://www.talkjesus.com/misc.php?do=page&template=bible_kjv
however, the images provides are tiny and I’m not a graphic designer by trade nor do I know where to find “book” images like these.
I need a dimension of about 700px width / 550px height. This is to make an actual book reading experience, online.
Can someone help out on this please?
chad@talkjesus.com / http://www.talkjesus.com
December 14th, 2007 at 3:46 am
simply great…
December 14th, 2007 at 5:10 pm
Awesome Script
December 25th, 2007 at 2:09 am
Hi…
I’m sorry if I’ll disturb with this question… but I haven’t understood if this tutorial can be used freely. I like this, and I would like to use this effect in my web site, free-technology.org (an italian web site), particularly in the future section where we’ll put our free magazine.
So… This tutorial is freeware or we have to purchase a license?
Thanks to someones that can help me. ;)
Portabile84
January 2nd, 2008 at 9:43 am
Portabile84, you are more than welcome to use and adapt the script to your own needs. Of course, a credit URL to this page in the comments is always useful for others wondering how to do it.
January 4th, 2008 at 3:52 am
:D Thanks for your reply AlexW :D
Ok… I’ll put a link into the footer and into the credits section of my web site :D
Thanks
PS: Happy 2008! ;)
January 14th, 2008 at 10:19 am
Hi…
I have just create my Thumb Magazine Preview… Next week I will create the big resolution of the Magazine :D
But I would like to tell to you that your script has a little bug :D
If I click into the right page, to display next pages… ok It work with no problem.
But If you try to click into the left page, the javascript script doesn’t dysplay the correct 2 previus pages…
Also, a little advice ->Into the image screenshot, it will be better to use the same order.
For example in the firs column we’ll put only the pages with negative page numbers, and into the second I think that it’s can be better to put only others page… :)
Also… the Javascript code, It work correctly with my modification :D
My Code…
$("#leftpage") .css("background-position", "0px "+$pageYpos+"px"); $("#flip") .css("background-position", "top right"); setTimeout ('$("#flip").css("background-position", "top center");', 200); setTimeout ('$("#rightpage").css("background-position", "146px "+$pageYpos+"px");', 200); ...... ...... ...... $("#rightpage") .css("background-position", "146px "+$pageYpos+"px"); $("#flip") .css("background-position", "top left"); setTimeout ('$("#flip").css("background-position", "top center");', 200); setTimeout ('$("#leftpage").css("background-position", "0px "+$pageYpos+"px");', 200);This code must be used only with the page order tha I have indicate into the prevoius text rows.
I have a last question: Can I translate your tutorial and put itsel into my forum? :D
I love this script :D :D
March 14th, 2008 at 4:12 pm
I would like to incorporate this on my website, Can you let me know how do i create a page curl effect and the page sliding after page is opened(similar to what you have in your page).
It would help me greatly to give a real page turn effect on my page.
and also I would like to know how do I call the pages 1 at a time.(the book I am doing is having more than 250 pages)
March 18th, 2008 at 10:57 am
Rags, the post above is a complete explanation on how to achieve the effect, so just follow it through.
As far as loading new pages as they are called, you would need to use AJAX to preload pages just before they are needed. This is quite doable, but it’s outside the scope of what I was trying to achieve with the effect.
But if you manage to get it running, we’d be keen to see it in action.
March 19th, 2008 at 11:27 am
First off awesome script!!!
One question is there a way I jump to a particular page. Like by putting a button that would skip it say page 2 & 3?
March 19th, 2008 at 11:33 am
First off awesome script!!!
One question is there a way I could place a button on the page that would skip to a particular page in the book like say page 3 & 4 with out turning the page?
March 19th, 2008 at 2:52 pm
Thanks chachiisme,
I would take a little bit more coding, but it wouldn’t be hard. Off the top of my head, you would need to add a new function.That function would be similar to the #leftpage/#rightpage functions used in the example above, except it would hardcode the position of the background image to the exact position of the page you wanted, rather than just keeping track of it’s current Y position ($pageYpos = $pageYpos + $pageheight;) as it does now.
You’d them have to tie that new function to a button or link to set trigger it.
April 6th, 2008 at 6:26 pm
Gorgeous
April 18th, 2008 at 11:37 pm
the finished demo JS is wrong. Right flip.
Notice that when you right flip, the page displays right-side-left
Right Turner code should be:
/* right page turner */ $("#rightpage").click( function() { $pageYpos = $pageYpos - $pageheight; // note: minus page height $("#rightpage") .css("background-position", "0px "+$pageYpos+"px"); $("#flip").css("background-position", "top left"); setTimeout ('$("#flip").css("background-position", "top center");', 200); setTimeout ('$("#leftpage").css("background-position", "146px "+$pageYpos+"px");', 200);May 9th, 2008 at 9:17 pm
How did you generate the image for the curves and curls? I need to make one without the orange and blue stripes. Thanks!
May 13th, 2008 at 5:16 pm
Devon, if you use Fireworks, I’d be happy to give you a copy of the working graphics I used. If you don’t have Fireworks, that file isn’t much more use to you than the file used in the example.
May 13th, 2008 at 5:25 pm
In fact, here is the working PNG if anyone is interested.
http://www.sitepoint.com/examples/jquery/pageturn-working.png