Building a Robust Side Scrolling Page Effect with Scriptaculous

This article is part of a series which details how to build a side scrolling page effect similar to what is seen on Panic’s Coda site. Please feel free to visit the rest of the series:

Part I - Introduction and using ASP.NET Ajax to build the effect
Part II - Creating the effect with Scriptaculous
Part III - Using MooTools

For a while now I have been writing about how to create a Side Scrolling Page Effect similar to the one that is seen on Panic’s Coda site. I have built the effect using 3 different frameworks and I have found that each framework has its own pluses and minuses, but in the end I decided to build a more robust solution using Scriptaculous (you can see why in the conclusion section of the MooTools article).

Today I am rounding out the series with the posting of that robust solution. Basically this is my take on that effect and what I implemented for my client. How the basic effect is achieved is covered in the other articles, so today’s goal is to explain what takes it from a simple demo to a fully functioning, cross-browser compatible website. At the end of the article I will, as usual, have a link to where you can download all the code used in the demo.

What is Robust Anyways?
A robust solution is basically one that will stand up to “real world punishment”. Practically this means a few things:

  1. It won’t break. A solution that blows up on the user isn’t much of a solution at all. In the case of a page effect like this one, even a minor bug can make the page unnavigable which is for all intents and purposes a “critical error”.
  2. It is cross-browser compatible. The easiest way to do this is to make sure it is XHTML compliant. Because the core of this effect is ASP.NET it is Transitional compliant rather than Strict. Hopefully someday they will make it so that ASP.NET can be strict. Outside of making sure it is compliant you need to test it on all the major browsers. The demo here has been tested and works on IE 7, Firefox 2, and Safari 3.
  3. It works even when it shouldn’t. This entire site is built upon javascript…and lots of it. Without javascript it shouldn’t work. However, you can’t build a site that completely shuts down when javascript isn’t on. It might not work perfectly, but users should be able to do the basics with the effects off. There is one caveat to this. There are a couple of extra effects that I added “just cuz”, and since these effects are not critical to basic functionality they do not work when JS is off.

Now, does robust mean that it will stand up to any conditions? Absolutely not. If building such a thing is even possible, it would take enormous amounts of time and energy. Robust simply means it is gonna work for the vast majority (aim for 95 - 99%) of people and situations.

What Are We Building Again?
Before we get too far into all this, its probably good to take a look at the end result first…kinda like peeking at the last page of a book.

Here is our final destination for this trip

You will notice it looks a bit different than the earlier demos, but overall its the same effect I built earlier. As we get further along here, you will notice that I am not detailing every line of code and CSS this time. The reason is simple…there is just too much of it.

With that said, if you are looking through the code and you have some questions about one part or another, please feel free to drop a comment or an email and I will do my best to walk you through it.

On with the Robustness!
The biggest difference between the original demos and this one is the fact that this time we have a menu. Now a menu’s job is to help navigate, but this guy serves an even more important job. He saves our butt in case a visitor doesn’t have javascript enabled.

If javascript is off, then our little arrows won’t do a darn thing so we need some other form of navigation. A menu serves that purpose well. The markup looks something like this:

<div id="Menu">
    <ul>
        <li id="MenuPage1" class="Page1Over" style="color: #FBE97E;" onclick="clickPage1()">
            <a href="#Page1Block">Page 1</a>
        </li>
        <li id="MenuPage2" class="Page2" onclick="clickPage2()">
            <a href="#Page2Block">Page 2</a>
        </li>
        <li id="MenuPage3" class="Page3" onclick="clickPage3()">
            <a href="#Page3Block">Page 3</a>
        </li>
        <li id="MenuPage4" class="Page4" onclick="clickPage4()">
            <a href="#Page4Block">Page 4</a>
        </li>
    </ul>
</div>

See how I have a standard anchor tag around each of the pages? This is for “no javascript-land”. If a person comes in without JS, then the menu needs to act like a normal menu. So I accomplish this with inpage links. The problem is, this causes grief for the user who has javascript enabled. We fix this with…you guessed it…javascript.

