JavaScript Scrolling Box Marquee Replacement

Tuesday, January 29, 2008 - 14:34

Having a Marquee on a web page is a nightmare from an XHTML validation point of view, so here is a neat function that will produce the same effect as a vertical scrolling marquee, that passes XHTML validation, and built entirely from JavaScript and CSS.

Vertical Scrolling

Take the following HTML code. Don't worry about reading it. It is just 7 p tags (2 of which act as spacers) contained within a div tag.

1
2
3
4
5
6
7
8
9
<div id="marquee_replacement" onmouseout="startit();" onmouseover="stop();">
<p class="spacer"></p>
<p>Lorem ipsum dolor sit amet consectetur enim proident in elit est. Culpa sit ad aliquip laboris sit ad tempor in dolore proident. Ut ut deserunt laboris ut exercitation sit consectetur nisi sunt incididunt. Nisi non et qui adipisicing labore tempor consequat anim id dolore. Veniam velit aliquip laborum. cillum dolor amet sed dolore laborum. in. Magna deserunt veniam anim ut deserunt est ut ut.</p>
<p>Aute enim quis duis exercitation magna cupidatat ullamco duis voluptate ullamco. Ad eu est in commodo occaecat mollit officia sit elit excepteur. Elit sint duis excepteur reprehenderit consequat cupidatat quis esse occaecat elit. Officia tempor laborum. dolore dolore nulla ea adipisicing pariatur irure deserunt. Enim ullamco mollit ut eu lorem elit ex sit cillum pariatur. Laboris laboris tempor ex ad officia eu.</p>
<p>Elit est laboris nisi nostrud incididunt exercitation qui in excepteur eiusmod. Exercitation eu occaecat mollit amet esse enim consectetur non veniam occaecat. Ea occaecat commodo dolore sunt ullamco veniam incididunt aliqua labore minim. Velit et amet nulla consectetur enim eiusmod enim ut in cupidatat. Velit do excepteur dolor sed nostrud cillum ad ea veniam sint. Culpa ex sed esse exercitation sed do in lorem ea proident. Ullamco labore.</p>
<p>Eiusmod id quis exercitation officia sit aliquip enim in in aliquip. Lorem adipisicing officia elit pariatur proident ut irure aute id dolor. Tempor cillum non dolore lorem enim in velit et pariatur consequat. Excepteur ad ex fugiat est esse dolore consectetur ut ut dolor. Mollit consequat culpa laborum. aliquip sunt nostrud dolore consequat cillum labore. Dolor officia lorem do sunt nostrud aliqua velit voluptate.</p>
<p>Eiusmod id quis exercitation officia sit aliquip enim in in aliquip. Lorem adipisicing officia elit pariatur proident ut irure aute id dolor. Tempor cillum non dolore lorem enim in velit et pariatur consequat. Excepteur ad ex fugiat est esse dolore consectetur ut ut dolor. Mollit consequat culpa laborum. aliquip sunt nostrud dolore consequat cillum labore. Dolor officia lorem do sunt nostrud aliqua velit voluptate.</p>
<p class="spacer"></p>
</div>

The following style sheet will make the div look like a little box and will allow the JavaScript to turn it into a marquee. The spacer p tags are also set here so that they are the same size as the div.

1
2
3
4
5
6
7
8
9
10
11
<style type="text/css">
#marquee_replacement{
 border:1px solid #000;
 width:200px;
 height:150px;
 overflow:auto;
}
#marquee_replacement p.spacer{
 height:150px;
}
</style>

Here is the JavaScript.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<script type="text/javascript">
// <!--
var speed = 5; // change scroll speed with this value
/**
 * Initialize the marquee, and start the marquee by calling the marquee function.
 */
function init(){
  var el = document.getElementById("marquee_replacement");
  el.style.overflow = 'hidden';
  scrollFromBottom();
}
 
var go = 0;
var timeout = '';
/**
 * This is where the scroll action happens.
 * Recursive method until stopped.
 */
