Check out my latest project: Full Frontal JavaScript Conference

The Silky Smooth Marquee

As we abused the Internet back in the 90 with tags like <blink> and <marquee> the last 10 years have seen the gradual extinction of these proprietary tags until we did full circle and the marquee effect appears in CSS 3.

There's actually a very strong business case and requirement for the marquee tag - since the only the alternative is often a hacky solution (I feel) that shifts the CSS left position which, depending on your browser, will begin to eat away at your CPU.

Funnily enough, the marquee tag is pretty well supported amongst the browser, but the actual effect is poorly executed natively (which is kind of odd if it's built directly in to the browser). So let's solve this with JavaScript.

Demo

This demonstration shows 3 jQuerified marquees and 3 standard marquees. You can see how the untouched marquees are jumpy to animate, even in the later browsers such as Firefox 3 and Safari - let alone IE6.

Demonstration of jQuery Marquee

Download

Download jQuery marquee plugin

Usage

Include the latest jQuery and the plugin file via the script tag, then:

$('marquee').marquee(optionalClass);

Note that the enhanced marquee doesn't particularly have to apply to a marquee tag - but it is reading the effect details from the tag - currently it will default to behaviour = scroll, dir = left, speed = 2. There's no (current) option for setting an overall default - but I'll add this if people feel it's required.

How it Works

There's a few solutions available that create a similar effect, but this plugin does two things differently:

  1. Progressively enhances the marquee tag making this plugin uber easy to use.
  2. The effect is not achieved using CSS. It's created using the overflow scroll on the element, which massively reduces the work the browser has to do - i.e. there's no re-rendering due to changes in CSS, it's scrolling using native functions of the browser.

It's worth noting that behind the scenes, the marquee tag is being lifted out of the DOM and replaced with divs. However, when it's chains in jQuery, it returns the new enhanced marquee div, so you can still hook click events, or navigate the DOM element if you wish - i.e. business as usual.

However, be warned - as we are lifting the marquee's contents in to a new div, it means and predefined events or data will be lost. To avoid this, make sure the marquee plugin is called before hand.

Events

The following events can be bound to:

  • stop - triggers when a loop is completed
  • start - triggers when a loop is started
  • end - completely finishes the loops if set

The follow events can be triggered by the user:

  • pause/stop (both do the same thing)
  • unpause/start (both do the same thing)

Support

I've written the marquee to run on a single timer function rather than one per marquee, the idea being that you could go crazy and add lots of marquees, and this code should scale.

Also, the marquee doesn't currently support direction="up" or direction="down"...yet. Come back later and I'll upgrade if there's any interest.

The marquee plugin now supports all directions.

† I've not tested it with more than 3 marquees yet - feel free to test and give feedback

Other Uses

I've played around with the implementation of the marquee and I've been able to easily create the effect of the user clicking and dragging the marquee back and forth - which is very smooth (note that before I start the drag effect, I need to trigger a stop event):

$('div.demo marquee').marquee('pointer').mouseover(function () {
  $(this).trigger('stop');
}).mouseout(function () {
  $(this).trigger('start');
}).mousemove(function (event) {
  if ($(this).data('drag') == true) {
    this.scrollLeft = $(this).data('scrollX') + ($(this).data('x') - event.clientX);
  }
}).mousedown(function (event) {
  $(this).data('drag', true).data('x', event.clientX).data('scrollX', this.scrollLeft);
}).mouseup(function () {
  $(this).data('drag', false);
});

129 Responses to “The Silky Smooth Marquee”

  1. Hiya. I attempted to add this code to a page already running with jQuery 1.4.1, however it didn't work. Swapping 1.4.1 for 1.2.6 fixed the problem immediately.

  2. Great plugin, but scrollamount property 1 is just a hair fast. I tried to 0.5 in the js file but it didn't render.

  3. 3 marquees with 60 a hrefs in it - not so smooth, about the same as jStockTicker-1.1

    thanks anyway.

  4. Thanks for sharing your work!

  5. Great piece of work!

  6. I have used your marquee plugin on one site and appreciate your efforts to provide this solution.

    I have encountered one problem that I have not been able to resolve. In Firefox the scrolling marquee (up) resets after the fourth item becomes visible. It works fine in all other browsers. Any idea why this might be happening and how to resolve it?

    Thanks.

  7. Christopher Evans March 10th, 2010 at 11:36 pm

    I am curious though if create a header on my website with this scrolling text... if every time a visitor switches pages, I don't want the scrolling text to start over. Anyway to keep it from resetting to the beginning and just continuing where it left off? I hope my questions makes sense.

  8. Wow...! This looks and works great, but I have a couple of questions.

    I would like to begin the scroll only on mouseover from a stopped state, and once the cursor mouseouts continues until the current scroll is done then stops.

    So firstly, how would this script be modified to accomplish the initial stopped state? Swapping the start and stop around in the jQuery script does not have any effect until one mouseovers.

    And secondly, how to modify it to continue until the end of the current scroll after mouseout?

    Unfortunately, my proficiency level with jQuery is only amateurish so I would very much appreciate assistance.

    Thanks in advance.

  9. The it is a bit too fast for me, so I modified the class:
    Added parameter 'stepDelay' to the function:

    $.fn.marquee = function (klass, stepDelay) {

    At the function beginning added parameter check which sets the default value:

    if (stepDelay == undefined || isNaN(parseInt(stepDelay, 10)) || stepDelay <= 0)
    stepDelay = 25;

    Finally replace the timeout of 25 (line 91) by stepDelay.

    setTimeout(animateMarquee, stepDelay);

    Use it like:

    $('#myMarquee').marquee('pointer', 60);

    Enjoy :-)

Leave a Reply
Not required

CODE: Please escape code and wrap in <pre><code>, doing so will automatically syntax highlight