function initialize()
{
    //the HTML is built to allow those without javascript to still function.
    //If the user has javascript, then we need to change that HTML so that it
    //will not interfere with the javascript
    document.getElementById("MenuPage1").innerHTML = "Page 1";
    document.getElementById("MenuPage2").innerHTML = "Page 2";
    document.getElementById("MenuPage3").innerHTML = "Page 3";
    document.getElementById("MenuPage4").innerHTML = "Page 4";
    //firefox keeps the saved page value after a refresh...we need it to reset.
    document.getElementById("hdnPage").value = 1;
    document.getElementById("hdnAnswer").value = 1;
}

This simple function is called onLoad and simply gets rid our anchors. Nothin’ fancy, but it does allow our main effect to work with or without javascript. Nice.

She Works Hard For The Money!
If you have looked ahead and peeked at the Javascript on our MoveLeft and MoveRight methods you will notice that they are a good deal bigger than they were before. Here is an overview of what is happening.

function MoveRight()
{
    var page = document.getElementById("hdnPage");
    var menu = document.getElementById("menuOver");
    
    //move the menu
    if (page.value == 1)
    {
         //Page1
         setFromPage("Page1");
         setToPage("Page2");
         
         menu.style.width = getMenuBoxSize("Page2");
         setMenuEffect(getX("right", "Page2"));
    }

    ...
    
    //move the big box
    if (page.value == 4)
    {
        var box = document.getElementById("BigBox");
        setBoxEffect(2628)
        page.value = 1;
    }
    else
    {
        setBoxEffect(-876)
        var val = parseInt(page.value) + 1;
        page.value = val;
    }
}

I have cut out some of the redundant parts, but above you can see what is happening. First I need to see what page we are on. I store that in a hidden variable that is initialized to 1. I do the same thing with the menu which is what I move first. Using some handy dandy helper methods I simply tell the page that I am going from Page 1 to Page 2.

The helper methods set the CSS classes to make it look pretty, and change the font color. Now this seems like overkill in the demo, but it was designed to allow different background images to come into play (basically a normal and selected state). Even though I am not using them in this demo, I figured it would be helpful to those of you adapt it for your own needs.

The helpers also tell the menu how far to move to the right. Again, this seems like overkill here, but in my application each menu item was a different size so it would change depending on which page I was moving to.

After the menu is moved, we move the “BigBox” which is where all of our content lives. This is easy…we move it by the same amount (except on the ends where it has to wrap around), and then we set the hidden value to keep track of what page we are showing.

So that is basically what happens when you click on one of the arrows, what happens if you click directly on a link? Lets see…

function clickPage1()
{
    var page = document.getElementById("hdnPage").value;
    var menu = document.getElementById("menuOver");
    menu.style.width = getMenuBoxSize("Page1");
    
    if (page == 1)
    {
        //nothin' to do here
        return;
    }
    else if (page == 2)
    {
        setFromPage("Page2"); 
        
        setMenuEffect(-135);
        setBoxEffect(876);
    }
    else if (page == 3)
    {
        setFromPage("Page3");
        
        setMenuEffect(-270);
        setBoxEffect(1752);
    }

    ...
       
    setToPage("Page1");
    
    document.getElementById("hdnPage").value = 1;
}

Unlike the Move methods, we can’t set it to move the exact same every time. Sometimes we move Left, sometimes we move right. For instance, the method shown above is called whenever a visitor clicks on the Page 1 link. If we are already on page one, then there is nothing to do. However, if you are on page 2 we need to move the menu to the left and we need to move the BigBox “1 page” (i.e. the amount of pixels that equate to the width of one of our blocks). If you are on page 3, the we need to move to the left the equivalent of 2 pages.

Once the menu and box are moved I set the hidden value to the page that was clicked on.

That is basically it…when you boil it down, it isn’t really all that difficult. To apply it to your own site all you would need to do is change the widths and movements to correspond to the sizes of your menu items.

Extra Effects
There are a couple of effects that I employed on my client’s page that I figured I would just leave in there in case you wanted something similar. The first is an accordion effect. One small problem with scriptaculous is that it does not have its own prebuilt accordion effect.

No worries…Kevin Miller of Stickman Labs has filled the need with his own extension that works with just about any language. You can see an example of it on “Page 2″ of the demo.

To get it to work is pretty simple. First you need a javascript method like this to initialize everything:

Event.observe(window, 'load', loadAccordions, false);

function loadAccordions()
{
    var bottomAccordion = new accordion('#divPage2');
    bottomAccordion.activate($$('#divPage2 .accordion_toggle')[0]);
}

