The bread and butter of jQuery is its ability to interact with all kinds of browser and physical events, including mouse movement, form interaction, and keyboard events. You can take control of these events using jQuery to provide your Web-site visitors with a much richer interactive experience.
By binding events such as a mouse click or a keypress to text, links, images, and other DOM elements, you can call into action myriad functions from animation to AJAX. Functions can be combined to create complex chain reactions, a very cool thing.
In this chapter I’ll show you how to gain control over many of these events while creating a fictional Web site called Photographer’s Exchange. You will combine the events to create effects that will make your Web audience sit up and take notice. Other events are very subtle and will add flavor to your Web applications.
You will design the Photographer’s Exchange Web site to allow photographers to show off their pictures and techniques. Users will be able to upload pictures and edit information about those pictures. Additionally, users will be able to submit articles about photography. Visitors will be able to search the site using different criteria. The front page of the site will showcase featured photographs and articles from photographers. Figure 2.1 shows the basic layout of the site ready for editing.
All of the code in this book is available as a download from the book’s Web site at www.appliedjquery.com/download.
If you want to apply the principles of progressive enhancement—as discussed in Chapter 1—to your site, you need to make your navigation as graceful as possible. The easiest way to do this is to fully form your links as if JavaScript, and therefore jQuery, is not available for your visitors.
Open the chap2/2-1.php file. You’ll find an unordered HTML list containing three links:
<a href="search.php" rel="searchWindow" class="modal"
id="search"><span>Search</span></a>
<a href="register.php" rel="registerWindow" class="modal"
id="register"><span>Register</span></a>
<a href="login.php" rel="loginWindow" class="modal"
id="login"><span>Login</span></a>
Each link works properly in the absence of JavaScript. Clicking on any of them causes the respective page to be loaded into the browser.
To save time and space in this book, I did not create the additional Web pages. The content for each modal window, which is contained in 1-1.php, can be placed in separate pages if you are concerned that users will not have JavaScript available.
This set of links will be used to call modal windows into the browser.
Modal windows are a clever way for users to interact with Web sites and applications. They provide smooth transitions by placing content “above” the current Web page and can give users information, as well as receive information from users either in forms or a confirmation dialog. Once the modal window is closed, users return to the same content in the Web browser that they were viewing previously.
Each modal window is used to perform a specific action in the site: search, register, or login. You do not have to make any modifications to the HTML for the links; all you have to do is add the proper jQuery.
1. Create a jQuery statement that selects all of the anchor tags that have a class of modal
:
$('a.modal').click(function() {
You have now handed over control of the click
event to jQuery or have bound jQuery’s click
event to the anchor tag. This binding allows jQuery to handle the click
event and any functions assigned to that event.
The remainder of the function decides which modal window to open, where to place the window, and how to close the modal window. Additionally, the function places a semitransparent “shade” over the entire site to make the modal window stand out. You can find the complete code in chap2/inc/jqpe.js under the section commented /* modal windows */
.
2. Store the value of the rel
attribute from the currently clicked item in a variable that will be used later in the function:
var modalID = $(this).attr('rel'),
3. Fade in the modal window that you selected and add a link that allows you to close the modal window. A graphic element (close_button.png) is used to make the close button look nice:
$('#' + modalID).fadeIn().prepend('<a href="#"
class="close"><img src="grfx/close_button.png"
class="close_button" title="Close Window"alt=
"Close" /></a>'),
In the file chap2/inc/modal.css, the margins and padding were defined for each of the modal windows. To get them to center on the screen, you need to account for the extra space created by the padding and margins so that the proper offset can be applied. In this case there is a 20-pixel margin and 20 pixels of padding surrounding each modal window. That means that you must add 80 pixels to the height and width. With the height and width set, you then divide by 2 to get the proper margin.
4. Assign the horizontal and vertical margin calculated values to the variables modalMarginTop
and modalMarginLeft
:
var modalMarginTop = ($('#' + modalID).height() + 80) / 2;
var modalMarginLeft = ($('#' + modalID).width() + 80) / 2;
5. Now add the margin information to the modal window’s CSS to center it:
$('#' + modalID).css({
'margin-top' : -modalMarginTop,
'margin-left' : -modalMarginLeft
});
Figure 2.2 shows a model of the modal box and how much it must be offset to the top and left of the browser window to center the box.
If you don’t calculate where the center of the box should go, the upper-left corner of the box will be centered in the browser window, as shown in Figure 2.3.
The last order of business for opening the modal window is creating a shaded background. The shade is actually a semitransparent div
through which you can still see the Web site. It is a very cool effect and helps users to understand that they are still on your site but that their attention should be focused on the content highlighted for them. You’ll use a similar version of the see-through div
for other widgets in the Web site.
1. Append a new div
to the body
to make the shade:
$('body').append('<div id="modalShade"></div>'),
2. Animate the shaded background to partial opacity to make it somewhat transparent:
$('#modalShade').css('opacity', 0.7).fadeIn();
3. Close the click
function with the return false;
method to keep the link from trying to load another page into the browser.
return false;
});
Once complete, the jQuery code opens the modal window in the center of the browser window with a shaded background that allows users to see the Web page beneath it (Figure 2.4).
Don’t worry about handling form information or processing that information right now. I’ll cover form handling and processing in Chapter 3, “Making Forms Pop” and Chapter 4, “Being Effective with AJAX.”
Users must be able to close the window and get rid of the shade, so you need to give users a way to get back to the Web site.
1. Start the close function by binding the close graphic and modal shade to a jQuery click
method:
$('a.close, #modalShade').live('click', function() {
Neither of these elements existed in the DOM (see Chapter 1 for a short discussion of the DOM) originally, so you have to use a special jQuery function, live,
to bind the click
to these elements.
2. Determine which modal window to close by getting the id
of the parent
of a.close
:
var thisModalID = $('a.close').parent().attr('id'),
3. Now fade out the modal window and the shade. When the fade-out is complete, use the callback function fadeOut
provides to remove the div
that held the shade and the link that was prepended to the modal window:
$('#modalShade, #'+thisModalID).fadeOut(function() {
$('#modalShade, a.close').remove();
});
return false;
});
In simple terms a callback is a block of executable code that is passed as an argument to another function. The block of code in the callback will run when the original function is complete. You issue a callback to the fadeOut
function as highlighted:
$('#modalShade, #'+thisModalID).fadeOut(function() {
$('#modalShade, a.close').remove();
});
The fade-out completes before issuing the callback to remove the #modal-Shade
and a.close
element from the DOM.
Combining multiple jQuery methods in this way makes a click on a link a pretty powerful event. Can you bind the click
event, or any other event, to elements that are not links? Of course you can, and you already have. Look at the following line again:
$('a.close, #modalShade').live('click', function() {
The highlighted value is the id
for the div
that held the shade, which is also bound to the live click
function. This allows users to click anywhere on the shade to fade out the modal window and perform the other items in the function. Binding to nonlink-type elements is common when using jQuery.
jQuery gives you the flexibility to bind events to any element available in the DOM. This gives you the capability to set up highly interactive user interfaces. Creating a truly fun and intuitive user experience is easier than ever because you are not limiting your users to just clicking a link or a button on your Web site.
The Photographer’s Exchange Web site needs a way to feature members’ photographs. A simple photo carousel will provide an excellent method of showcasing the members’ talents while allowing you, as the developer, to flex your creative muscles.
Let’s add a simple version of a photo carousel to the site now.
The concept for the carousel is very simple and is based on an unordered list of thumbnail images. You can see this list added to the site in chap2/2-2.php:
<div id="carouselContainer">
<div id="carouselOuter">
<div id="scrollLeft"><img src="photos/arrowLeft.jpg" /></div>
<div id="carouselInner">
<ul id="carouselUL">
<li><img class="carThumb" src="photos/thumb_ka1.jpg" /></li>
<li><img class="carThumb" src="photos/thumb_ka2.jpg" /></li>
<li><img class="carThumb" src="photos/thumb_ka3.jpg" /></li>
<li><img class="carThumb" src="photos/thumb_ka4.jpg" /></li>
<li><img class="carThumb" src="photos/thumb_ka11.jpg" /></li>
<li><img class="carThumb" src="photos/thumb_ka12.jpg" /></li>
<li><img class="carThumb" src="photos/thumb_ka13.jpg" /></li>
<li><img class="carThumb" src="photos/thumb_ka14.jpg" /></li>
</ul>
</div>
<div id="scrollRight"><img src="photos/arrowRight.jpg" /></div>
</div>
</div>
Now that you have a list of images, you need to add the following carousel features:
• Automatic scrolling.
• Scrolling that stops when a mouse cursor hovers over any portion of the carousel.
• Scrolling that continues when the mouse cursor is not hovering over any portion of the carousel.
• Highlighting an image when the mouse cursor hovers over a thumbnail of that image.
• Controlling manual scrolling.
• Displaying a larger version of a picture when its respective thumbnail is clicked.
Before you can start adding these features, you need to create the container for the carousel using CSS. Let’s cover that first.
To make the carousel effect work well, it must have a solid container. The container will be defined by the CSS along with the markup that you created earlier.
1. Set up the #carouselInner
rule to allow only a certain number of thumbnails to be visible at any one time:
#carouselInner {
float: left;
width: 510px;
overflow: hidden;
background: #000000;
}
The #carouselInner
rule sets up a visible area of 510 pixels. Anything outside of the element assigned to this rule will not be visible. The 510-pixel area is calculated by adding the widths of three thumbnails (160 pixels each) plus 10 pixels for each thumbnail. The additional pixels allow for padding around each image.
2. Create a left margin that allows two images to be hidden off to the left of the carousel. Setting this margin is the most important part of the #carouselUL
rule. Having two images to the left of the carousel ensures that the scrolling will happen smoothly. Make sure that the whole carousel is wide enough to hold the number of thumbnails you plan to display. In this case #carouselUL
is designed to hold a maximum of 50 thumbnails:
#carouselUL {
position: relative;
list-style-type: none;
left: -340px;
margin: 0px;
padding: 0px;
width: 8500px;
padding-bottom: 10px;
}
3. Now set the height and width of the list items:
#carouselUL li{
float: left;
width: 160px;
height: 128px;
padding: 0px;
background: #000000;
margin-top: 10px;
margin-bottom: 10px;
margin-left: 5px;
margin-right: 5px;
text-align: center;
}
Figure 2.5 gives you an idea of how list items will be moved. As the carousel scrolls to the left, the first list item is moved to the end of the list while the item is invisible. The reverse happens (the last list item is moved to the first spot) when the carousel scrolls to the right. The user gets the impression that the images are on a carousel going around and around.
Once the style information has been defined, you can begin working on adding the features to the carousel using jQuery.
There is much more to the CSS (chap4/css/carousel.css) for the carousel, but it is mostly decorative or setting up space for the arrows that will be used for manual control of the carousel. Additionally, the style information for the modal window to display the larger pictures is defined.
It is time for you to start adding the features defined for the carousel. You’ll first create a function that automatically scrolls the carousel. Create a file called carousel.js and save it in the chap2/inc folder.
1. Create the function using the function keyword and call the function autoCarousel. Then s
et the variable itemWidth
equal to the width of one of the list items in the carousel and add 10 to it to make space for the padding:
function autoCarousel() {
var itemWidth = $('#carouselUL li').outerWidth() + 10;
2. Determine how far to the left the carousel needs to move. Recall that the left margin of the CSS was set to -340 originally, so the moveFactor
will be -510. Assign the results of that calculation to the variable moveFactor
:
var moveFactor = parseInt($('#carouselUL').css('left'))
- itemWidth;
3. Now the fun really begins! Bind the animate
method to the unordered list identified by #carouselUL
. Then the list of images is moved to the left so that the images’ left margins are the same as the moveFactor
. Add the duration of slow
and easing transition of linear
for tighter control of the animation:
$('#carouselUL').animate(
{'left' : moveFactor}, 'slow', 'linear',
function(){
4. Move the first list item to the end of the list, after the last list item. This line of code, contained in the animation’s callback function, contains the secret to making the carousel infinite:
$("#carouselUL li:last").after($("#carouselUL
li:first"));
By moving the list item and changing the order of the HTML list as a whole, you can make the pictures appear to keep going around the carousel.
Easing, in jQuery terms, tells an animation how fast to move at different points during the animation’s progress. jQuery includes two default easing methods: linear and swing. Linear moves the animation steadily from point A to point B with no speed change. Swing moves the animation slowly at first, faster near its midpoint, and then slows down as it reaches its end. Both of these easing methods will help to smooth animations, making them less jerky. You can create some cool effects by using George Smith’s jQuery Easing Plugin. The plugin makes dozens of additional easing types available to use in your jQuery applications. The plugin is available from the GSGD Web site at http://gsgd.co.uk/sandbox/jquery/easing.
5. Close out the function by resetting the left margin back to its original value and closing all of the brackets and braces:
$('#carouselUL').css({'left' : '-340px'});
});
};
If you don’t reset the left margin, the carousel will continue to scroll to the left, and eventually the pictures will be out of sight.
6. Call the autoCarousel
function by placing it in a setInterval
function. Give the setInterval
method an identifier by assigning it to a variable. Set the interval to 2000 milliseconds (2 seconds):
var moveCarousel = setInterval(autoCarousel, 2000);
Now you can load the page. You’ll see that the carousel starts automatically and pauses for 2 seconds between each animation.
7. Use the very next line of code to make all the thumbnails and the arrow graphics appear to be faded:
$('.carThumb, #scrollLeft, #scrollRight').css({opacity: 0.5});
You’ll take advantage of the opacity being set to a faded state when you create the hover
functions.
You’ll bind the hover
function to the thumbnail images identified by the class of carThumb
as well as the divs
containing the arrows that will be used to manually control the scrolling of the carousel. Three actions are required for the hover
function:
• Stop the scrolling when a mouse cursor hovers over any portion of the carousel.
• Highlight the image when the mouse cursor hovers over a thumbnail.
• Continue scrolling when the mouse cursor is not hovering over any portion of the carousel.
1. Bind the hover
function to the class carThumb
and elements with an id
of scrollLeft
and scrollRight
:
$('.carThumb, #scrollLeft, #scrollRight').hover(function() {
The hover
function consists of two sections, one for mouseover and one for mouseout. The jQuery hover
method combines this functionality to give you a tremendous amount of flexibility.
2. Bind the jQuery stop
and animate
methods for the mouseover portion of the function to elements represented by $(this)
. The stop
makes sure that the current animation will quit when you move the mouse away or perform some other action. Without stop
, the animations would continue to queue up and run, and that is not desirable for the hover
function:
$(this).stop().animate({
opacity: 1
}, 75);
The animation makes the image fade to full opacity very quickly (75 milliseconds). This gives the appearance of the image being highlighted and fulfills one of the requirements. The cursor is hovered over a thumbnail in Figure 2.6, making it appear to be brighter than the thumbnails adjacent to it.
3. Stop the scrolling animation of the carousel by clearing the setInterval
function. Identify the interval to be cleared by passing the identifier moveCarousel
to the clearInterval
function:
clearInterval(moveCarousel);
4. Add the code to fade the image in the mouseout portion of the hover
function:
}, function() {
$(this).stop().animate({
opacity: 0.5
}, 250);
The mouseout side of the jQuery hover
function reverses the fade of the opacity and does so more slowly (250 milliseconds) just for effect. Note that you did not apply any easing to either side of the hover
function. Easing will work here, but the times for the movement to either full or half opacity are so fast that most easing methods would hardly be noticed.
5. Restart the carousel’s automatic scrolling by calling the setInterval
function in the last line of the mouseout side of the hover
function:
moveCarousel = setInterval(autoCarousel, 2000);
});
The requirements for the carousel are being met pretty quickly. Next, you’ll give the Web-site visitors a way to control the scrolling of the carousel manually.
Web-site visitors need the ability to manually scroll the carousel so they can look for specific images. Adding manual control is fairly simple, even though the movement of the carousel may seem backwards compared to the image that is clicked. In other words, clicking the right arrow moves the carousel to the left, and clicking the left arrow moves the carousel to the right.
A portion of the functionality for manual control was completed for the automatic scroll function autoCarousel
(the following highlighted code). All that you need to do is wrap the code in a function that binds a click
function to the element identified as scrollRight
:
$('#scrollRight').click(function(){
var itemWidth = $('#carouselUL li').outerWidth() + 10;
var moveFactor = parseInt($('#carouselUL').css('left')) - itemWidth;
$('#carouselUL').animate(
{'left' : moveFactor}, 'slow', 'linear', function(){
$("#carouselUL li:last").after($("#carouselUL li:first"));
$('#carouselUL').css({'left' : '-340px'});
});
});
If you’ve been really observant, you’ll notice that this click
event is bound to an arrow image that points to the right but moves the carousel to the left. As mentioned earlier, the movement might seem a little backwards for these functions, but there is a very good reason.
Visitors to Web sites have been conditioned by actions that they have performed for most of their lives. One of the most prominent of these conditions is turning the page of a book or a newspaper. This action requires you to grasp a section of the page on your right and move it to the left. It seems quite natural that this movement will reveal new content the way you expect it to. The same goes for the carousel. Clicking on the right moves the carousel to the left and feels very natural. You can test this by making a couple of changes to the function.
Moving the carousel to the right requires only a couple of changes.
1. Make a copy of the function that was used to set up manual control when clicking on the right arrow, and paste the newly copied code below that function.
2. Change the first line of the function to bind the click
function to the scrollLeft
selector:
$('#scrollLeft').click(function(){
3. Change the calculation assigned to the moveFactor
variable to add the itemWidth
instead of subtracting it:
var itemWidth = $('#carouselUL li').outerWidth() + 10;
var moveFactor = parseInt($('#carouselUL').css('left')) +
itemWidth;
The distance moved by the carousel is the same as it was before; it is just moving in a different direction. This difference in direction is accomplished by animating the move from -340 pixels left to -170 pixels left (the carousel moves from -340 pixels left to -510 pixels left when animating to the left):
4. Create the function that binds the animate
method to the carousel:
$('#carouselUL').animate(
{'left' : moveFactor}, 'slow', 'linear', function(){
5. Move the last list item to a place before the first list item:
$("#carouselUL li:first").before($("#carouselUL
li:last"));
Making this move is the opposite of the action that was performed before to reorder the image list and makes the carousel “infinite” in the opposite direction if the user continues to manually select the scrollLeft
option.
6. Reset the left margin to its original location with the last line of code to complete the requirement for manual control of the carousel:
$('#carouselUL').css({'left' : '-340px'});
});
});
To understand the movement, Figure 2.7 illustrates the normal left margin of the carousel at -340 pixels. The margin gets moved to the right or left temporarily as needed by the carousel click
functions. This gives the animation method a “go-to” location.
You need to add one more requirement to complete the carousel, and it is a huge one (excuse the pun). The carousel needs a method to display larger images.
When site visitors spot a thumbnail that they would like to get a better look at, you do not want them to just squint at the thumbnails and try to imagine them as larger images. By applying some CSS and jQuery, it is easy to give users a way to view larger pictures by clicking a thumbnail.
1. Using a technique similar to the creation of modal windows with form elements, create a div
just before the closing body
tag in chap2/2-2.php:
<div id="photoModal" class="photoModal"></div>
2. Add the style rules for photoModal
to chap2/css/carousel.css:
.photoModal {
display: none;
background: #FFFFFF;
color: #000000;
border: 20px solid #FFFFFF;
float: left;
font-size: 1.2em;
position: fixed;
width: auto;
height: auto;
top: 50%;
left: 50%;
z-index: 200;
}
It is important that you include a height and width property (highlighted) in the rule because these properties ensure that the image loaded into the div will fill the div properly and support the calculation that centers the picture within the browser window.
Next, you’ll add the additional functions to handle the large images to the file you created earlier, chap2/inc/carousel.js. The first addition should be a function that loads all of the larger images into hidden divs
having a class of photoHolder
. It is necessary to load the images this way because jQuery cannot measure the height and width of something that is not yet loaded. Without the facility to measure elements not yet in the DOM, loading each image when the thumbnail is clicked may give you erratic results.
1. Bind the thumbnails with a class of carThumb
to the each
method to begin the function:
$('.carThumb').each(function(){
2. Extract the image’s path and name information based on the source of the thumbnail. For example, the first line assigns photos/thumb_ka1.jpg to the variable photoInfo
:
var photoInfo = $(this).attr("src");
3. Split the thumbnail path information apart at the forward slash:
var photoPathArr = photoInfo.split('/'),
The split creates an array called photoPathArr
. This array contains two pieces of information; photos contained in photoPathArr[0]
and thumb_ka1.jpg in photoPathArr[1]
.
4. Concatenate a forward slash to photos (contained in photoPathArr[0]
). The forward slash is needed to truly represent the path for the images:
var photoPath = photoPathArr[0]+'/';
5. Perform another split to get the actual name of the full-sized image:
var photoInfoArr = photoInfo.split('_'),
The name of the full-sized image will be contained in photoInfoArr[1]
.
6. Reassemble the two pieces to provide the path to the full-sized image like photos/ka1.jpg:
var photoSrc = photoPath+photoInfoArr[1];
Note that manipulating text as you just did occurs frequently in jQuery (and other programming languages). As a matter of fact, you’ll see similar text manipulation later in this function when you bind the click
event to the thumbnails. As your skills grow, you’ll be able to write functions that will process text manipulations like this quickly, and more important, as snippets of code that are reusable.
7. Define the images by creating a new image with the $('<img/>')
selector and bind the image to the load function:
$('<img/>').load(function(){
8. Append a div
to the body of the HTML document to hold the full-sized image:
$('body').append('<div class="photoHolder"><a
href="'+photoSrc+'"</div>'),
9. Set the CSS display
property to none
for each of the elements assigned the class photoHolder
. This is to make sure that each newly added element is invisible to the Web-site visitor:
$('.photoHolder').css('display','none'),
10. Give the new $('<img/>')
its source information:
}).attr('src', photoSrc);
});
As the each
function loops through the unordered list of images, each full-sized image will be placed into its respective element and hidden away from the user.
For the click
function that will be bound to the thumbnails, you will go through the same text-manipulation steps that were performed for the image-loading function. The steps are repeated again because the load
and click
functions are discrete from each other and cannot access each other’s variables.
1. Bind the elements having a class of carThumb
to jQuery’s click
method:
$('.carThumb').click(function() {
2. Step through the text-manipulation steps to get the path and full-sized image name:
var photoInfo = $(this).attr("src");
var photoPathArr = photoInfo.split('/'),
var photoPath = photoPathArr[0]+'/';
var photoInfoArr = photoInfo.split('_'),
3. Create an image tag for the full-sized photograph:
var photoImgTag = '<img src="'+photoPath+photoInfoArr[1]+'"
id="currentPhoto" />';
4. Get the name of the modal window to be used from the rel
attribute of the thumbnail:
var modalID = $(this).attr('rel'),
5. Place the image tag into the modal window:
$('#' + modalID).html(photoImgTag);
6. Apply the fade to the photoModal to make it appear in the browser window. Additionally, append a button that allows visitors to close the window to the modal window:
$('#' + modalID).fadeIn('slow', 'swing').append('<div
class="photoNote"><a href="#" class="closePhoto"><img
src="grfx/photoClose.jpg" class="closeX"
title="Close Photo" alt="Close" /></a></div>'),
7. Load the current height of the HTML body into the variable bodyHeight
:
var bodyHeight = $('body').height();
$('#currentPhoto').css('height', (bodyHeight - 200));
The bodyHeight
variable is then used to set the total height of the enlarged image. Doing this will keep the enlarged image within the boundaries of the browser window, preventing the site visitor from having to scroll up and down to see the full image. The height applied to the enlarged image is 200 pixels less than the total height of the browser window, which will also allow for a nice-looking border around the picture.
Name items carefully so that their information is reusable in ways that will shorten your code and allow you to write more efficient functions. Prefixing the photograph’s name with “thumb_” in this case will give you all the information you need to create the proper path for retrieving the full-sized images. The function for uploading photos (in Chapter 3) will name the thumbnails and full-sized images for you.
8. Use the same calculation that centered the modal windows earlier to center the current modal window:
var modalMarginTop = ($('#' + modalID).height() + 40) / 2;
var modalMarginLeft = ($('#' + modalID).width() + 40) / 2;
$('#' + modalID).css({
'margin-top' : -modalMarginTop,
'margin-left' : -modalMarginLeft
});
9. Close out the function by adding the see-through shade to the background to make the photograph stand out:
$('body').append('<div id="carouselShade"></div>'),
$('#carouselShade').css('opacity', 0.7).fadeIn();
return false;
});
Clicking a thumbnail now reveals a larger photograph centered in the browser window (Figure 2.8).
The function to close the modal window containing the photograph is the same function that was created in the section “Creating and Calling Modal Windows.”
Binding events to elements is an exciting tool for making your Web applications come to life. The ability to combine jQuery events, such as click
, hover
, fade
, and animate
, provides a wealth of opportunities to create highly interactive experiences for your Web-site visitors.
One of the most popular interactive opportunities to come along has its roots in old-school game design—using sprites.
Video games have been all the rage for the past 30 or so years, and anyone who has played early versions of games, such as Mario Brothers or Legend of Zelda, has played a game that used sprites as its basis for animation.
Simply put, a sprite is a graphic that describes multiple items, each item being at a specific location within the graphic. Each of the items in the sprite can be accessed by its location relative to a certain point in the sprite. Typically, the top-left corner (often described as 0, 0) of the sprite is the point used as the reference to each item’s relative location.
The CSS layout is extremely important to the success of sprite-based navigation. The style sheet rules hold all of the location information for the items contained in the sprite. Figure 2.9 shows the sprite used on the Photographer’s Exchange site. This sprite consists of six items divided into two rows of three items each. The rows and columns are only used to keep the items in the sprite organized; elements can be anywhere you want them to be in a sprite. This sprite will be used for popping up several of the site’s modal dialog windows.
The mainNav.jpg sprite (located in the chap2/grfx folder in the Web site’s code) is divided into two categories. The first category contains the items in their natural state with no hover. The second category (the second line of items) is the group that shows a user has hovered over them with a mouse cursor.
Determining the measurements of the sprite is critical. You’ll use this measurement information in the CSS to define the location of items. Obtain the width of each column (for instance, the Search column) and the height of each row. Figure 2.10 illustrates the measurements for the navigation sprite.
Note that the columns may have different widths; the height is consistent from row to row and must be for the animation effect to work properly.
In a sprite intended to be used as navigation on the side of the page (vertically), the column widths must be consistent from column to column but the heights may differ.
The HTML markup for the navigation is quite simple, consisting of an unordered HTML list in chap2/2-2.php. Each list item contains an anchor tag and a span tag:
<ul id="spriteNav">
<li><a href="search.php" rel="searchWindow" class="modal"
id="search"><span>Search</span></a></li>
<li><a href="register.php" rel="registerWindow" class="modal"
id="register"><span>Register</span></a></li>
<li><a href="login.php" rel="loginWindow" class="modal"
id="login"><span>Login</span></a></li>
</ul>
Although the markup is incredibly simple, the CSS is much more involved but not complicated. Each of the image’s states must be described in the style sheet. These states also include the location information for each image.
Let’s dig into the CSS (chap2/css/spritenav.css) now. First up in the style sheet is the basic housekeeping.
1. Define the height of the sprite in the spriteNav
rule:
#spriteNav {
height: 30px;
list-style: none;
margin: 0;
padding: 0;
}
2. Set each list item to float left so that each item will be side by side:
#spriteNav li {
float: left;
}
3. Define the background image for the list item anchor tags:
#spriteNav li a {
background: url(../grfx/mainNav.jpg) no-repeat;
display: block;
height: 30px;
position: relative;
}
4. Now define the background image for the span
tags nested in each list item anchor tag:
#spriteNav li a span {
background: url(../grfx/mainNav.jpg) no-repeat;
display: block;
position: absolute;
top: 0;
left: 0;
height: 30px;
width: 100%;
}
The sprite is set as the background image for both the anchor links and the spans. This is the basis for how the whole highlighting effect works as you fade from one sprite to the other:
Each column of items must have a width and a position. The position is defined with x and y coordinates. Because you are working with the first row of items, the y-axis will be 0 for each item. The x-axis for each item is defined as the total width of all of the items that precede the one the mouse cursor is currently hovering over.
Look at Figure 2.10 again. In the sprite, the Search item in the top row has starting coordinates of 0 for the x-axis and 0 for the y-axis. The Search is 100 pixels wide, so the Register item still has a 0 y-axis, but the x-axis is -100 pixels. The Register item is 115 pixels wide, so the x-axis value for the Login item is the width of the Search item plus the width of the Register item, -215 pixels.
1. Define each list element’s width
and background-position
:
#spriteNav li a#search {
width: 100px;
}
#spriteNav li a#register {
width: 110px;
background-position: -100px 0px;
}
#spriteNav li a#login {
width: 90px;
background-position: -215px 0px;
}
2. Now define each span element’s background-position
:
#spriteNav li a#search span {
background-position: 0px -30px;
}
#spriteNav li a#register span {
background-position: -100px -30px;
}
#spriteNav li a#login span {
background-position: -215px -30px;
}
Why use negative numbers? Imagine that each list element is a box and that the upper-left corner of that box is defined by the coordinates 0, 0. To get each item of the sprite to line up with the left edge of its list item, the sprite item must be offset to the left by the appropriate number of pixels.
For the sprite items in the second row, the sprite is not only offset to the left, it is offset upwards the necessary amount in a similar fashion.
Now that the CSS is properly defined, you can turn your attention to creating the jQuery that will animate the transformations of the sprite.
You could just use the HTML and CSS to create an immediate change from one sprite item to another, but what fun would that be? It’s time to add some jQuery to give a smooth animated effect to the sprite’s transitions.
1. Create the function and start by making sure that the spriteNav
spans are set to default states:
$(function() {
$("#spriteNav span").css("opacity", "0");
$("#spriteNav span").text(''),
Note that the span
element is made invisible by reducing its opacity to 0. The span
elements contain the sprite items that will be shown when the mouse cursor hovers over the span
.
2. Bind the span
elements to the jQuery hover
method and set up the mouseover and mouseout portions of the function:
$("#spriteNav span").hover(function() {
$(this).stop().animate({
opacity: 1
}, 100);
}, function(){
$(this).stop().animate({
opacity: 0
}, 500);
});
});
You’ve seen the hover effect before as part of the requirement for the carousel. The difference here is that the hover
method fades in the portion of the sprite that is described by #spriteNav span
. Under normal circumstances, the span is totally transparent, allowing you to see the sprite item described by #spriteNav li
. When the mouse cursor enters the span’s space, the opacity of the sprite element is animated to being fully visible. Figure 2.11 shows the hover effect, but I encourage you to load the code into a browser to get a full appreciation of the animation.
In Chapter 6, “Creating Application Interfaces,” I’ll show you how to create a more complicated interaction and animation with sprites.
This chapter was packed with action based on binding Web-page elements to events such as click or hover. Once bound to an event, jQuery can perform any number of methods based on those events, including animation or appending new elements to the DOM. You moved smoothly from using a single event to combining events and methods to create widgets like modal windows, the infinite image carousel, and interactive sprite-based navigation.
This chapter has given you a solid baseline for using and combining events, but there are many more events you will want to explore as well. Let’s take your jQuery development skills to the next level while exploring events you can use with forms.
44.200.94.150