function scrollFromBottom(){
  clearTimeout(timeout);
  var el = document.getElementById("marquee_replacement");
  if(el.scrollTop >= el.scrollHeight-150){
    el.scrollTop = 0;
  };
  el.scrollTop = el.scrollTop + speed;
  if(go == 0){
    timeout = setTimeout("scrollFromBottom()",50);
  };
}
 
/**
 * Set the stop variable to be true (will stop the marquee at the next pass).
 */
function stop(){
  go = 1;
}
 
/**
 * Set the stop variable to be false and call the marquee function.
 */
function startit(){
  go = 0;
  scrollFromBottom();
}
// -->
</script>

You will also need to set an onload event on the body tag so that the init() function is run when the page loads. The init() function sets the overflow of the div to be hidden so that no scroll bar appears on it. This has to be done after the page has loaded as it doesn't seem to do anything when set in the main style sheet. The init() function then calls the scrollFromBottom() function which just moves the text a littler higher up the page and then calls itself to repeat the process. Once the bottom of the text goes past the top of the div the height is reset and the process repeats.

You need a <p class="spacer"></p> at the start end end of the marquee. This creates a buffer zone which makes the marquee look more natural, but not only that the height of the elements is worked out with the spacer classes in mind. You also need to make sure that you give the spacer tags a specific height. For instance, in the code above I have set the height of the spacer tags to be 150px. You must then make sure that the scrollHeight of the marquee is subtracted by the height of a spacer tag. Take a look at line 12 of the JavaScript.

The div tag is also the given two events of on mouse out and on mouse over. These functions are in place to stop the text from scrolling when a user moves their mouse over it. This can be left out or kept in depending on what you want the marquee to do, but is replicates the original functionality of the HTML marquee.

Have a look at the example of vertical scrolling JavaScript marquee.

Horizontal Scrolling

Horizontal scrolling is slightly different. It uses the scrollLeft property of the main containing div but there is some initial set up needed to figure out how much scrolling is needed. In order to get the text inside the div to scroll you need to use a inner div, which contains a set of p tags, two of which are spacer tags. The inner div is used to keep the p tags in a single line. Here is the HTML code used to the horizontal scrolling marquee.

1
2
3
4
5
6
7
<div id="marquee_replacement" onmouseout="startit();" onmouseover="stop();">
<div id="start"><p class="spacer"></p>
<p>Lorem ipsum dolor sit amet consectetur enim proident in elit est. Culpa sit ad aliquip laboris sit ad tempor in dolore proident. Ut ut deserunt laboris ut exercitation sit consectetur nisi sunt incididunt. Nisi non et qui adipisicing labore tempor consequat anim id dolore. Veniam velit aliquip laborum. cillum dolor amet sed dolore laborum. in. Magna deserunt veniam anim ut deserunt est ut ut.</p>
<p>Aute enim quis duis exercitation magna cupidatat ullamco duis voluptate ullamco. Ad eu est in commodo occaecat mollit officia sit elit excepteur. Elit sint duis excepteur reprehenderit consequat cupidatat quis esse occaecat elit. Officia tempor laborum. dolore dolore nulla ea adipisicing pariatur irure deserunt. Enim ullamco mollit ut eu lorem elit ex sit cillum pariatur. Laboris laboris tempor ex ad officia eu.</p>
<p class="spacer"></p>
</div>
</div>

Next you will need to set some styles up in order to make the p tags appear in a line.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<style type="text/css">
#marquee_replacement{
 border:1px solid #000;
 width:1000px;
 height:20px;
 overflow:auto;
}
 
#marquee_replacement div#start p{
 padding:0;
 margin:0;
 left:0;
 width:auto;
 display:inline;
 float:left;
 white-space: nowrap;
 height:15px;
}
 
#marquee_replacement div#start p.spacer{
 width:1100px;
}
 
#marquee_replacement div#start{
 display:block;
 height:10px;
}
</style>

Finally here is the JavaScript needed. It works in the same way as the vertical scroller except that the required width of the inner div tag is worked out before the scrolling is started. The script takes all of the p tags in the inner div and totals how wide each of them is. The looping function then only has to go as far as that, minus the width of the marquee_replacement div.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
<script type="text/javascript">
// <!--
var pWidth = 0;
var speed = 5; // change scroll speed with this value
/**
 * Get a collection of all of the objects of a particular type, can pass in an object that they should be collected from.
 */
