The context of the example is a news scroller so we’ll be working with plain text, but we should be able to put whatever we wanted into the underlying mark-up; images, or links, or whatever. We’ll be using jQuery as the underlying JS library, and a little HTML and CSS. Let’s make a start.


Final Product

The Underlying HTML

In a new page in your text editor add the following code:
  1.     
  2.     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">  
  3. <link rel="stylesheet" type="text/css" href="simpleTicker.css">  
  4.     
  5.     
  6. <dl id="ticker">  
  7. <dt>This is a news title!</dt>  
  8. <dd>This is a snippet of the news. It could be the whole news item or it could link to another page containing...</dd>  
  9. <dt>News Heading 2</dt>  
  10. <dd>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</dd>  
  11. <dt>News Heading 3</dt>  
  12. <dd>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</dd>  
  13. <dt>News Heading 4</dt>  
  14. <dd>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</dd>  
  15. <dt class="heading">This item is long!</dt>  
  16. <dd class="text">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</dd>  
  17. </dl>  
  18.   
  19.     <script type="text/javascript" src="jquery-1.3.2.js"></script>  
  20.     <script type="text/javascript">  
  21.   
  22.     </script>  
  23.     
Save this as simpleTicker.html in a directory containing jQuery 1.3.2. As well as the usual page furniture – the DOCTYPE, META content-type, title, etc – we have a custom style sheet that we’ll create in just a moment and we link to jQuery at the end of the body (for performance reasons).
Example
On the page is the content that we’ll progressively enhance into the news ticker; it’s made up of a simple definition-list element, which feels appropriate for our purposes. Although only inline content can be placed in each <dt> element, block-level content can be put in the <dd> elements.
The code is minimal and highly accessible; browsers, mobile devices and screen-readers should all have no difficulty interpreting and rendering it. With no styling however, it does look pretty shocking:

Providing Default Styling

Let’s add some basic styling; even with JavaScript switched off, no one wants to see the list as it is at the moment. In a new file in your text editor add the following code:
  1. #ticker {  
  2.   width:180pxheight:300pxoverflow:autoborder:1px solid #aaaaaa;  
  3. }  
  4. #ticker dt {  
  5.   font:normal 14px Georgia; padding:0 10px 5px 10px;  
  6.   background-color:#e5e5e5padding-top:10pxborder:1px solid #ffffff;  
  7.   border-bottom:noneborder-right:none;  
  8. }  
  9. #ticker dd {  
  10.   margin-left:0; font:normal 11px Verdanapadding:0 10px 10px 10px;  
  11.   border-bottom:1px solid #aaaaaabackground-color:#e5e5e5;  
  12.   border-left:1px solid #ffffff;  
  13. }  
  14. #ticker dd.last { border-bottom:1px solid #ffffff;  
Save this file in the same directory as the page and call it simpleTicker.css. We give the list a set width and height and set the overflow property to auto; the height of the ticker is less than the space required to show all of the news items so the scrollbar will allow visitors with JavaScript disabled to view all of the content.
Example
Some of the styles are purely presentational; anything that sets a background-color, border or font is totally arbitrary and is used to make the example a little more attractive. The widget should now look like this:
However minimal we choose to make it, it’s a big improvement on the default rendering; it would quite happily fit into a sidebar or column now; it’s an acceptable fallback from the finished widget and a great foundation from which to progressively enhance.

Progressively Enhancing the Ticker

