Scroll Up Headline Reader

A couple weeks ago someone on the jQuery discussion list asked if someone could reproduce a rotating headline box in which the headlines, in succession, scroll up into the box, pause, and then scroll up out of the box. Since I already had some code for rotating images on a page, I decided to recycle it and take the challenge.

Here is the finished product. (Please note that if you are looking at this in a feed reader, you won't be able to see the effect. )

Get Started with the HTML and CSS

The first thing I did was throw a simple page together using a single container DIV with an id of "scrollup" and four or five DIVs with a class of "headline" to hold each headline.

HTML:
  1. <div id="scrollup">
  2.   <div class="headline"> ... </div> 
  3.   <div class="headline"> ... </div> 
  4.   <div class="headline"> ... </div> 
  5.   <div class="headline"> ... </div>     
  6. </div>

I then added this simple CSS to the scrollup ID and the headline class:

CSS:
  1. #scrollup {
  2.   position: relative;
  3.   overflow: hidden;
  4.   border: 1px solid #000;
  5.   height: 200px;
  6.   width: 200px
  7. }
  8. .headline {
  9.   position: absolute;
  10.   top: 210px;
  11.   left: 5px;
  12.   height: 195px;
  13.   width:190px;
  14. }

That made all of the headlines absolutely positioned in relation to their containing box, which got a height and width of 200px. Notice that the top of all of those headlines is 210px, and the overflow property of the container is set to hidden, so none of the headlines would be showing — until they were ready.

Set Up the jQuery

At the top of the jQuery file I defined variables for the total number of headlines, the interval between headlines, the current headline, and the "old" headline:

JavaScript:
  1. var headline_count;
  2. var headline_interval;
  3. var current_headline = 0;
  4. var old_headline = 0;

Then I set the headline_count variable to be the number of div elements that have a class of "headline." But that number can't be computed until the DOM is loaded, so I wrapped the variable in jQuery's $(document).ready() function. I also wanted to set the first headline's "top" property so that it would be immediately visible, while the others would remain hidden — at least initially — below the box (as set in the CSS):

JavaScript:
  1. $(document).ready(function(){
  2.   headline_count = $("div.headline").size();
  3.   $("div.headline:eq(" + current_headline + ")").css(top, '5px');
  4. });

The code examples for this entry used to include the .top() method, which, as of jQuery 1.1, no longer works. You will need to use .css('top', 'Npx') instead.

Before we move on, I'd like to point out a few things about the above code:

  1. jQuery has a .size() function that is similar to JavaScript's length property in that it returns the number of jQuery objects defined by the $() that comes before it.
  2. The second line is only fired once, when the DOM is first loaded. Instead of setting every headline's top to 5px, it uses a special jQuery DOM selector, :eq(), to set only the current headline's top. Typically, :eq() would take a number, like so: $("div.headline:eq(0)").
  3. I chose to pass in the "current_headline" variable instead of a number to allow for a little flexibility. If I later decide I want to start with the fourth headline, for example, I'd just have to change var current_headline = 0 up at the top of the script to var current_headline = 3. In order to get the variable in there, though, I had to concatenate it with the rest of the selector before and after it.

Everybody Rotate!

Now that everything was in place, I could write my headline_rotate() function. I first needed to increment each headline by one until I reached the last one and then start over, creating a loop. To do so, I used what my friend Jonathan Chaffer told me is called "clock arithmetic." Here is what that looks like (at least, the way I did it):

JavaScript:
  1. function headline_rotate() {
  2.   current_headline = (old_headline + 1) % headline_count;
  3. }

Line 2 sets a new value for current_headline by first adding 1 to old_headline and then using the modulus operator (%) to get the remainder of old_headline + 1 (our new headline) divided by headline_count (total number of headlines). Jonathan explained it this way: "the remainder will always equal old_headline + 1 until it reaches headline_count, at which point the remainder becomes zero." The only thing better than having a genius working next to me is having a genius who is great at explaining things to mere mortals like me. :)