function getElementsByTagNames(list,obj) {
  if (!obj) var obj = document;
  var tagNames = list.split(',');
  var resultArray = new Array();
  for (var i=0;i<tagNames.length;i++) {
    var tags = obj.getElementsByTagName(tagNames[i]);
    for (var j=0;j<tags.length;j++) {
      resultArray.push(tags[j]);
    };
  };
  var testNode = resultArray[0];
  if(!testNode){
    return [];
  };
  if(testNode.sourceIndex){
    resultArray.sort(function(a,b){
      return a.sourceIndex - b.sourceIndex;
    });
  }else if(testNode.compareDocumentPosition){
    resultArray.sort(function(a,b){
      return 3 - (a.compareDocumentPosition(b) & 6);
    });
  };
  return resultArray;
}
 
/**
 * Initialize the marquee, and start the marquee by calling the marquee function.
 */
function init(){
  var div = document.getElementById("marquee_replacement");
  div.style.overflow = 'hidden';
  
  var ps = getElementsByTagNames('p',div);
  for(var j=0;j<ps.length;j++){
    pWidth += ps[j].offsetWidth;
  }
 
  var startdiv = document.getElementById("start");
  startdiv.style.width = pWidth+'px';
  div.scrollLeft = 0;
  setTimeout("scrollFromBottom()",50);
}
 
var go = 0;
var timeout = '';
 
/**
 * This is where the scroll action happens.
 * Recursive method until stopped.
 */
function scrollFromSide(){
  clearTimeout(timeout);
  var el = document.getElementById("marquee_replacement");
  if(el.scrollLeft >= pWidth-1000){
    el.scrollLeft = 0;
  };
  el.scrollLeft = el.scrollLeft+speed;
  if(go == 0){
    timeout = setTimeout("scrollFromSide()",50);
  };
}
 
/**
 * Set the stop variable to be true (will stop the marquee at the next pass).
 */
function stop(){
  go = 1;
  timeout = '';
}
 
/**
 * Set the stop variable to be false and call the marquee function.
 */
function startit(){
  go = 0;
  scrollFromSide();
}
// -->
</script>

Have a look at the example of horizontal scrolling JavaScript marquee.

Debugging

If you are stuck as to why the marquee isn't working then you can do the following.

Add this line of HTML anywhere in your page, preferably near to where you have put the marquee. <p id="test"></p>

Add the following line of JavaScript to your marquee script. You will want to put it just after the function declaration for scrollFromBottom() for vertical Scrolling and scrollFromSide() for horizontal scrolling.

document.getElementById('test').innerHTML = el.scrollTop+ ' ' +el.scrollHeight;

This should print out two numbers. The second will be the height of the marquee element and will remain constant. The first number will increase (or decrease if you have created a backwards scrolling marquee) as the scrolling takes place. The first number will be reset when it gets to the end of the marquee. If it doesn't, or it gets to a certain value and stops then you need to look at the following line of code (from scrollFromBottom() in this case).

1
2
3
if(el.scrollTop >= el.scrollHeight-150){
 el.scrollTop = 0;
};

The value of 150 here needs to be the same as the height you set for the <p class="spacer"></p> tag in your CSS. If it is less than the value then it will never repeat itself. If it is greater than the value then it will repeat before it gets to the bottom.

Update

30/01/2007 - Added both vertical and horizontal scrolling.

22/05/2008 - Small bug noticed in the getElementsByTagNames() function due to a encoding typo. Also needed to start the marquee off in the init() function.

28/08/2008 - Added some helpful descriptions and comments.

11/02/2009 - Fixed the crazy moving faster bug. It seems that by adding a call to clearTimeout() at the start of the scrolling function it stops JavaScript trying to set lots of setTimeout() calls and therefore call this function more and more times. I have updated the code and the examples to reflect this change.

Category: 
philipnorton42's picture

Philip Norton

Phil is the founder and administrator of #! code and is an IT professional working in the North West of the UK.
Google+ | Twitter