Now we can move on to the fun part – adding the JavaScript that will turn this from a simple list into an automatic ticker; in the empty <script> element at the bottom of the page add the following code:
  1. $(function() {  
  2.   
  3.   //cache the ticker  
  4.   var ticker = $("#ticker");  
  5.   
  6.   //wrap dt:dd pairs in divs  
  7.   ticker.children().filter("dt").each(function() {  
  8.   
  9.     var dt = $(this),  
  10.       container = $(" 
  11. <div>");  
  12.   
  13.     dt.next().appendTo(container);  
  14.     dt.prependTo(container);  
  15.     container.appendTo(ticker);  
  16.   });  
  17.   
  18.   //hide the scrollbar  
  19.   ticker.css("overflow""hidden");  
  20.   
  21.   //animator function  
  22.   function animator(currentItem) {  
  23.   
  24.     //work out new anim duration  
  25.     var distance = currentItem.height(),  
  26.     duration = (distance - Math.abs(parseInt(currentItem.css("marginTop")))) / 0.025;  
  27.   
  28.     //animate the first child of the ticker  
  29.     currentItem.animate({ marginTop: -distance }, duration, "linear"function() {  
  30.   
  31.       //move current item to the bottom     currentItem.appendTo(currentItem.parent()).css("marginTop", 0);  
  32.   
  33.     //recurse  
  34.     animator(currentItem.parent().children(":first"));  
  35.     });  
  36.   };  
  37.   
  38.   //start the ticker  
  39.   animator(ticker.children(":first"));  
  40. });  
  41. </div>  
All of our code is encased within the jQuery document.ready short-cut $(function(){ }) which will execute the anonymous function as soon as the page has loaded. The first thing we do is to cache our main selector, which is the outer <dl> element; this will save us from having to repeatedly select the element from the DOM whenever we want to work with it and improves the performance of the page.
The underlying definition list contains both definition term and definition description elements, all of which could potentially be of varying sizes. To make things a little easier in our script we next wrap each <dt> and <dd> pair in a containing <div> element; this allows us to group the different elements logically and smooth out the animations. It also means that we can use whatever margins and padding on the *lt;dt> and
elements without needing to take these into consideration in our animation calculations.
To do this we select all of the children from our cached selector and use the jQuery filter method to discard all of the <dd> elements. Then for each remaining <dt> we create a new container <div> and append both the <dt> and the <dd> to the new container. We have to add the <dd> that follows the current <dt> first, because once the <dt> has been appended to the container it won’t have a <dd> after it. We therefore need to use the prepend method on the <dt> once the <dd> has been appended.
Once all of the <dt> and <dd> pairs have been wrapped in <div> elements we then change the ticker’s overflow CSS property to hidden so that the scrollbar is removed. This is part of the accessibility strategy and ensures that only visitors with JavaScript enabled get to see the enhanced ticker.
Next we define our animator function, which is where we’ll set the animation which causes the ticker to begin scrolling and then keep scrolling indefinitely. This is a regular JavaScript function which accepts a single parameter; when we call this function we’ll pass in the first container element within the ticker.
The first thing we do within this function is work out the distance that the selected element has to travel and the duration of the animation. The distance part is easy; it’s just the height of the current container element.
The duration is a little more complex; it’s the total distance to travel minus the distance already traveled, divided by a baseline speed that I’ve arbitrarily set at 0.025. The height will already be an integer but the css method will return a string representing the margin-top of the element being animated so we need to use JavaScript’s parseInt() function to convert it to a number. It will also be a negative number so we use the Math.abs() JavaScript function to convert it from a negative to an absolute (positive) number.
The baseline speed that we divide the remaining distance to travel by is pretty slow in my opinion; I’ve seen tickers before (built with Java) and they’ve been approximately the same speed and I didn’t get motion sickness or suffer any ill effects. If you feel that the animation is too fast (or even too slow) feel free to change this figure. It needs to be a really small number though; anything in the range of 0.01 to 0.09 is probably going to be ok.
Once we have these figures we can then create the animation using jQuery’s animate method. The first parameter for this method is the actual animation itself; we want the first of the container elements in the ticker to be moved upwards until it is completely hidden in the overflow, but we also want to drag the rest of the container elements up by the same distance as well so we use adjust the marginTop of the element.
The second argument of the animate method is the duration which we worked out a moment ago. The third argument is the easing method; custom jQuery animations automatically get two types of easing – swing and linear. Swing causes the animation to speed up and slow down, while linear makes it sooth and continuous, so this is the option for us in this situation.
The final argument is an anonymous callback function that will be executed when the animation ends. Within this function we move the element that has just been animated to the end of the set of containers, reset its marginTop back to 0, and then recursively call the animator function again, passing in the new first-child of the ticker.
Finally, we need to call the animator function once to start off the whole process. When we view this page in a browser, the ticker should smoothly scroll through each of the elements in the list repeatedly:

Starting and Stopping

Example
Now we need to think about what we want to happen when a visitor mouses-over a news item; personally I think the default behavior should be that it pauses on mouse-over and then restarts again on mouse out. We can easily add this behavior with a couple of jQuery event handlers; add the following code just before the final brace/curly brace combo:
  1. //set mouseenter  
  2. ticker.mouseenter(function() {  
  3.   
  4.   //stop current animation  
  5.   ticker.children().stop();  
  6.   
  7. });  
  8.   
  9. //set mouseleave  
  10. ticker.mouseleave(function() {  
  11.   
  12.   //resume animation  
  13.   animator(ticker.children(":first"));  
  14. });  
Both of these functions are really simple; we use mouseenter and mouseleave instead of mouseover and mouseout because it makes these functions nice and small; we don’t need to worry about ignoring mouseouts when the pointer moves from the outer ticker element to one of the child elements. In the mouseenter function we simply stop the animation. In the mouseleave function we just restart the animation once more, passing in the first-child of the ticker.

Fixing IE

We have one problem left to solve, and fortunately it’s an easy one. Running the page as it is in IE (tested in version 8) throws an error as soon as it is loaded. The error is caused because the very first time the animator function runs the first container <div> will have its margin-top set to auto by the browser. Other browsers will interpret the margin-top as 0. Which browser is correct is debatable, although I’ll let you draw your own conclusion about the fact that IE is the only browser that causes the problem. All we need to do to fix it is explicitly set the margin-top of the container elements. We can do this by adding the following line of code to the style sheet:
  1. #ticker div { margin-top:0; }  
Now the page should work in IE as well:
Example

Summary

This now brings us to the end of the tutorial, we should now have a simple but effective news ticker that can be put to use in a variety of ways. When using text, like in this example, defining the headings and associated content sections within a definition list makes sense from a semantics perspective, and it’s easy to add any additional elements we may need as we go.

0 nhận xét:

Đăng nhận xét

 
Top