Add the Animation

Next I added the animation into the headline_rotate() function — moving the old headline up and out of sight while moving the next headline (now called current_headline) into view.

The old headline movement actually has two parts: (a) scrolling up and out of sight and (b) moving instantly back down underneath the box so that it's ready to slide up into the box again the next time. This is where jQuery's "callbacks" come in very handy. I could queue the second effect by putting it in the callback of the first. Compare just the first effect...

JavaScript:
  1. $("div.headline:eq(" + old_headline + ")").animate({top: -205},"slow")

...to the first, plus the second in the callback...

JavaScript:
  1. $("div.headline:eq(" + old_headline + ")").animate({top: -205},"slow", function() {
  2.     $(this).css('top', '210px');
  3. });

By the way, the -205 in .animate({top: -205}) means that the top of the headline moves to 205 pixels above the top of its containing element (because the containing element had its position set to relative) so that we're sure the entire headline clears the box.

For the current headline, I simply moved its top up to 5 pixels below the top of the scrollup box so that it would be visible. And after that, I made old_headline equal current_headline:

JavaScript:
  1. $("div.headline:eq(" + current_headline + ")").animate({top: 5},"slow")
  2.   old_headline = current_headline;
  3. }

To get the function to run when the page loaded, I simply dropped headline_rotate() inside my $(document).ready(). Unfortunately, that only made the animation fire once. I wanted it to repeat.

And Repeat

Remember that headline_interval variable I included way at the top? Here is how I used it:

Still inside $(document).ready(), I replaced headline_rotate() with headline_interval = setInterval(headline_rotate,5000);. That made JavaScript's setInterval() trigger my headline_rotate() function once every 5000 milliseconds (5 seconds).

Bonus – Pause on Hover!

I was fairly satisfied with the way the headline rotator worked, but I realized that for it to be really useful I'd want to make it pause when the mouse would hover over the box and start up again as soon as the mouse went back out. I'm not sure that I did it the best way, but it seems to have worked fairly well for me. I attached jQuery's hover() method to the "scrollup" div. The hover() takes two arguments, the first for mouseover and the second for mouseout. In the mouseover part, I stop the "interval," and in the mouseout part, I started it back up and called headline_rotate() again so the next headline would show up immediately:

JavaScript:
  1. $('#scrollup').hover(function() {
  2.   clearInterval(headline_interval);
  3. }, function() {
  4.   headline_interval = setInterval(headline_rotate,5000);
  5.   headline_rotate();
  6. });

That hover stuff also went inside $(document).ready(), and then I was done!

The Full Code

I set up a demo page with the full code and CSS embedded in the <head>, so if you want to take a look and copy it for your own use, go ahead. Or, take a look at the full jQuery code below:

JavaScript:
  1. var headline_count;
  2. var headline_interval;
  3. var old_headline = 0;
  4. var current_headline = 0;
  5.  
  6. $(document).ready(function(){
  7.   headline_count = $("div.headline").size();
  8.   $("div.headline:eq("+current_headline+")").css('top', '5px');
  9.  
  10.   headline_interval = setInterval(headline_rotate,5000);
  11.   $('#scrollup').hover(function() {
  12.     clearInterval(headline_interval);
  13.   }, function() {
  14.     headline_interval = setInterval(headline_rotate,5000);
  15.     headline_rotate();
  16.   });
  17. });
  18.  
  19. function headline_rotate() {
  20.   current_headline = (old_headline + 1) % headline_count;
  21.   $("div.headline:eq(" + old_headline + ")")
  22.     .animate({top: -205},"slow", function() {
  23.       $(this).css('top', '210px');
  24.     });
  25.   $("div.headline:eq(" + current_headline + ")")
  26.     .animate({top: 5},"slow")
  27.   old_headline = current_headline;
  28. }

If you have any questions about the code or suggestions for improvement, please leave a comment.