Comments

Hi, How would you make this scroll horizontally instead of vertically? Is it an easy switch or a complete re-write? Thanks, Lisa
philipnorton42's picture
Submitted by philipnorton42 on Wed, 01/30/2008 - 17:58

Lisa, Thanks for the comment. I have changed the post so that it talks about both horizontal and vertical scrolling. It doesn't require a complete re-write, just a little tweaking.
That is a good replacement for marquee for using on XHTML coded pages. But, I can't run your script on my site. I guess it doesn't work because of onload event on body tag. I added init() funtion on my page like this. Is it correct or am i doing something else wrong? Thank you.
This script can have only one scroll bar in a web page as CSS declared is id name. I need to have more than one marquee tags to show oscillating progress bars for my web page. Only one of them will be shown at a given time. I quickly changed the CSS id styles to classes and and i generalized the script methods to accept div id names. But It is not starting the second time.
Nice elegant and compact solution on the vertical scroll! The only oddity that I experienced is that when I moved the mouse quickly through the scrolling area, it accelerated the scrolling pace. I had to move the mouse back into the scroll area and then move out slowly. Have you seen this behavior as well? Thanks, Roland
philipnorton42's picture
Submitted by philipnorton42 on Tue, 04/15/2008 - 08:55

I have seen this behaviour but I haven't been able pinpoint where it is coming from. If anyone has any suggestions then I would be more than happy to try them out.
philipnorton42's picture
Submitted by philipnorton42 on Tue, 08/12/2008 - 15:20

@Genie - Glad to help. Send me a message via the contact form above and I'll take a look at what you are trying to do. @Pram - The script is designed to have only one per page and is therefore far from perfect. I would be interested in seeing the script you have created to solve this issue.
Good replacement for the non-standard marquee tag. How to make it scroll from left to right instead of the currently implemented right to left scrolling?
philipnorton42's picture
Submitted by philipnorton42 on Wed, 05/21/2008 - 17:04

If you have the right onload functions in place then the only thing I can think of is that you are copying and pasting the code directly from hashbangcode.com and you are carrying across the annoying quote characters that Wordpress puts into the text. Look out for the character ASCII character with the code 148. I have re-encoded the post to make sure there are not odd characters there that JavaScript doesn't like.
how to change the speed of the scrolling
philipnorton42's picture
Submitted by philipnorton42 on Mon, 05/19/2008 - 15:58

Each script has a variable, defined at the top called speed. I have set it to be 5 in both scripts. var speed = 5; This is the amount of scrolling that each script does, so the higher the speed variable, the more the box scrolls by on each iteration and the faster the scrolling appears to be.
Great script. Is there a way to get it to scoll smoother? And to reverse or loop when it has finished? Right now it just stops when finished. Thanks,
philipnorton42's picture
Submitted by philipnorton42 on Wed, 08/06/2008 - 17:12

It is quite easy. All you have to do is reverse some of the parameters. Essentially you want to be counting down the scroll value, rather than counting up. I have created a demo at the following address: http://www.hashbangcode.com/examples/javascript-marquee/lr-horizontal-scroll.php
philipnorton42's picture
Submitted by philipnorton42 on Mon, 08/11/2008 - 08:50

Are you sure it stops when it is finished? In the browsers I tested it out on it repeats over and over. Getting it to scroll smoother can be accomplished by changing the amount of time delay in between function calls. Look for the following line: timeout = setTimeout(&quot;scrollFromSide()&quot;,50); This is currently set to 50, which means that 50 milliseconds pass before the function is called. you can get different levels of speed and smoothness using this value and the speed variable. Setting them both to 1 seems to create a smooth scrolling speedy marquee, but the speed varaible doesn't seem to work fully with numbers lower than 1. Hope that helps!
That does make it smoother, thanks! Everything else seems to be working great, but I need it to loop and I'm not sure why it won't. I have 8 different pictures with 8 titles, on the vertical scrolling script. One picture and one title per paragraph, but it stops at number 8. I checked all of the code to see if I mucked something up, but I couldn't find anything. I also made sure the site was xhtml valid, and css error free. That didn't seem to make any difference. This error occurs in both IE & Firefox. I'm not sure if I can post the site here, because it's adult.
Hello, I have a question on Vertical Scrolling. If I have a up/down button, what script should I put in to control the text? Regards,
philipnorton42's picture
Submitted by philipnorton42 on Sun, 09/21/2008 - 01:09

