Chapter 2
IN THIS CHAPTER
Figuring out events
Handling mouse clicks, key presses, and more
Showing, hiding, and fading elements
Moving elements around the page
Animating CSS properties
Today’s web animation can be built with the same tools we’ve always used to design and build the web: CSS and JavaScript. That is a huge amount of power and a vast arena in which to be creative.
— VAL HEAD
HTML, CSS, JavaScript, and jQuery are among the web development world’s most powerful tools, enabling you to create pages and entire sites that look great and work flawlessly (well, as close to flawlessly as the complexity of the web allows). But there’s a problem with most of the web pages built using these tools: The pages just kind of sit there. Once the page loads, its content and its structure are fixed, immutable. You can’t click anything, you can’t change anything, nothing moves or jiggles, spins or flips, fades in or fades out. Sure, the page doesn’t distract, but neither does it delight, and that’s a no-no in the modern web. Fortunately, you’ve come to the right place because this chapter shows you how to liven up even the most moribund page. Here you delve into two techniques for injecting some dynamism into dead pages: events and animation. These powerful tools not only give your page a dose of adrenaline, but they offer you endless possibilities for exploring and expressing your creativity.
When you buy a car, no matter how much you paid for it or how technologically advanced it is, the car just sits there unless you do something. (If you’re reading this in a future where all the cars are autonomous, my apologies.) That might be fine if it’s a good-looking car, but it’s much more likely you’ll want the car to do something, anything. Here’s a short list of actions you can take to achieve that goal:
The common denominator for all these actions is that they set up a situation to which the car must respond in some way: turning on, engaging the gears, moving, playing sounds. Looked at it from this angle, the car is a machine that responds to external stimuli, or, in a word, to events.
Somewhat surprisingly, a web page is also a machine that responds to external stimuli. I’ll describe what I mean.
In web development, an event is an action that occurs when a user interacts with a web page. Here are some examples:
How can your web page possibly know when any of these actions occur? The secret is that JavaScript was built with events in mind. As the computer science professors would say, JavaScript is an event-driven language.
So why don’t web pages respond to events automatically? Why do they just sit there? Because web pages are static by default, meaning that they ignore the events that are firing all around them. Your job as a web developer is to change that behavior by making your web pages “listen” for particular events to occur. You do that by setting up special chunks of code called event handlers that say, in effect, “Be a dear and watch out for event X to occur, will you? When it does, be so kind as to execute the code that I’ve placed here for you. Thanks so much.” An event handler consists of two parts:
I said earlier that events are baked into JavaScript, but in this book I’m not going to talk about vanilla JavaScript event handling. That’s because jQuery offers straightforward event-handling methods that are easier to use and more flexible that those offered by pure JavaScript, so it makes sense to learn about events the jQuery way.
There are dozens of possible events your web page can respond to, but lucky for you only a small subset of these events is needed in most day-to-day web development. I break these down into the following five categories:
document
object. The only event you need to worry about here is ready
, which fires when the document
object has completed loading.click
(the user clicks the mouse), dblclick
(the user double-clicks the mouse), and mouseover
(the user moves the mouse pointer over an element).keypress
, which is fired when the user presses a key.focus
(an element gains the focus, for example, when the user tabs to a form control), blur
(an element loses the focus), change
(the user changes the value of a form control), and submit
(the user submits the form). See Book 6, Chapters 2 and 3 to learn about forms and form events.scroll
, which fires when the user scrolls the window vertically or horizontally, and resize
, which fires when the user changes the window width or height.You configure your code to listen for and react to an event by setting up an event handler using jQuery's on()
method. Here’s the syntax:
$(selector).on(event, function() {
This code runs when the event fires
});
selector
: A jQuery selector that specifies the web page element or set to be monitored for the event. The event is said to be bound to the element or set.event
: A string specifying the name of the event you want the browser to listen for. For the main events I mention in the previous section, use one of the following, enclosed in quotation marks: ready
, click
, dblclick
, mouseover
, keypress
, focus
, blur
, change
, submit
, scroll
, or resize
.function()
: The callback function that jQuery executes when the event occurs.Here's an example:
HTML:
<div id="my-div"></div>
<button id="my-button">Click to add some text, above</button>
jQuery:
$('#my-button').on('click', function() {
$('#my-div').html('<h1>Hello Click World!</h1>');
});
The HTML sets up an empty div
element and a button
element. The jQuery code attaches a click
event listener to the button, and the callback function adds the HTML string <h1>Hello Click World!</h1>
to the div
. Figure 2-1 shows the resulting page after the button has been clicked.
jQuery also offers some shortcut methods for setting up event handlers. Here’s the syntax:
$(selector).event(function() {
This code runs when the event fires
});
selector
: A jQuery selector that specifies the web page element to be monitored for the event.event
: The name of event you want to handle. This defines a jQuery method as the event listener.function()
: The callback function that jQuery executes when the event occurs.For example, the ready
event fires when the document
object has finished loading, so here's some code that handles that event:
$(document).ready(function() {
$('body').prepend('<h1>Hello Event World!</h1>');
});
As another example, here’s a rewrite of the earlier code I used to demonstrate the on()
method:
HTML:
<div id="my-div"></div>
<button id="my-button">Click to add some text, above</button>
jQuery:
$('#my-button').click(function() {
$('#my-div').html('<h1>Hello Click World!</h1>');
});
As a third example, the following code uses the dblclick()
method to swap a div
element's text and background colors when the div
is double-clicked:
CSS:
div {
color: lemonchiffon;
background-color: darkgreen;
}
HTML:
<div id="my-div">
Double-click to switch the text and background colors.
</div>
jQuery:
$('#my-div').dblclick(function() {
if($('#my-div').css('color') === 'rgb(255, 250, 205)') {
$('#my-div').css('color', 'darkgreen');
$('#my-div').css('background-color', 'lemonchiffon');
} else {
$('#my-div').css('color', 'lemonchiffon');
$('#my-div').css('background-color', 'darkgreen');
}
});
In the dblclick
callback function, an if()
statement checks to see if the current color
value of the div
element equals rgb(255, 250, 205)
, which corresponds to the lemonchiffon
color keyword. If so, the text and background colors are swapped.
$('#my-button').on('click', function() {
$('#my-div').html('<h1>Hello Click World!</h1>');
$('#my-button').blur();
});
When an event fires, jQuery creates an Event
object, the properties of which contain info about the event, including the following:
target
: The web page element to which the event occurred. For example, if you set up a click
handler for a div
element, that div
is the target of the click.which
: A numeric code that specifies the key that was pressed during a keypress
event.pageX
: The distance (in pixels) that the mouse pointer was from the left edge of the browser's content area when the event fired.pageY
: The distance (in pixels) that the mouse pointer was from the top edge of the browser’s content area when the event fired.metaKey
: A Boolean value that equals true
if the user had the Windows key ( ) or the Mac Command key (⌘ ) held down when the event fired.shiftKey
: A Boolean value that equals true
if the user had the Shift key held down when the event fired.To access these properties, you insert a name for the Event
object as an argument in your event handler's callback function:
$(selector).on(event, function(e) {
This code runs when the event fires
});
e
: A name for the Event
object that jQuery generates when the event fires. You can use whatever name you want, but most coders use e
(although evt
and event
are also common).For example, when handling the keypress
event, you need access to the which
property to find out the code for the key the user pressed. Here's an example page that can help you determine which code value to look for:
HTML:
<div>
Type a key:
</div>
<input id="key-input" type="text">
<div>
Here's the code of the key you pressed:
</div>
<div id="key-output">
</div>
jQuery:
$('#key-input').keypress(function(e) {
$('#key-output').text(e.which);
});
The HTML sets up an <input>
tag to accept a keystroke, and a <div>
tag with id="key-output"
to use for the output. The jQuery code adds a keypress
event listener to the input
element, and when the event fires, the callback function writes e.which
to the output div
. Figure 2-2 shows the page in action.
For these and many similar situations, you can tell the web browser not to perform an event’s default action by running the Event
object’s preventDefault()
method:
event.preventDefault();
event
: A reference to the Event
object that jQuery creates when an event firesFor example, take a peek at the following code:
HTML:
<a href="http://wiley.com/">Wiley</a>
<a href="http://wordspy.com/">Word Spy</a>
<a href="http://webcodingplayground.io/">Web Coding Playground</a>
<div id="output">
Link URL:
<div>
jQuery:
$('a').click(function(e) {
e.preventDefault();
strURL = e.target.href
$('#output').text('Link URL: ' + strURL);
});
The HTML defines three links (styled as inline blocks, which I haven't shown here) and a div
element. The jQuery sets up a click
event listener for all the a
elements, and the callback function does three things:
e.preventDefault()
method to tell the browser not to navigate to the link address.e.target.href
to get the URL of the link.div
element. Figure 2-3 shows an example.HTML:
<button id="add-div-button">
Click to add the div
</button>
jQuery:
// Build the div element as a string and then prepend it
$('#add-div-button').click(function() {
var strDiv = '<div id="my-div">';
strDiv += 'Double-click to switch the text and background colors.';
strDiv += '</div>'
$('body').prepend(strDiv);
});
// Set up the div with a double-click event handler
$('#my-div').on('dblclick', function() {
if($('#my-div').css('color') === 'rgb(255, 250, 205)') {
$('#my-div').css('color', 'darkgreen');
$('#my-div').css('background-color', 'lemonchiffon');
} else {
$('#my-div').css('color', 'lemonchiffon');
$('#my-div').css('background-color', 'darkgreen');
}
});
When you click the button, the first jQuery event handler builds a div
element as a string and then uses prepend
to add it to the body
element. That div
element uses the id
value my-div
. However, the second jQuery event handler is for a dblclick
event on that same my-div
element. Theoretically, the dblclick
handler switches the element's text and background colors, but if you try this example, you can double-click the div
until your finger falls off and nothing will happen.
Why doesn’t the event handler handle anything? Because when the browser was loading the page and came upon the code for the dblclick
event handler, the target — that is, the div
with the id
value my-div
— didn't yet exist, so the browser ignored that event handler.
To fix this problem, you use a jQuery technique called event delegation, which means you do two things:
on()
method that specifies which element your click handler actually applies to.Here’s the new syntax for the on()
method:
$(ancestor).on(event, descendant, function() {
This code runs when the event fires
});
ancestor
: A selector that specifies the ancestor element that is delegated to be monitored for the eventevent
: A string specifying the name of event you want the browser to listen fordescendant
: A selector that specifies the descendant element of ancestor
that's the actual target of the eventfunction()
: The callback function that jQuery executes when the event occursThis version of the on()
method delegates the event handler to the ancestor
element. When the event fires, the ancestor
element looks through its descendants until it finds the element or set given by descendant
, and it then runs the handler with that element or set as the event target.
To fix the previous example, you could use the document
object as the ancestor
argument, and add #my-div
as the descendant
argument:
$(document).on('dblclick', '#my-div', function() {
Most of the time you'll want to leave an event handler on the job full-time so it’s always available for your page visitors. However, sometimes you only want an event handler available part-time. For example, if clicking a button loads some HTML and text that you want to leave on the page, then it’s best to remove both the button and its event handler to avoid confusing the user.
To remove an event handler, run jQuery’s off()
method:
$(selector).off(event);
selector
: A jQuery selector that specifies the web page element or set from which you want the event removedevent
: A string specifying the name of the event you want to removeHere's an example that removes the click
event from the element with the id
value my-button
:
$('#my-button').off('click');
When you attend a speech or talk, nothing will put you to sleep faster — or, if you remain awake, make you want to head for the exit quicker — than listening to someone speak in a flat, affectless, monotone. The best orators use intonation, gestures, and the dramatic pause for effect to keep listeners not only in, but on the edge of, their seats.
Web pages, too, can appear flat and lifeless. Even if you've applied lots of color and top-notch typography, that’s like dressing up a deadly dull speaker in a flattering dress or sharp suit: The deadly dullness remains. Web page liveliness comes not only from an attractive appearance, but also from the judicious use of animation, the digital equivalent of voice modulation and hand gestures.
That might sound like a lot of extra effort to put in for a bit of eye candy, but interface animations aren’t just for show: When used properly they help the reader navigate and use your site, keep the reader engaged, and provide delight. But what about the work involved? Forget about it: jQuery offers a few ready-made tools that enable you to add sophisticated animation effects with just a few lines of code.
One of the most common web page effects is hiding something and then showing it when the user clicks a heading, a button, or some other page element. These effects are used for drop-down menus, navigation bars, image captions, question-and-answer sections (where clicking the question shows and hides the answer), and many other scenarios.
To hide an element, use jQuery’s hide()
method:
$(selector).hide();
selector
: A jQuery selector that specifies the web page element or set you want to hideFor example, the following statement hides the web page's header
element:
$('header').hide();
To show a hidden element, use jQuery’s show()
method:
$(selector).show();
selector
: A jQuery selector that specifies the hidden web page element or set you want to showFor example, the following statement shows the web page's header
element:
$('header').show();
Finally, you can toggle an element between shown and hidden by using jQuery’s toggle()
method:
$(selector).toggle();
selector
: A jQuery selector that specifies the hidden web page element or set you want to toggle between shown and hiddenFor example, the following statement toggles the web page's header
element:
$('header').toggle();
The hide()
, show()
, and toggle()
methods that I cover in the previous section change the display of the element immediately. If the suddenness of these effects seems a bit harsh to you, then you might prefer the jQuery animations that fade an element out or in.
To fade an element out, use jQuery's fadeOut()
method:
$(selector).fadeOut();
selector
: A jQuery selector that specifies the web page element or set you want to fade outFor example, the following statement fades out the web page's aside
element:
$('aside').fadeOut();
To fade an element in, use jQuery’s fadeIn()
method:
$(selector).fadeIn();
selector
: A jQuery selector that specifies the web page element or set you want to fade inFor example, the following statement fades in the web page's aside
element:
$('aside').fadeIn();
And, yes, you can toggle the fading by running jQuery’s fadeToggle()
method:
$(selector).fadeToggle();
selector
: A jQuery selector that specifies the web page element or set you want to toggle between fading in and fading outFor example, the following statement toggles fading for the web page's aside
element:
$('aside').fadeToggle();
As an alternative to the fade animations that I cover in the previous section, you can also make an element show or hide itself gradually by sliding into or out of its position on the page.
To hide an element by sliding it up from its bottom edge until it disappears, use jQuery’s slideUp()
method:
$(selector).slideUp();
selector
: A jQuery selector that specifies the web page element or set you want to slide upFor example, the following statement slides up the web page's nav
element:
$('nav').slideUp();
To show an element by sliding it down from its top edge, use jQuery’s slideDown()
method:
$(selector).slideDown();
selector
: A jQuery selector that specifies the web page element or set you want to slide downFor example, the following statement slides down the web page's nav
element:
$('nav').slideDown();
I know, you’re way ahead of me: You can toggle the slide effect by running jQuery’s slideToggle()
method:
$(selector).slideToggle();
selector
: A jQuery selector that specifies the web page element or set you want to toggle between sliding up and sliding downFor example, the following statement toggles sliding for the web page's nav
element:
$('nav').slideToggle();
When you use any of jQuery’s animation methods — hide()
, show()
, toggle()
, fadeOut()
, fadeIn()
, fadeToggle()
, slideUp()
, slideDown()
, or slideToggle()
— without parameters, jQuery runs the animation using its default settings:
swing
.You have quite a bit of control over the duration, and a bit of control over the pace, by using jQuery’s animations with the addition of two parameters that set the duration and the easing function:
$(selector).animation(duration, easing);
selector
: A jQuery selector that specifies the web page element or set you want to work with.animation
: The name of the animation method you want to run.duration
: The length of the animation, in milliseconds. You can also use the keywords slow
(equivalent to 600ms) or fast
(equivalent to 200ms).easing
: A string that specifies the easing function you want to use for the animation. The default is swing
, but you can also specify linear
to have the animation run at a constant pace.For example, the following statement toggles the nav
element between hidden and shown, where the animation takes one second and uses the linear
easing function.
$('nav').toggle(1000, 'linear');
A common web design pattern is the accordion, a menu or list of items, each of which contains extra content that is hidden by default. When you click an item in the accordion, that item's hidden content is displayed. Click the item again, and the content returns to being hidden. An accordion is useful when you have a long series or list of items, and to display everything at once would be overwhelming for the reader. Instead, you can display just the headings, menu commands, or similar top-level items, and you can hide the rest of the content associated with each item, thus making the list or menu easier to read and navigate.
Take a look at an example. First, here’s some CSS and HTML code to mull over:
CSS:
.sentence {
display: none;
}
HTML:
<header>
<h1>Some Food Words to Chew On</h1>
</header>
<main>
<p>
Click a word or its definition to see that term's sample sentence.
</p>
<section id="alamode" class="word">
<b>à la mode</b> (al·uh·MODE, adjective). Describes a dish that's served with ice cream.
<p class="sentence">
Give her a big spoon and a piece of apple pie <b>à la mode</b> the size of her head, and Moira had her own little slice of heaven.
</p>
</section>
<section id="appetizer" class="word">
<b>appetizer</b> (AP·uh·tye·zur, noun). Food or drink that's served before the main meal and is meant to stimulate the appetite.
<p class="sentence">
A slow eater, Karen was only halfway through her salad <b>appetizer</b> when the waiter showed up with the main course.
</p>
</section>
<section id="comestible" class="word">
<b>comestible</b> (kuh·MES·tuh·bul, noun). An item that can be eaten as food.
<p class="sentence">
After picking up bread, meat, cheese, and a few other <b>comestibles</b>, Deirdre was ready for the weekend-long Three Stooges festival.
</p>
</section>
<section id="cuisine" class="word">
<b>cuisine</b> (kwi·ZEEN, noun). A style of cooking as well as the food cooked in that style.
<p class="sentence">
His local restaurant was supposed to specialize in French <b>cuisine</b>, so Sean wondered why they didn't serve french fries.
</p>
</section>
<section id="epicure" class="word">
<b>epicure</b> (EP·uh·kyoor, noun). A person with sophisticated tastes, especially when it comes to food and wine.
<p class="sentence">
Being able to tell beef stroganoff from beef Wellington and a Bordeaux from a Beaujolais convinced Dominic that he was quite the <b>epicure</b>.
</p>
</section>
<section id="ingest" class="word">
<b>ingest</b> (in·JEST, verb). To take food into the body.
<p class="sentence">
Not at all hungry, but also unwilling to displease his wife, Mr. Tortellini <b>ingested</b> her spaghetti with grim determination.
</p>
</section>
<section id="nosh" class="word">
<b>nosh</b> (nawsh, verb). To eat a light meal or a snack.
<p class="sentence">
Wanda would guiltily <b>nosh</b> on a pepperoni stick before going in to her vegetarian cooking class.
</p>
</section>
</main>
The HTML consists mostly of a series of <section>
tags, each of which contains a word, its pronunciation, its definition, and a <p>
tag that contains a sample sentence that uses the word. Each of these <p>
tags is given the class named sentence
, and in the CSS code, you can see that the sentence
class is hidden by default by styling it with the declaration display: none
. Figure 2-4 shows the initial state of the page.
The goal here is to display a word's sample sentence when the reader clicks the word (or its pronunciation or definition). One way to do this would be to set up a click
event handler on each word and then have that handler’s callback function use a method such as slideToggle()
or fadeToggle()
to show and hide the sample sentence. That would do the job, but it requires a lot of work. Sure, it's not bad with the seven items in my list, but what if there were 70 items, or 700?
Instead, I’m going to take advantage of three timesaving features of my HTML code:
<section>
tag uses the class named word
, so I can set up a single click event handler that is bound to that class name.<section>
tag also uses a unique id
value that is based on its word. I can use that id
value to know which term was clicked.<p>
tag is a direct child of its parent <section>
tag, which lets me target the <p>
tag using the child selector.Given all this, the jQuery code required to show and hide the sample sentences is remarkably compact:
$('.word').click(function(e) {
var wordID = e.target.id;
$('#' + wordID + ' > p').slideToggle('slow');
});
Three things are going on here:
click
event method is bound to the class named word
, so it fires any time the reader clicks a <section>
tag's content.<section>
tag was clicked, the code gets the value of e.target.id
, which returns the id
value of the clicked section
element. That id
value is stored in the wordID
variable.#
to wordID
, and then adds the child selector for the p
element: > p
. With the section
element's sample sentence selected, the code runs the slideToggle()
animation to slide the sample sentence in and out of view.Figure 2-5 shows the page with one of the sample sentences displayed.
One of the most interesting and exciting jQuery methods is animate()
, which enables you to apply an animation to any CSS property that accepts a numeric value: font-size
, padding
, border-width
, opacity
, and many more. Here's the syntax to use:
$(selector).animate(properties, duration, easing);
selector
: A jQuery selector that specifies the web page element or set you want to work with.properties
: An object literal that specifies the CSS property-value pairs that you want to animate.duration
: An optional length of the animation, in milliseconds. You can also use the keywords slow
(equivalent to 600ms) or fast
(equivalent to 200ms). The default is 400ms.easing
: An optional string that specifies the easing function you want to use for the animation. The default is swing
, but you can also specify linear
to have the animation run at a constant pace.The properties
parameter requires a bit more elaboration. It requires an object literal, which is a collection of property-value pairs, separated by commas and surrounded by braces. Here's the general form:
{
property1: value1,
property2: value2,
etc.
propertyN: valueN
}
Each property is a CSS property name, which needs to be enclosed in quotation marks if it contains a hyphen (-). Each value is a number, followed by a measurement unit, if needed. (Some CSS properties, such as opacity
and line-spacing
, take unitless numeric values.) If the value has a measurement unit, surround the number and unit with quotation marks. For example, here's the object literal to use if you want your animation to change the left position to 425px
, the font size to 1rem
, and the opacity to 1
:
{
left: '425px',
'font-size': '1rem',
opacity: 1
}
You then insert the object literal into the animate()
method as the properties
parameter:
$('aside').animate(
{
left: '425px',
'font-size': '1rem',
opacity: 1
},
1500,
'linear'
);
This example animates the page's aside
element with a duration of 1.5 seconds and linear easing. Notice that I arranged the animate()
arguments vertically for easier reading.
aside {
position: absolute;
left: -20rem;
font-size: .1rem;
opacity: 0;
}
Given this initial rule, you can see that the animation does three things:
425px
from the left edge of the content area.1rem
to 1rem
0
(transparent) to 1
(fully visible)Most of the time you'll want your jQuery animations to run their course without further ado. However, there might be times when some further ado is exactly what you want. For example, at the completion of an animation, you might want to adjust the text on a button (for example, from “Hide the nav bar” to “Show the nav bar”) or you might want to run another animation (a technique known as animation chaining).
You can perform these and similar post-animation tasks by adding a callback function to the animation method. First, here’s the syntax to use for one of jQuery’s built-in animation effects:
$(selector).animation(function() {
Code to run when the animation is done
});
selector
: A jQuery selector that specifies the web page element or set you want to work with.animation
: The name of the animation method you want to run.function()
: The callback function. jQuery executes the code inside this function after the animation ends.Here's an example:
HTML:
<nav>
<a href="#">Home</a>
<a href="#">What's New</a>
<a href="#">What's Old</a>
<a href="#">What's What</a>
</nav>
<main>
<button id="slide-nav">Hide the nav bar</button>
</main>
jQuery:
$('#slide-nav').click(function() {
$('nav').slideToggle(function() {
// Get the current button text
var btnText = $('#slide-nav').text();
// Check the first four letters of the button text
// and then change the button text accordingly
if (btnText.substr(0, 4) === 'Hide') {
$('#slide-nav').text('Show the nav bar');
} else {
$('#slide-nav').text('Hide the nav bar');
}
});
});
The HTML defines a button
element that, when clicked, hides and shows the nav
element. The jQuery code sets up a click
event handler for the button, and that handler's callback function runs the slideToggle()
animation on the nav
element. The slideToggle()
animation also includes a callback function that gets the button text, checks to see if the first four characters are Hide
, and then changes the button text according to the result.
$(selector).animation(duration, easing, function() {
Code to run when the animation is done
});
For the animate()
method, you can also include a callback function by using the following syntax:
$(selector).animate(properties, duration, easing, function() {
Code to run when the animation is done
});
Here’s an example that runs a second animate()
method after the first one is complete:
$('#animate-aside').click(function() {
$('aside').animate(
{
left: '425px'
},
500,
'linear',
function() {
$('aside > p').animate(
{
opacity: 1
},
2000
); // End of the second animate() method
} // End of the first animate() method's callback function
); // End of the first animate() method
}); // End of the click() method
3.149.26.176