UPDATE

Jonathan Chaffer and I wrote a much-improved version of this headline reader and discuss it in detail in the Learning jQuery book.You can see a demo of it on the companion site. Also, Mike Alsup has written the brilliant Cycle plugin that does the scroll-up effect and much, much more. Check it out!

38 Responses to “Scroll Up Headline Reader”

  1. Erin Says:

    I really like your tutorials! Wish there were more of them!

    One observation: It seems inefficient to continuously create new jQuery objects:$("div.headline:eq(" + current_headline + ")") Can't you just create one and then somehow access the different headlines within it?

    Here's a suggestion for future tutorials: I've been trying to understand the code behind some of the more popular plugins (at jquery.com) such as Accordion http://fmarcia.info/jquery/accordion.html and sometimes they are written at such a high level that there are parts I just don't understand. If you could take a pluggin and explain how it works (line by line) it would be great!

  2. Karl Says:

    Hi Erin, thanks for the comment and the suggestions! You may be right about the inefficiency of creating the jQuery objects; I'll have to look into that.

    I wish there were more of the tutorials, as well. :) And there will be, as time goes on. The blog is still in its infancy, so stay tuned. Good idea about looking "behind the scenes" of popular plugns. I'll try to add that to the list of upcoming entries.

  3. Erin Says:

    How about this:

    var headline_count;
    var headline_interval;
    var old_headline = 0;
    var current_headline=0;
    var headlines = new Array(); // an array of jQuery objects
    
    $(document).ready(function(){
      headline_count = $("div.headline").size();
    
      for (var i = 0; i < headline_count; i++) {
        headlines[i] = $("div.headline:eq("+i+")");
      }
    
      headlines[current_headline].top('5px');
    
      headline_interval = setInterval(headline_rotate,5000);
      $('#scrollup').hover(function() {
        clearInterval(headline_interval);
      }, function() {
        headline_interval = setInterval(headline_rotate,5000);
        headline_rotate();
      });
    });
    
    function headline_rotate() {
      current_headline = (old_headline + 1) % headline_count;
      headlines[old_headline].animate({top: -205},"slow", function() {
        $(this).top('210px');
        });
      headlines[current_headline].show().animate({top: 5},"slow");
      old_headline = current_headline;
    }
  4. Karl Says:

    Erin, that looks good to me. Thanks again!

    By the way, I dressed up your comment's code a bit and deleted the first two failed attempts for you.

  5. Erin Says:

    Thanks Karl. The code was truncating at the "less than" in the for loop.

  6. ShevKen Says:

    Can you whip out a version which allows display of multiple headlines instead of 1-by-1.

    such as

    http://javascript.internet.com/text-effects/ajscroller.html

  7. Karl Says:

    Sure can, Kevin. It might take me a while to actually get to it, but look for a new entry sometime next week.

  8. ShevKen Says:

    Thanks Karl. Looking forward to it!

    The ability to manipulate headlines directly in html instead of in the javscript really attracts. Gd job.

  9. mikek Says:

    hi karl, your single line scroller is pretty neat (i've integrated it with a project in cakephp). i'd also be interested in a means to scroll multiple headlines. will look out for an update soon :D

  10. Karl Says:

    Thanks, Mike. Glad you like it. The multi-headline scroller is a bit trickier than I had thought at first, because of the headlines' varying heights. I will definitely post an entry on it, but it might be a while before I can get to it and give it some sustained thought.

  11. Glen Lipka Says:

    It was originally meant to be used on http://www.intuit.com. Unfortunately, I think they removed it after I left. I kept a copy here. Check the bottom right box.

    It is a great widget. Well done!

  12. bergdog Says:

    Oh, it's wonderful! I'm a JavaScript beginner and also a jQuery beginner, but I could really understand what you say, even though my mother language is Chinese, thank U!!!

  13. victor Says:

    Hi Karl,

    Seems that your demo page example (http://test.learningjquery.com/scrollup.htm) doesn't work neither in Firefox nor in Opera (only in IE). At the same time an example at the beginning of this article works fine. Any explanation?

  14. Karl Says:

    Hi Victor, thanks for notifying me of the problem with the demo page. I wrote the script last fall before version 1.1 and its API change. Before 1.1, we could use a shorthand method such as .top() in place of .css('top'), but those shorthand methods have been removed.

    I updated the demo script on the test site, so it should be working just fine now. Thanks again for catching the problem.

  15. tomasz Says:

    Nice script !
    But it would be nice with a 'previous' and a 'next' button to skip the news :)

  16. commadot.com » Blog Archive » Marketo.com Launched Says:

    [...] product and public site this week.  Uses a bunch of jQuery, Tabs Plugin, Validation Plugin and Scrolling Promo Effect.  Design was done by Sean Zimmerman.  HTML Production was done by NetKitchen and myself.  [...]

  17. Randy Says:

    We did a website based off this script except that our news has a counter:

    1 of 10

    a "pause" and "next" buttons. You can see it in action here:

    http://www.crestwoodbaptist.org/

    source code available from the site using "view source" :)

  18. Markus Says:

    Hi,

    i look for a script like this, thx.
    But one question:

    When a User has JS off in the Browser nothing will display. Is there e way with JS off that all News will display with a vertical scrollbar?

    Sry for my poor english...

    greetings Markus

  19. Karl Says:

    Markus, I'm really glad you asked that question. This script should definitely degrade better than it does. Here is one way you can make it look good without JavaScript:

    1. make these changes (in bold) to the stylesheet

    #scrollup {
      border:1px solid #000;
      height:200px;
      overflow:auto;
      position:relative;
      width:200px;
    }
    .headline {
      height: auto;
      left: 5px;
      position: relative;
      top: 5px;
    }

    2. Then, to get it looking sharp again with JavaScript, replace this line:

    $("div.headline:eq("+current_headline+")").css('top','5px');

    with this:

    $('#scrollup').css({position: 'absolute', overflow: 'hidden'})
    $('div.headline')
    .css({position: 'absolute', height: '195px'})
      .not(current_headline)
      .css('top','210px');

    Let me know how that works for you.

  20. Karl Says:

    Randy, Nice work on your variation of the script. I like your additions!

  21. Markus Says:

    Hi Karl,

    thx for help. I will try it later.

    Now i found a littel "Bug". Using IE7 and move the mouse over the scroller he didn´t stop. When moved the mouse in the scroller to any direction it looks crazy... ;)

    mfg Markus

  22. Alex Says:

    Is there a version of this that would use an unordered list instead of a stack of nested DIVs?

  23. Karl Says:

    Hi Alex. I haven't written a version that would use an unordered list instead, but I don't think it would be hard to modify this one. If you used <ul id="scrollup"> and <li class="headline">, then I think it would mostly be a matter of modifying the CSS a bit and changing references to "div.headline" in the code to "li.headline"

    If you'd like to give that a whirl, feel free to contact me if you get stuck along the way.

  24. Emre Says:

    Hi Karl, thanks alot for your tutorial...
    i ve modified your code a bit, i ve changed divs to unordered list and vertical scrolling to horizontal scrolling.
    here is the modified version:
    http://www.emrecamdere.com/news_scroller_jquery.html
    i hope it ll be useful for someone

  25. Nixdama Says:

    it not works on IE7

  26. Zoo Says:

    I am looking for a code that scrolls up, pauses, then scrolls news to the left or right, then with the next news story it scrolls up, pauses, then scrolls news to the left or right again. Can the two codes mentioned be combined in someway to accomplish this action? Thanks for the tutorial!

  27. Laurent Says:

    Hi!
    First of all, thanks for this very useful script.
    I've got a problem with Flash. Have you ever tried to include an swf object in one of the headlines? While it works in IE7, the flash animation gets stuck in the bottom of #scrollup in Firefox and doesn't scroll. I imagine that your script is not to blame but the way Firefox interpret the object tag but if by any chance, you've encountered the problem...
    Once again, thanks for your work and have a nice day ;-)

  28. Karl Says:

    Hi Laurent,
    I'm sorry, but I have very little experience with Flash. You might have better luck with Mike Alsup's Cycle plugin. It's very solid with tons of features.

  29. Mike Says:

    thank you for your straightforward and functional tutorial

  30. Chad’s dailies » Blog Archive » links for 2007-10-05 Says:

    [...] Learning jQuery » Scroll Up Headline Reader (tags: jquery scroller) [...]

  31. Bhaarat Says:

    Hi Karl,

    Thanks a LOT for this. I never knew about jQuery! but this really is like magic!! Cant wait to go home and get my hands dirty with this. Also, do you know if the dzone scroll functionality where more headlines are loaded as the user is about to reach the end of the page is also done in jQuery?

    If you have some code that would kind of show how to achieve that it would be wonderfull!!

    Thanks for this!!

  32. tracert Says:

    Hi Karl,

    Thank you for the script, it's very nice. But I have a problem.
    I use the toggle() function to display and hide the headline div. When I click on the link (which hides the headline div), and click again (displays the headline div again), it starts rolling again, but it looks like this: picture

  33. miguelito Says:

    Hi all. i´m Miguelito ( newbe in jQuery from Spain)

    I have to do a continuos scroll function to a div with html structure like this:
    div-class listaScroll) ul li li li li /ul /div
    each li has html inside ( news to scroll)

    it works, but surelly you can hep me with some 'bugs'

    1.- Rest-of-the-page-links does not work if i do not 'stop' the timer properly

    2.- multiple divs in same page scrolling: scrolls at same time, stops in same time :(

    any ideas ?

    URL: my site (i´m modifiyng it)

    Thanks for your time!.

    ( I´m using jquey.timer.js for timers, but maybe innecesary, or maybe it´s the problem. I´m new with jquery timer events :) )

    CODE:


    jQuery(document).ready(function(){
    initScroll();
    jQuery(".listaScroll ul li a").hover( stopScroll, initScroll);

    function initScroll(){
    jQuery(".listaScroll").everyTime(3000, 'miTimer', scrollUp);
    }
    function scrollUp() {
    var elemParent=jQuery(this).find("ul:eq(0)").get();
    jQuery(elemParent).find("li:eq(0)").hide(2000, function(){
    jQuery(this).appendTo(elemParent).show(); //mode element to the end
    });
    }

    function stopScroll(){
    jQuery(".listaScroll").stopTime("miTimer");
    }

    jQuery("a").click( function(){ // ehem... it stops the scroll, so the links work again...
    stopScroll();
    return true;
    });

    });

  34. Catalin Oltean Says:

    How I can make script to work with an external scrollup div inserted in document with Ajax?

  35. Catalin Oltean Says:

    How I can make script to work with a scrollup div that contain an external html file inserted in document (div) with Ajax?

  36. Damith Says:

    if we put dynamic content...how we handle height thing...

    mean how height should be auto fitted to each loading....because in my case that viewing area should be changed with it loaded no of items...so..how can we handle that kind of thing...pls tell me thanks

  37. Jauhari Says:

    This is what's I looking for, I have a question.
    How to integrated this code with this effect

    http://www.malsup.com/jquery/cycle/begin.html

    Please Help me and thanks

  38. Naperville Says:

    very good tut, it really help me, thanks!

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <pre> <em> <i> <li> <ol> <strike> <strong> <ul>

IMPORTANT: If you wish to post code examples, please wrap them in <code> tags. Multi-line code should be wrapped in <pre><code> </code></pre> Also, use &lt; instead of < and &gt; instead of > in the examples themselves. Otherwise, you could lose part of the comment when it's submitted.