and then you need to make the markup of each part look like this:

<div class="accordion_toggle">
    <div class="toggle_text">Item 1</div>
</div>
<div class="accordion_content">
    <div class="content_text">Detail text</div>
</div>

Now the “toggle_text” and “content_text” are CSS classes of my design just so I could get my stuff looking the way I wanted, but the “accordion_toggle”, and “accordion_content” are required.

Its a solid implementation that has a lot of bells and whistles (including horizontal accordions), so if you need this effect, it is definitely worth checking out.

The other extra is a home-grown Question/Answer effect. The reason I needed this is because you cannot have any internal scrolling (due to a Firefox issue) inside of any of our pages. A Q&A by its very nature is pretty long so I created a scrolling effect.

To get it to work you need two things:

Some javascript

function MoveToAnswer(number)
{
    var currentAnswer = document.getElementById("hdnAnswer").value;
    var value = number - parseInt(currentAnswer);
    var y = parseInt(value) * -100;
    new Effect.MoveBy('Answers', y, 0 , 
          {duration: 0.4,  transition: Effect.Transitions.sinoidal, queue: 'end'});
    
    //change the current answer
    document.getElementById("hdnAnswer").value = number;
}

(the 100 can be anything…that is just what I have each answer’s height set at)

and some markup

<div onclick="MoveToAnswer(1)" class="question">Question 1</div>
<div id="answer1" class="answer">Answer 1</div>

The only trick is that the Questions and Answers must be “in order” meaning you can’t go 1,2,4,5…otherwise the scrolling will break.

Conclusion
So there you have it…a robust side scrolling page effect. Its been a long journey, but the end result has been a great learning experience for me and I hope it was for you as well. Again, if you run into any issues, or have any questions about what I did, or why I did it, please feel free to drop a comment. Heck, if you have suggestions to make it better, I am all ears.

When you are ready to get your hands dirty, feel free to download the demo code and get crackin’!