@Jackie - You have either missed out the last paragraph - the empty one. Or you have got the offset height wrong. Try fiddling with the number 150 until you get the right result.
1
2
3
if(el.scrollTop &gt;= el.scrollHeight-150){
&nbsp;el.scrollTop = 0;
};
Also, take a look at the debug section, it might point you in the right direction.
I was wondering if anyone figured out how to stop the marquee from speeding up after the mouse goes over it. Thanks, Erika
philipnorton42's picture
Submitted by philipnorton42 on Mon, 09/15/2008 - 08:51

@Erika - I haven't been able to figure out why it does that. I gut feeling is that that it is something to do with the pseudo-recursion that the function uses. Almost like it is doubling up the function calls. Anyone got any other ideas?
I just want to say thank you to tech support. #! code Rocks! They responded to my help request quickly, explained what was wrong, and even wrote the fix in a html file for me. You guys need a tip button. Thank you again!
philipnorton42's picture
Submitted by philipnorton42 on Thu, 08/28/2008 - 09:42

@Genie - You are very welcome! I have added some of the help that I sent to this post just in case anyone else comes across those problems.
I used your code and when it loads it scrolls fine up until the last paragraph. I need it to loop continuously until they leave the page. What did I do wrong?
I may have just had a breakthrough with the issue of it speeding up after mouseover. It's still not perfect but seems to have improved a lot. I declared a global variable 'lastTimeoutID' and in the scrollFromBottom function, I started using that variable to collect the ID of the setTimeout() method call, ie: lastTimeoutID = setTimeout("scrollFromBottom()",50); Then, in the stop function, the first thing I do is clear the last call - clearTimeout(lastTimeoutID);
I've modified the script to handle multiple marquees on the same page, if anyone is still interested let me know... Also, I've found that I couldn't get the marquee to loop unless the height of my spacer paragraphs was greater than or equal to the height of the div. That might be helpful to others experiencing the same issue. I'm having the issue with it speeding up as well, I agree it is probably the recursion.
philipnorton42's picture
Submitted by philipnorton42 on Tue, 12/23/2008 - 19:12

You just have to put a call to the stop() function in the init() function and the put a call to the startit() function in the onclick event of the button. You need to call the init() function to get everything started.
I need a marquee to stop scrolling when tha page loads, then go when you click a button. Thanks
Juanita, I would be interested in seeing your script modifications for multiples on the same page; and anything else you have learned or discovered about the speeding up problem. I also want to be able to implement a "hesitation" in the scroll, so that it (when scrolling up) brings a line or two in and pauses, then scrolls that out as the next lines come in (which then pause.) My thanks for all the work everyone has done so far. I have looked at a lot of different sites and code - this one seems to be the most flexible, versatile, well designed, even nearly elegant for the purpose I had in mind.
indeed a good script. just wanted to knw how culd we incoprporate it with database . i want to use data frm database
philipnorton42's picture
Submitted by philipnorton42 on Wed, 12/17/2008 - 16:20

Incorporating data from a database is simply a case of printing out the information you want inside the p tags. Remember to leave the two spacer p tags in place.
philipnorton42's picture
Submitted by philipnorton42 on Tue, 04/14/2009 - 10:49

You'll need to call the stop() function to stop it and the startit() function to start it. You will need to catch the onmousedown and onmouseup events in order to control the box in the right way. Also, remove the call to scrollFromBottom() in the init() function if you don't want the scrolling to start when the page loads.
philipnorton42's picture
Submitted by philipnorton42 on Fri, 03/13/2009 - 11:01

It sounds like you haven't called the scrollFromSide() function from within the init() function and it is therefore being called from the startit() function.
Hello Great script :) I have one bizarre problem though. I'm using the horizontal scroller and it will ONLY start once the cursor has gone over the marquee. If the cursor doesn't touch it, the scrolling doesn't start! I must have done something simple wrong?!
Thanks for your reply! I know the script of the "function scrollFromBottom()" is calling the function to move up, but I don't know how to change the script to call the function to move down. Regards
philipnorton42's picture
Submitted by philipnorton42 on Wed, 04/15/2009 - 08:40

Oh yes, good point! You will need to use the scrollBottom property instead of the scrollTop property. You could ether get the scrollFromBottom() function to switch modes, or you could just create a different function.
some text marqeeing up and down then mouse go in that text it stopped how it is in java script
Hey wonderful script, the only problem im having is that I cant seem to be able to start the scrolling unless mouse over, I reall want it to be when the page loads, how can i do that, I know someones mentioned something about it above but i cant figure it out, nay help would be appreciated, thanks.
This is exactly what I needed, after searching all day. However one slight problem, same as the previous person posted, it only start scrolling when the mouse is hovered over it to start it. How would you get it so it just starts automatically when the page loads up? Cheers.
philipnorton42's picture
Submitted by philipnorton42 on Mon, 06/21/2010 - 09:59

You just need to stick a call to the start() function somewhere on the page so that it is called when the dom element is available. This can be after the container element or within the onload element in the body element.

Why I should use your script, I think there is a simple way makin a marquee text, something like this:

<marquee direction='left' behaviour='scroll' scroolamount='1' delay='1'>This is a marquee text</marquee>

Could explain to me I use don't use that script?

philipnorton42's picture
Submitted by philipnorton42 on Wed, 09/21/2011 - 09:47

You don't have to use it if you don't want to. I wrote this code years ago and it was just a way of getting to grips with JavaScript at the time. 

Hello im trying to make 2 buttons 1 pointing up and the other down the idea is that when i mouseover them the text moves the way they point and it speeds up and can we make the default scrolling from top to bottom??
Thanks a lot!

I have a slight problem at 702tvrepair.com, a website I'm doing for a company for my technical report writing class.
I successfully implemented the marquee but it takes time to start. It takes quite a few seconds to start and I don't think the user will want to stay long enough on the front-page to see it start. I noticed that increasing the start p.spacer width allowed it to stay long enough on the screen to see the last few characters. ... but how do I get it to come up right away?

Somehow I changed the if(el.scrollLeft >= pWidth-1000) before to if(el.scrollLeft >= pWidth-0) and that seemed to do the job but it wouldn't work on Android Chrome as it stopped at the end. That would have been swell because it started right away but I have to get it to work on Android Chrome because one of my main points is cross-platform compatibility.

Your help will be greatly appreciated! Thanks!

Hi, I'm a newbie here in html. And i am doing a sample site which i have an iframe. All i need to do is to put a content inside of it. I'll be using a marquee for that. How can i put that inside iframe without using any src? Thanks. (Please use not technical words. I cant understand most of it.)

Hi, I'm a newbie here in html. And i am doing a sample site which i have an iframe. All i need to do is to put a content inside of it. I'll be using a marquee for that. How can i put that inside iframe without using any src? Thanks. (Please use not technical words. I cant understand most of it.)

hi im not good with english and html. i cant understand everything. i always tried scrollbar and marquee. i m glad found it but that code is high level for me. vertical worked but horizontal dont worked. i using vertical but my problem is its stoping and dont starting again end of pictures. im sorry maybe i cant tell you.
http://enisbaydemir.blogspot.com.tr/ you can see it on my mainpage at right side. i dont know maybe i need to use a slider for that its hard to find a slider with scrollbar javascript

philipnorton42's picture
Submitted by philipnorton42 on Thu, 02/06/2014 - 16:55

I honestly wouldn't use this code. It was written a long time ago (way before Android Chrome was a thing) and there are much better examples of scrolling effects by more competent JavaScript developers ;)

Thanks for your honesty! I searched what you told me, ...for an Android Chrome compatible marquee and the first one I found worked like a charm with an extra bouncy benefit. Thanks again!

Hi, Please send me the cript to handle multiple marquees on the same page. Thnaks

Add new comment