The feeling of dynamics was often what distinguished rich Flash sites from sites based on html standards. Until recently, flash interfaces always seemed more alive, they interacted with the user dynamically, and this is the functionality that other sites could not just take and copy.
Of course, later the state of affairs changed - effects for dynamic interfaces appeared, supported by such JS libraries as
Prototype ,
Scriptaculous ,
Moo ,
YUI ,
MochiKit (and this list can be continued). Now is the time (in 4 years) to remember the
CSS Sprites technique and see if we can add “a little dynamics” to it.
Meet jQuery
Here we are faced with the first condition: we need to use
jQuery for everything to work out. jQuery is a well-designed JS-library that provides us with the same necessary functionality as other libraries, but has, in addition, an additional advantage, which allows us to simplify the expansion of CSS Sprites: we can use the same constructions for selecting page elements used in CSS.
It should be noted that this library requires downloading a few extra kilobytes of scripts. Of course, external JS libraries are cached and loaded only once - when a site visitor opens the page for the first time. The most compact version of jQuery weighs 15 kb. This is an inevitable increase in page size, and it can be a problem. If you already use jQuery for other purposes, then everything is fine. But if you are interested in adding only this technique, then count the size of the loaded page and decide for yourself whether the effect is worth it. (Since
jQuery is hosted by Google , you can link to the version of the library used, as we have in the examples, and hope that most browsers on your site have already cached the library's URL) (Per:
In my opinion, the author there is a little exaggerating the problem: jQuery is one of the smallest JS-libraries and 15 extra kilobytes for the dynamics when first loaded - it is not a bad thing )
')
What about other JS libraries? Absolutely nothing prevents you from using them. View this article as an open invitation to port this technique to the library that you use.
HTML and CSS
The first thing we want to do is to create the basis of the navigation menu for site visitors with disabled JavaScript.
We already have a CSS-based method for the rollover effect (i.e. hover effect), so let's start creating our site navigation using CSS Sprites. And, since we are lazy, in the future we will not create everything a second time, but simply take these developments, just adding jQuery on top.
CSS Sprites ImageIf you have any questions about the CSS Sprites technique, you can take a look at the
original article , but there are a few points that are worth explaining below. Let's start with HTML. Pay special attention to this structure, we will often refer to it in the future:
<ul class = 'nav current-about'>
<li class = 'home'> <a href='#'> Home </a> </ li>
<li class = 'about'> <a href='#'> About </a> </ li>
<li class = 'services'> <a href='#'> Services </a> </ li>
<li class = 'contact'> <a href='#'> Contact </a> </ li>
</ ul>
Each class serves a specific purpose: the
nav
tag
ul
allows you to point to this element using CSS (and later Javascript), while the second
current-about
class is used to highlight the page being viewed or the section of the site. Each
li
element has its own unique class, which is also used to point to this tag in CSS or JS.
So, our navigation markup is a simple and accessible HTML list, and we have enough classes to make Sprites work:
.nav {
width: 401px;
height: 48px;
background: url(../i/blue-nav.gif) no-repeat;
position: absolute;
top: 100px;
left: 100px;
}
We set the
position
property to
absolute
to change the reference point for positional shifts of
li
tags. We could also use the value of
relative
to achieve the same effect and, at the same time, leaving the
.nav
element in the normal flow. There are some reasons to use the value
relative
, but in this article we will use the value
absolute
. More information on this subject can be found in the
article by Douglas Bowman .
The basis of the Sprites technique itself in our case is the use of background-images for each navigation element and their absolute positioning within the parent
ul
tag:
.nav li a:link, .nav li a:visited {
position: absolute;
top: 0;
height: 48px;
text-indent: -9000px;
overflow: hidden;
}
.nav .home a:link, .nav .home a:visited {
left: 23px;
width: 76px;
}
.nav .home a:hover, .nav .home a:focus {
background: url(../i/blue-nav.gif) no-repeat -23px -49px;
}
.nav .home a:active {
background: url(../i/blue-nav.gif) no-repeat -23px -98px;
}
We are going to move a little further than in the original article, and define the
focus
and
active
states. The first state is a small addition to the image selector, when the link is subject to a
hover
or
focus
state, the
active
state adds a new property — when you click on an element. They are optional, but it is a good idea to define styles for both states. The “
overflow: hidden
” rule is also new in our styles; it serves to prevent the appearance of a visual bug in some browsers.
Example 1 : Customizing CSS Sprites for a menu.
So, we’ve come to the starting point - we now have a working navigation menu based on the CSS Sprites technique, with the ability to select the active element. Let's develop our idea further.
Initial jQuery setup
Note that all the code written below will be located inside this jQuery function, it guarantees that the code will run only once and only after the entire page has been completely loaded. All the pieces of code below assume that they run inside this function, so if you encounter errors, do not forget to check the location of the code:
$(document).ready(function(){
//
});
Since the sprite menu is our “default menu” for disabled Javascript (if we did everything right), we’d better get rid of all the background images in the styles for the hover elements, so we will create new background images using the script:
$(".nav").children("li").each(function() {
$(this).children("a").css({backgroundImage:"none"});
});
The first line requests the element (s) of the class
nav
and then applies the function to each child element
li
that they contain. This function is shown in the second line of the code; it interrogates the
this
object (
this
means the
li
tags found) for the presence of child tags a inside it. If there are such, then the CSS
background-image
property of these elements is set to
none
.
Example 2 : Disabling styles when hovering using jQuery.
It works ... but we also lost the selection of the selected menu item in the process. Therefore, we need to check the name of our
current-( )
class for the parent
ul
tag to save the background image for the selected item. The previous code needs to be expanded a little:
$(".nav").children("li").each(function() {
var current = "nav current-" + ($(this).attr("class"));
var parentClass = $(".nav").attr("class");
if (parentClass != current) {
$(this).children("a").css({backgroundImage:"none"});
}
});
(Per.:
The next paragraph explains in detail what the above code does. I found this redundant - this is obvious even to those who are not familiar with jQuery. :) )
Event binding
Now we need to bind the function to each of the
li
elements for each interaction event to which the styles are applied. Let's create a function for this and call it
attachNavEvents
:
function attachNavEvents(parent, myClass) {
$(parent + " ." + myClass).mouseover(function() {
// -
}).mouseout(function() {
// -
}).mousedown(function() {
// -
}).mouseup(function() {
// -
});
}
This function takes 2 arguments. The first argument is a string containing the class name of the parent element. The second argument is a string containing the name of the class name of the
li
tag to which events are bound. We combined both arguments in the next line of the function to create a selector similar to that used in CSS, such as
.nav .home
.
Since jQuery allows you to bind several functions at once to a single object, we were able to create all the functions for handling events at once (in one chain). The function chain is a unique jQuery concept. Do not bother about her - not so important as it works. Therefore, if you are in a bit of confusion, just take on faith what we are doing now.
Now we will tie these functions to each item in our menu. For now, we will not do this in the best way (but later we will optimize it), and simply run the function we have created for each
li
tag. As arguments, we pass the parent element for each menu item, as well as our own class name for the
li
tag:
attachNavEvents(".nav", "home");
attachNavEvents(".nav", "about");
attachNavEvents(".nav", "services");
attachNavEvents(".nav", "contact");
So far we have done almost nothing, but we have everything ahead.
Example 3 : Initial script configuration for events.
Theory
I'm going to explain what we will do next. This is important to understand, because you will need to create styles for the elements with which we will work.
For each of the links, we will create a new
div
tag inside the
li
tag. We will use this new tag for jQuery effects. The background image for the
div
tag will be the same as what we used earlier for the a tag (and it also depends on the parent
li
tag). We are absolutely positioning the
div
tag (it will be positioned relative to the
.nav
element). Thus, we almost completely copied the existing a tag from our initial CSS Sprites construct. Through trial and error, I found out that creating a new
div
tag makes it less difficult to create dynamic effects on jQuery than if we manage only existing tags, so this is a necessary step.
Styles for the
div
tag must be pre-written in CSS. We will create a new unique class for a
div
(for example,
.nav-home
), depending on the name of the parent class
li
, and add styles to it:
.nav-home {
position: absolute;
top: 0;
left: 23px;
width: 76px;
height: 48px;
background: url(../i/blue-nav.gif) no-repeat -23px -49px;
}
Practice
It's time to add effects. When the mouseover event fires, we create a
div
element with the appropriate class name. We need this tag to be invisible before it appears, so we use the jQuery css function to set its
display: none
property. Finally, we use the
fadeIn
jQuery function to
fadeIn
in a
div
and pass it the value 200 as an argument to determine the duration of the animation in milliseconds:
function attachNavEvents(parent, myClass) {
$(parent + " ." + myClass).mouseover(function() {
$(this).before('<div class="nav-' + myClass + '"></div>');
$("div.nav-" + myClass).css({display:"none"}).fadeIn(200);
});
}
Then we do the same, just the opposite, for a mouseout event — our
div
should fade out. After it disappears, we remove the
div
from the DOM. Here’s how our
attachNavEvents
function should work:
function attachNavEvents(parent, myClass) {
$(parent + " ." + myClass).mouseover(function() {
$(this).before('<div class="nav-' + myClass + '"></div>');
$("div.nav-" + myClass).css({display:"none"}).fadeIn(200);
}).mouseout(function() {
// -
$("div.nav-" + myClass).fadeOut(200, function() {
$(this).remove();
});
});
}
And this is enough for hover effects.
Example 4 : Adding effects on hover.
We should think about handling the mousedown and mouseup events, since we have specified the
active
state for the links in the styles. Create another class so that we can only refer to it in CSS and change the name of the class when the mousedown event occurs. When a mouseup event occurs, the former class name for the
div
tag will be returned. Here is how the
attachNavEvents
function will look like after these changes:
function attachNavEvents(parent, myClass) {
$(parent + " ." + myClass).mouseover(function() {
$(this).before('<div class="nav-' + myClass + '"></div>');
$("div.nav-" + myClass).css({display:"none"}).fadeIn(200);
}).mouseout(function() {
$("div.nav-" + myClass).fadeOut(200, function() {
$(this).remove();
});
}).mousedown(function() {
$("div.nav-" + myClass).attr("class", "nav-" + myClass + "-click");
}).mouseup(function() {
$("div.nav-" + myClass + "-click").attr("class", "nav-" + myClass);
});
}
We can reuse styles when hovering on a
div
tag, just by slightly changing the position of the background sprite image to create styles when clicked:
.nav-home, .nav-home-click {
position: absolute;
top: 0;
left: 23px;
width: 76px;
height: 48px;
background: url(../i/blue-nav.gif) no-repeat -23px -49px;
}
.nav-home-click {
background: url(../i/blue-nav.gif) no-repeat -23px -98px;
}
Now we have hover effects, we see the selected navigation item, and the effects on click also work.
Example 5 : Putting it all together.
Other reflections
We are not limited to the fade effect. jQuery has built-in functions “slideUp / slideDown”, which can also be used (the
second example in the article ). Or we can even show imagination and use our own animation effects based on styles and using the jQuery-function animate (the
third example ). Immediately warn about the function animate - the animation may not be very smooth, as you might have noticed in our example.
Cross-browser compatibility is like a kind of small gift for you, jQuery works great in all modern browsers, and everything you see here works in IE6, IE7, FF2, FF3, Safari, Opera, etc. We even provided many graceful ways to circumvent the limitations of the functional. So, if Javascript is disabled on the site visitor, he will see the dynamics implemented using CSS Sprites. (Trans .:
It does not work in IE6 ) If CSS and JS are disabled, the visitor will see a simple
ul
list. We get other advantages of CSS Sprites besides this, since we can use one image for various navigation states and effects.
Although it is not necessary, it is still recommended to take into account that the speed of animation more than a few hundred milliseconds may be pleasant at first, and then begin to get on your nerves to visitors of your site after the effect of the site’s novelty for them disappears. So prefer faster animation.
Another small problem that you may encounter is when the text on the site begins to "blink" during the animation. This complex phenomenon is associated with the
sub-pixel rendering inherent in modern operating systems. The best solution to this problem is to set an almost opaque opacity value so that the text is rendered in a special way. If you add this line to your styles, the “blinking of the text” should stop, only the text will be smoothed out in the usual way, and not with the help of sub-pixels:
p {
opacity 0.9999;
}
Feature Pack for Sprites2
There is no need to memorize any code in this article, since we have prepared the
function used in our final example. Using the JavaScript code in the HTML file, as an aid, you need to change only one line in the code to apply Sprites2 on your website:
$(document).ready(function(){
generateSprites(".nav", "current-", true, 150, "slide");
});
The
generateSprites
function takes 5 arguments:
1. The class name of the parent
ul
, including the period.
2. The prefix used for selected items (for example, for the selected selected class, use "
selected-
" as the prefix value).
3. A switch that indicates whether styles are used for the
active
state. If you define the state: active and its equivalents in jQuery in your style sheet, set to
true
. Otherwise, set it to
false
.
4. Speed ​​of animation, in milliseconds (300 = 0.3 seconds).
5. Type of animation, string variable. Set the “slide” or “fade”, the latter is the default.
Example 6 : Just one simple line of code to change thanks to our function.
You will still need to position and apply styles to the various elements in your CSS, so feel free to use the examples of our style files in this article as a hint.
Notes
At the time of this writing, a
similar technique has spread on the Internet, albeit without additional support for CSS Sprites. We also found a completely different
animated jQuery menu , which you may find useful.