33 Comments so far »

  1. Jay said,

    Wrote on August 18, 2007 @ 10:14 pm

    hi i enjoyed the read

  2. David Baxter said,

    Wrote on August 20, 2007 @ 8:52 am

    Hey Jay, thanks a lot!

    David

  3. HazelNutz said,

    Wrote on August 29, 2007 @ 7:21 am

    Great stuff!!!

    Exactly the solution I was looking for, I’ll implement it in my future applications, if it’s okay!?

    I’ll, for example, change one of my sites, www.mincv.se, with your solution!

  4. David Baxter said,

    Wrote on August 29, 2007 @ 9:07 am

    Glad you liked it, feel free to use it, just shoot me a link when it is done so I can see it in action.

    David

  5. Gretchen said,

    Wrote on September 18, 2007 @ 12:58 pm

    Really great information! I have been beating my head against the wall for several weeks trying to get a hint on how to get the gridview to scroll smoothly in a div/panel, etc. ALL that I have seen scroll approx. 1 1/2 rows at a time which is totally unacceptable for viewing important data. Where should I look for the answer? Thanks in advance! I use VS2005 and Ajax.

  6. David Baxter said,

    Wrote on September 18, 2007 @ 1:29 pm

    Hey Gretchen, have you tried putting the grid into the solution I provided? There shouldn’t be any controls that won’t slide around in the “blocks” I setup here, but I could be wrong.

    Shoot me an email [david @ creativeui . com] with the details and I will do my best to help out.

    David

  7. Gretchen said,

    Wrote on September 18, 2007 @ 2:47 pm

    Thanks so much, David, for your reply and generous offer! I need to do a little studying on JavaScript before I make a total fool out of myself, so I will keep your email address and be back to you in a few weeks.
    Thanks again!

  8. tyler said,

    Wrote on October 1, 2007 @ 12:54 am

    hm, just wondering…instead of a separate click function for each tab…posible to write a generic single function that computes how much to move the menu/bigbox? prob there is but at 1AM, my mind not quick enuff… :(

  9. David Baxter said,

    Wrote on October 1, 2007 @ 9:22 am

    I would definitely say that there is a way to make that method more generic (i.e. one function). The example has it so that all of the menu items are the exact same size. This makes a generic method easier to implement.

    In the “real” version I made for a client has several different sizes. Hence why the demo has multiple methods.

    Hope that helps.

    David

  10. tyler said,

    Wrote on October 1, 2007 @ 8:29 pm

    same here re varying widths…was thinking if you could store the specific widths of each tab in a hash or array, you could in theory make it compute the distance to slide…if i can get off my butt (and learn javascript syntax) i might give it a go

  11. David Baxter said,

    Wrote on October 2, 2007 @ 7:55 am

    Not a bad idea at all Tyler. Let me know how it works out.

    David

  12. tyler said,

    Wrote on October 4, 2007 @ 9:50 am

    will do…

    just out of curiousity - have you run into a bug where the overflow: hidden attribute on the scrollbox div breaks on Windows IE and Mozilla? It’s weird - on my page, it will break once you start clicking and scrolling and you can see the entire bigbox div. works fine on safari 3.0 beta, and more or less ok in Camino…

    Tyler

  13. tyler said,

    Wrote on October 4, 2007 @ 9:50 am

    (on your demo and on the panic site, everything works fine…)

  14. rails blog » Blog Archive » [Rails-spinoffs] Re: css overflow:hidden attribute breaking on scriptaculous side scrolling animation? said,

    Wrote on October 4, 2007 @ 8:02 pm

    […] am trying to build a side scrolling animation like the one onpanic.com/coda and on http://www.creativeui.com/2007/08/13/building-a-robust-side-scrolling-page-effect-with-scriptaculou…(from which I am using a modified code […]

  15. GSIY … Ruby-Rails Portal said,

    Wrote on October 4, 2007 @ 9:23 pm

    […] am trying to build a side scrolling animation like the one on panic.com/coda and on http://www.creativeui.com/2007/08/13/building-a-robust-side-scrolling-page-effect-with-scriptaculous… (from which I am using a modified code […]

  16. GSIY … Ruby-Rails Portal said,

    Wrote on October 4, 2007 @ 9:26 pm

    […] am trying to build a side scrolling animation like the one onpanic.com/coda and on http://www.creativeui.com/2007/08/13/building-a-robust-side-scrolling-page-effect-with-scriptaculou…(from which I am using a modified code […]

  17. Nick said,

    Wrote on November 1, 2007 @ 5:28 pm

    I’ve created multiple instances of your scrolling pages, you can see the example on my site listed above. All works excellent and grand in Firefox, but when used in IE, only the first instance will work properly. I basically named each variable adding 2,3,4 etc. to the end of the names, then duplicated the javascript and retitled those accordingly. (e.g. MoveLeft2(), MoveLeft3() etc.)

    Any ideas on why it would break in IE, but work fine in FF?

    example is at www.nickhand.net/newsite07_end/index.php

  18. David Baxter said,

    Wrote on November 1, 2007 @ 5:46 pm

    Hey Nick, can you email me your code?

    David

  19. Nick said,

    Wrote on November 1, 2007 @ 5:59 pm

    Sent, but the confirmation page appears that my html i sent you may have been rendered and such, sooo if that’s the case, shoot me an email and i’ll respond w/my code again. Thanks David

    Nick

  20. steve ofner said,

    Wrote on November 21, 2007 @ 3:43 pm

    would it be possible to add a simple timer to the script so that every 10 secs or so it auto jumps to the next section if no one’s clicked?

  21. David Baxter said,

    Wrote on November 23, 2007 @ 8:50 am

    Sure, that is definitely possible. If you are using .NET you can use the UpdateTimer contol. In a pure javascript world you can use window.SetInterval to get it done.

    Hope that helps.

    David

  22. Hazelnutz said,

    Wrote on January 30, 2008 @ 3:42 am

    Hi again David,
    In my version of your Side Scrolling Page solution I’ve put an overflow:auto function on a div on page one. It’s working well on Windows IE but in Mozilla, when scrolling to page two, part of page one is visible to the left on page two!
    Any suggestions how to fix it?

  23. David Baxter said,

    Wrote on January 30, 2008 @ 9:55 am

    Hey Hazel, my first suggestion would be to start with the CSS I have in my example and make sure that is working for you on both browsers (it should).

    Once that is working, then start manipulating it one aspect at a time till you get the effect you want.

    CSS can be a tricky bird, and sometimes the most irrelevant thing can throw off the entire page.

    Let me know how that works out for you.

    David

  24. Note-Worthy » Side-scroll page effect said,

    Wrote on February 4, 2008 @ 11:46 pm

    […] Found this script […]

  25. Christine said,

    Wrote on March 9, 2008 @ 12:20 am

    Hello David,

    I am working with this script but with double the number of blocks, hoping that this is not too much for the script to handle. So far it’s going OK except that I get a horizontal scrolling bar in the browser once I get to block 6 or so. Do you know how I can get rid of this scrollbar? I’ve just added on the necessary width to the #bigbox in CSS for the additional blocks - do I need to change something in the accordion.js or another file to ward off this browser scrollbar?

    Thanks for posting this great work, and for any help you can provide with my quandary here…

    -Christine

  26. David Baxter said,

    Wrote on March 10, 2008 @ 11:14 am

    Hey Christine, glad the tutorial was helpful. I am sure there is some limit to this script, but I would imagine it is pretty large, and beyond what you are talking about.

    The scrollbar can be hidden with the CSS command overflow:hidden. I would also recommend making your blocks as small as you can in order to prevent the need for a scrollbar at all.

    You shouldn’t ever need to change the javascript files unless you are getting REALLY fancy and wanting to change the behavior of things.

    Feel free to email me if you need more help.

    David

  27. Inishi said,

    Wrote on April 28, 2008 @ 11:50 am

    Hey David,
    I was looking a similar effect, and your script is by far the most flexible and useful I’ve found so far. I have a problem though. I’m new to javascript, and what I’ve learned has been more out of interest than any formal study. I’m trying to add more blocks to the script. While it works perfectly when I add “Page5″ to the MoveRight() and MoveLeft() functions, when I add page5 to the ClickPage(1-4)() the whole website stops working. I even made a ClickPage5() which works. But I can’t make the ClickPage1-4 take into account Page 5. What is the correct way to add blocks to these functions? Is there a limit to the amount of blocks I can add? Thanks anyways, and sorry for not explaining it better.

    Inishi

  28. David Baxter said,

    Wrote on April 29, 2008 @ 9:23 am

    Hey Inishi, I am glad the script is working well for you.

    The current script is built for 4 pages, but there is no reason it can’t be made larger. In fact, several people have done quite a few creative things with it so I know it can be upgraded.

    The key is to get the pixels right. Currently the left and right methods are set to move enough for 4 pages. To add more, you simply need to expand them and tweak the numbers to include more pages. It isn’t difficult, but it can be a bit maddening to find out you are 3 pixels off…trial and error is the way I built it.

    Hope that helps,
    David

  29. Inishi said,

    Wrote on April 30, 2008 @ 4:30 pm

    Hey David,
    Thanks for the info, and I found my error. The clickPage#() didn’t work untill I had the page5 condition in all of them. At first I wanted to do small changes and go by sections to check if my changes to your code still worked, so I didn’t try to add the page5 condition to all of the clickpage# functions till right now. Seems wine gave me the inspiration. Thanks a lot for a great website. And I specially appreciate the examples and the open code, since I can learn a lot from tweaking it myself. Since I learned html and css on my own, I really enjoy the learning opportunity CreativeUI gives to me to learn more about better interfaces. (Really, making a website in Latin America pays more than being a skilled Barman). Thanks.
    Inishi.

  30. ♥ techyPink! said,

    Wrote on August 2, 2008 @ 11:17 pm

    […] this script Filed under: AJAX […]

  31. Prosegger said,

    Wrote on January 14, 2009 @ 7:00 am

    Hey, I’m looking for a solution to scrolling variable width content (e.g. the box should have 80% of the site’s width, and the 4 menu items should be 20% of the site’s width each). Can anybody give me any hints as to where to find something similar?

    Thanks in advance,
    pro

  32. David Baxter said,

    Wrote on January 14, 2009 @ 10:04 am

    I don’t know of any that will do that “out of the box”, but most of the scripts, including this one, should be able to be updated to work with variable widths without a huge amount of effort.

    David

  33. Chad Nance said,

    Wrote on February 4, 2009 @ 9:25 pm

    was wondering if this can be done with PHP instead of ASP

Comment RSS · TrackBack URI

Leave a Comment

Name: (Required)

E-mail: (Required)

Website:

Comment: