📜 ⬆️ ⬇️

CSS Sprites 2: Javascript Time

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 Image

If 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.

Source: https://habr.com/ru/post/38693/


All Articles