Five Useful Interactive CSS/jQuery Techniques Deconstructed

Advertisement

With the wide variety of CSS3 and JavaScript techniques available today, it’s easier than ever to create unique interactive websites that delight visitors and provide a more engaging user experience.

In this article, we’ll walk through five interactive techniques that you can start using right now. We’ll cover:

  1. Animated text effects1,
  2. Animated images2 without GIFs,
  3. More engaging drop-down menus3,
  4. Fancier slideshow navigation4,
  5. Animated icons5 for the hover state of buttons.

Besides learning how to accomplish these specific tasks, you’ll also master a variety of useful CSS and jQuery tricks that you can leverage when creating your own interactive techniques. The solutions presented here are certainly not perfect, so any thoughts, ideas and suggestions on how you would solve these design problems would be very appreciated.

So, let’s dive in and start building more exciting websites!

1. Extruded Text Effect

Extruded text effect on David DeSandro's site6

The footer of David DeSandro’s website7 uses extruded text that animates on mouseover. This interactive text effect is a quick and impressive way to add some flare to your website. With only a few lines of CSS3, we can make the text appear to pop out of the page in three dimensions.

First let’s set up some text (the code is copied from the original site):

<span class="extruded">Extrude Me</span>

And some basic styling (the code is copied from the original site):

body {
    background-color: #444;
    text-align: center;
}

.extruded {
    color: #888;
    font-family: proxima-nova-1, proxima-nova-2, 'Helvetica Neue', Arial, sans-serif;
    font-size: 48px;
    font-weight: bold;
    text-shadow: #000 3px 3px;
}

Here, we’ve applied some basic styles and added a text-shadow. But this text-shadow doesn’t look three-dimensional; to accomplish the extruded effect, we’ll need to add more text-shadows:

text-shadow: #000 1px 1px, #000 2px 2px, #000 3px 3px;

This will add three different text-shadows to our text, stacked on top of each other to create the three dimensional appearance we want.

Styling the Hover State

Next, let’s add a hover state with a bigger text-shadow:

.extruded:hover {
    color: #FFF;
    text-shadow: #58E 1px 1px, #58E 2px 2px, #58E 3px 3px, #58E 4px 4px, #58E 5px 5px, #58E 6px 6px;
}

Here, we’ve added three more text-shadows to increase the depth of the extrude effect. But this effect alone is too flat; we want the text to look like it’s popping off the page. So, let’s reposition the text to make it appear to grow taller from the base of the extruded section:

.extruded {
    position: relative;
}

.extruded:hover {
    color: #FFF;
    text-shadow: #58E 1px 1px, #58E 2px 2px, #58E 3px 3px, #58E 4px 4px, #58E 5px 5px, #58E 6px 6px;
    left: -6px;
    top: -6px;
}

Now in the hover state, the extruded text moves up the same distance as our max text-shadow value. We also added position: relative, which must be attached to the base state, not just the hover state, or else it will cause problems when we animate it.

Animating the Transition

Next, we can add a CSS3 transition189 to our text to animate the color change and extrude effect:

.extruded {
     -moz-transition: all 0.3s ease-out; /* FF3.7+ */
       -o-transition: all 0.3s ease-out; /* Opera 10.5 */
  -webkit-transition: all 0.3s ease-out; /* Saf3.2+, Chrome */
          transition: all 0.3s ease-out;
}

This triggers a smooth animation for our different CSS changes on hover. While it doesn’t work in all browsers, it does degrade nicely to the basic hover effect.

Bringing it all together:

body {
    background-color: #444;
    text-align: center;
}

.extruded {
    color: #888;
    font-family: proxima-nova-1, proxima-nova-2, 'Helvetica Neue', Arial, sans-serif; /* the original site doesn't use the @font-face attribute */
    font-size: 48px;
    font-weight: bold;
    text-shadow: #000 1px 1px, #000 2px 2px, #000 3px 3px;
    position: relative;
    -moz-transition: all 0.3s ease-out; /* FF3.7+ */
       -o-transition: all 0.3s ease-out; /* Opera 10.5 */
  -webkit-transition: all 0.3s ease-out; /* Saf3.2+, Chrome */
          transition: all 0.3s ease-out;
}

.extruded:hover {
    color: #FFF;
    text-shadow: #58E 1px 1px, #58E 2px 2px, #58E 3px 3px, #58E 4px 4px, #58E 5px 5px, #58E 6px 6px;
    left: -6px;
    top: -6px;
}

Shortcomings

While applying several CSS3 text-shadows works well when the text is static, it falls a bit short when used alongside the transition animation.

In short, the biggest text-shadow animates just fine, but the other text-shadows aren’t applied until the animation completes. This causes a quick correction: the browser stutters with a basic drop-shadow before filling in the rest diagonally.

Fortunately, we can make this drawback relatively unnoticeable, provided that we follow a few style guidelines. Basically, we want to hide the bulk of the extruded portion with the top text. This means that we should generally use this effect with bolder fonts, such as the Proxima Nova family used by David DeSandro. Also, we should be careful to avoid text-shadows that are too big for the font. Tweak your settings with this in mind until the animated extrude looks believable.

Finally, this technique will not work in IE, because text-shadow is unsupported in all versions of IE (even IE9).

2. Animating A Background Image

Animated monster image from Love Nonsense12

While we can easily animate text with a few lines of code, animating an image usually requires bigger and slower assets, such as animated GIFs13 or Flash or HTML5 video. While complex animations will still depend on these technologies, we can create a compelling illusion of animation using CSS alone.

Love Nonsense14 uses a hover effect to alter the color of the images on the website. The trick here is to use a transparent PNG with a background color. The color of the PNG should match the website’s background, so that all of the transparent areas in the PNG show up when filled with a background color. Thus, the PNG should contain the negative space of the image you want to display (i.e. the shape you want should be transparent, and everything else should be the same color as the background).

Here’s an example of the Smashing Magazine logo with negative space:

Coloring the negative space of an image15

Notice in the demo16 how when the background color is set to orange, it starts to look more like the real thing.

The Code

First, let’s do some basic mark-up:

<div class="post-wrapper">
    <h2 class="post-title">
        This is the title you hover over

        <img src="knockout-image.png" class="post-image" alt="" />
    </h2>
    
    <p>Some more text here.</p>
</div>

Here we include a post with a title, our knock-out image and a paragraph of text.

Next, let’s set up some static styles:

.post-wrapper {
    position: relative;
    padding-left: 240px;
}

.post-image {
    position: absolute;
    top: 0;
    left: 0;
    background-color: #bbb;
}

.post-title {
    color: #037072;
}

Here, we’ve set up the post’s wrapper with position: relative and with enough padding on the left side to absolutely position the image to the left of our post. We’ve also added a background color to our image; so now the positive space in our PNG shows up as light gray.

Next, let’s add some hover effects:

.post-title:hover {
    color: #d63c25;
}

.post-title:hover .post-image {
    background-color: #f04e36;
}

Now, when we hover over the title or the image, both will change color.

We can take this effect a step further by animating the transition:

.post-image {
    -webkit-transition: background-color 400ms ease-in;
    -moz-transition: background-color 400ms ease-in;
    transition: background-color 400ms ease-in;
}

.post-title {
    -webkit-transition: color 400ms ease-in;
    -moz-transition: color 400ms ease-in;
    transition: color 400ms ease-in;
}

Here, we’ve added a CSS3 transition189 to both the image and the title, which will make for a smooth color change animation.

Unfortunately, CSS3 transitions are not currently supported in IE9. However, even in unsupported browsers, the color change will still occur — it just won’t have a smooth animation.

If complete cross-browser support for the animation is important, you could always provide a jQuery version of the animation for unsupported browsers. Bear in mind, though, that jQuery’s animate() method19 does not support color animations, so you’ll need to use a color plug-in20.

Putting all the CSS together:

.post-wrapper {
    position: relative;
    padding-left: 240px;
}

.post-image {
    position: absolute;
    top: 0;
    left: 0;
    background-color: #bbb;
    -webkit-transition: background-color 400ms ease-in;
    -moz-transition: background-color 400ms ease-in;
    transition: background-color 400ms ease-in;
}

.post-title {
    color: #037072;
    -webkit-transition: color 400ms ease-in;
    -moz-transition: color 400ms ease-in;
    transition: color 400ms ease-in;
}

/* add the hover states */

.post-title:hover {
    color: #d63c25;
}

.post-title:hover .post-image {
    background-color: #f04e36;
}

3. Mega Dropdown

Mega dropdown menu on Bohemia23

One common design problem with dropdown menus is that they often contain a lot of items. Instead of presenting all of its items in a long single column, Bohemia Design24 uses a multi-column dropdown. This approach not only looks great, but provides an opportunity to group the links and highlight the most important ones.

Let’s recreate this menu using CSS and jQuery.

Building the Tabs

Ideally, we would start with a lean and simple mark-up…

<nav>
    <li><a href="#">Tab 1</a></li>
    <li><a href="#">Tab 2</a></li>
    <li><a href="#">Tab 3</a></li>
    <li><a href="#">Tab 4</a></li>
    <li><a href="#">Tab 5</a></li>
</nav>

…and use nav li a, nav > li or nav li to style the list items in the navigation. The child selector doesn’t work in IE6 and nav li would cause problems since there are additional LIs nested in the content area of the dropdown. If you absolutely need the site to work for IE6 users as well (and that’s what you sometimes will have to do), you’ll need to have markup similar to the original mark-up in this example:

<ul id="main-nav">
    <li class="main-nav-item">
        <a href="#" class="main-nav-tab">Tab 1</a>
    </li>
    
    <li class="main-nav-item">
        <a href="#" class="main-nav-tab">Tab 2</a>
    </li>
    
    <li class="main-nav-item">
        <a href="#" class="main-nav-tab">Tab 3</a>
    </li>
    
    <li class="main-nav-item">
        <a href="#" class="main-nav-tab">Tab 4</a>
    </li>
    
    <li class="main-nav-item">
        <a href="#" class="main-nav-tab">Tab 5</a>
    </li>
</ul>

Next, let’s style these five tabs:

#main-nav {
    width: 800px;
    height: 50px;
    position: relative;
    list-style: none;
    padding: 0;
}

#main-nav .main-nav-item {
    display: inline;
}

#main-nav .main-nav-tab {
    float: left;
    width: 140px;
    height: 30px;
    padding: 10px;
    line-height: 30px;
    text-align: center;
    color: #FFF;
    text-decoration: none;
    font-size: 18px;
}

Although a lot of the CSS is specific to our example, there are a few important styles to note.

First, we’ve defined a height and width for our overall tab area and matched the total height and width of all five tabs, so that we can position the dropdown correctly. Next, we’ve defined position: relative for the tab wrapper, which will allow us to position the dropdown absolutely.

Then, we added list-style: none to the list wrapper, and display: inline to each list item, to eliminate any list styling.

Finally, we floated all of the tab links to the left.

Building the Dropdown

Now, let’s build the dropdown mark-up in one of our tab wrappers:

<li class="main-nav-item">
        <a href="#" class="main-nav-tab">Tab 1</a>
            
        <div class="main-nav-dd">
            <div class="main-nav-dd-column">
            Column content here
            </div>
        </div>
        
        <div class="main-nav-dd">
            <div class="main-nav-dd-column">
            Column content here
            </div>
        </div>
        
        <div class="main-nav-dd">
            <div class="main-nav-dd-column">
            Column content here
            </div>
        </div>
    </li>

Next, let’s style this dropdown:

#main-nav .main-nav-dd {
    position: absolute;
    top: 50px;
    left: 0;
    margin: 0;
    padding: 0;
    background-color: #FFF;
    border-bottom: 4px solid #f60;
}

#main-nav .main-nav-dd-column {
    width: 130px;
    padding: 15px 20px 8px;
    display: table-cell;
    border-left: 1px solid #ddd;
    *float: left;
    *border-left: 0;
}

#main-nav .main-nav-dd-column:first-child {
    border-left: 0;
}

Here, we’ve positioned the dropdown absolutely, directly beneath the first tab.

Let’s set display: table-cell on all of the column wrappers, so that they display next to each other. But table-cell is not supported in IE6 or 7, so we’ve used an attribute hack26 as an alternative for IE6 and 7. This hack places an asterisk (*) before each of the attributes that are specific to IE6 and 7.

Thus, we’ve defined a backup for unsupported IEs, which is simply float: left. This works almost as well as display: table-cell, except that the floated elements don’t match each other’s height, so the borders between columns don’t line up. To avoid this minor issue, we simply remove the border-left using the same asterisk hack.

Finally, we remove the left border from the first column for all browsers. Although the :first-child pseudo-class doesn’t work properly in IE6, fortunately it doesn’t make a difference, because we’ve already hidden the borders in these browsers.

Adding the Interaction

We’ve built the mark-up and styles for our dropdown, but we still need to make the menu interactive. Let’s use jQuery to add a class to show and hide the dropdown:

$(function() {
    var $mainNav = $('#main-nav');
    
    $mainNav.children('.main-nav-item').hover(function(ev) {
        // show the dropdown
        $(this).addClass('main-nav-item-active');
    }, function(ev) {
        // hide the dropdown
        $(this).removeClass('main-nav-item-active');
    });
});

Here, we’ve attached a hover listener27 to each list item, which adds and removes the class main-nav-item-active. Attach this to the list item rather than the tab itself, or else the dropdown will disappear when the user mouses off the tab and into the dropdown area.

Now we can use this class hook to hide and show the dropdown with CSS:

#main-nav .main-nav-dd {
    display: none;
}

#main-nav .main-nav-item-active .main-nav-dd {
    display: block;
}

Let’s use the active class to style the active tab:

#main-nav .main-nav-item-active .main-nav-tab {
    background-color: #FFF;
    color: #f60;
    -webkit-border-top-left-radius: 5px;
    -webkit-border-top-right-radius: 5px;
    -moz-border-radius-topleft: 5px;
    -moz-border-radius-topright: 5px;
    border-top-left-radius: 5px;
    border-top-right-radius: 5px;
}

Here, we’ve changed the background and text colors and rounded the top corners (in supported browsers).

Positioning the Dropdown

Now the basic mouse interaction has been built and the dropdown displays on mouseover. Unfortunately, it is still not positioned correctly under each tab, so let’s add some more code to our hover events:

$(function() {
    var $mainNav = $('#main-nav');
    
    $mainNav.children('.main-nav-item').hover(function(ev) {
        var $this = $(this),
        $dd = $this.find('.main-nav-dd');
        
        // get the left position of this tab
        var leftPos = $this.find('.main-nav-tab').position().left;

        // position the dropdown
        
        $dd.css('left', leftPos);
        
        // show the dropdown
        $this.addClass('main-nav-item-active');
    }, function(ev) {
    
        // hide the dropdown
        $(this).removeClass('main-nav-item-active');
    });
});

Here, we use jQuery’s position() method28 to get the left offset from the current tab. We then use this value to position the dropdown directly beneath the appropriate tab.

However, with the tabs on the right side, the dropdown menu will end up poking out of the tab area. Besides looking bad, this could lead to overflow issues, with portions of the dropdown falling outside of the browser window.

Let’s fix the positioning with some JavaScript:

$(function() {
    var $mainNav = $('#main-nav'),
    navWidth = $mainNav.width();
    
    $mainNav.children('.main-nav-item').hover(function(ev) {
        var $this = $(this),
        $dd = $this.find('.main-nav-dd');
        
        // get the left position of this tab
        var leftPos = $this.find('.main-nav-tab').position().left;
        
        // get the width of the dropdown
        var ddWidth = $dd.width(),
        leftMax = navWidth - ddWidth;
        
        // position the dropdown
        $dd.css('left', Math.min(leftPos, leftMax) );
        
        // show the dropdown
        $this.addClass('main-nav-item-active');
    }, function(ev) {
    
        // hide the dropdown
        $(this).removeClass('main-nav-item-active');
    });
});

Here, we start by finding the overall width of the tab area. Because recalculating the width for each tab is not necessary, we can define it outside of our hover listener.

Next, we find the width of the dropdown and determine the maximum left value, which is the overall tab width minus the width of the dropdown.

Finally, instead of always positioning the dropdown directly beneath the tab, we use the Math.min() method29 to pick the lowest between the tab offset and the maximum left value.

Thus, we confine the dropdown to the area beneath the tabs and avoid any content issues.

Other Approaches

While this script is fully functional, we could still improve the user experience. Currently, when the user mouses away from the dropdown, the menu hides immediately. You could build a delay using setTimeout() to ensure that the dropdown remains visible when the user mouses away and then quickly mouses back. This creates a better experience, because it avoids hiding the dropdown during accidental movements.

If you’d rather avoid setTimeout(), you could also look into the hoverIntent jQuery plug-in30, which makes fine-tuned control over mouse actions much easier.

Besides improving the user experience, you could also avoid jQuery altogether in all browsers except IE6.

Instead of using jQuery’s hover() listener, we could use the CSS pseudo-class :hover to hide and show the dropdown.

One downside with the CSS-only solution is that you can’t build a delay for the :hover pseudo-class.

Also, you will have to position the dropdown manually under each tab to avoid the overflow issues. Alternatively, if you aren’t concerned with overflow issues, you could attach position: relative to each list item and avoid setting any positions manually.

Finally, if you’re supporting IE6, make sure to include the script above as a backup for IE6 (but don’t include it for other browsers).

4. Animated Slideshow Navigation

Animated slideshow navigation on McKinney33

There are a lot of JavaScript slideshow techniques, but the animated navigation on McKinney34 is a fresh, subtle approach.

Basic jQuery Slideshow

Let’s build something similar. We’ll start with some mark-up for a basic slideshow:

<div id="slideshow">
    <div id="slideshow-reel">
        <div class="slide">
            <h1>Slide 1</h1>
        </div>
        
        <div class="slide">
            <h1>Slide 2</h1>
        </div>
        
        <div class="slide">
            <h1>Slide 3</h1>
        </div>
        
        <div class="slide">
            <h1>Slide 4</h1>
        </div>
        
        <div class="slide">
            <h1>Slide 5</h1>
        </div>
        
        <div class="slide">
            <h1>Slide 6</h1>
        </div>
    </div>
</div>

Here we’ve set up six slides, which can be filled with any content we need. Let’s set up some CSS to display the slides as a horizontal reel:

#slideshow {
    width: 900px;
    height: 500px;
    overflow: hidden;
    position: relative;
}

#slideshow-reel {
    width: 5400px;
    height: 450px;
    position: absolute;
    top: 0;
    left: 0;
}

#slideshow-reel .slide {
    width: 900px;
    height: 450px;
    float: left;
    background-color: gray;
}

Here, we’ve defined the dimensions of the slideshow, along with overflow: hidden to hide the other slides in the reel. We’ve also defined the dimensions of the reel: with six slides at 900 pixels each, it is 5400 pixels wide. (You could also just set this to a really high number, like 10000 pixels.) Then, we absolutely positioned the reel inside the slideshow (which has position: relative). Finally, we defined the dimensions for all of the individual slides and floated them to the left to fill up our reel.

Basic Slideshow Animation

Now, let’s add some jQuery to animate this slideshow:

$(function() {
    function changeSlide( newSlide ) {        
        // change the currSlide value
        currSlide = newSlide;
        
        // make sure the currSlide value is not too low or high
        if ( currSlide > maxSlide ) currSlide = 0;
        else if ( currSlide < 0 ) currSlide = maxSlide;
        
        // animate the slide reel
        $slideReel.animate({
            left : currSlide * -900
        }, 400, 'swing', function() {
            // set new timeout if active
            if ( activeSlideshow ) slideTimeout = setTimeout(nextSlide, 1200);
        });
    }
    
    function nextSlide() {
        changeSlide( currSlide + 1 );
    }
    
    // define some variables / DOM references
    var activeSlideshow = true,
    currSlide = 0,
    slideTimeout,
    $slideshow = $('#slideshow'),
    $slideReel = $slideshow.find('#slideshow-reel'),
    maxSlide = $slideReel.children().length - 1;
    
    // start the animation
    slideTimeout = setTimeout(nextSlide, 1200);
});

Here, we’ve started by creating the function changeSlide(), which animates the slide reel. This function accepts an index for the next slide to show, and it checks to make sure that the value isn’t too high or low to be in the reel.

Next, it animates the slide reel to the appropriate position, and then finishes by setting a new timeout36 to trigger the next iteration.

Finally, we’ve built the function nextSlide(), which simply triggers changeSlide() to show the next slide in the reel. This simple function is just a shortcut to be used with setTimeout().

The Left and Right Navigation

Next, let’s set up the left and right arrows in the slideshow, starting with the mark-up:

<a href="#" id="slideshow-prev"></a>
    <a href="#" id="slideshow-next"></a>

For simplicity’s sake, we’ve added the mark-up to the HTML source. Appending it to the jQuery is often a better approach, to ensure that the controls appear only when they are usable.

Let’s style these arrows with CSS:

#slideshow-prev, #slideshow-next {
    display: block;
    position: absolute;
    top: 190px;
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 28px 21px;
    border-color: transparent;
    outline: none;
}

#slideshow-prev:hover, #slideshow-next:hover {
    opacity: .5;
    filter: alpha(opacity=50);
    -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
}

#slideshow-prev {
    left: 0;
    border-right-color: #fff;
}

#slideshow-next {
    right: 0;
    border-left-color: #fff;
}

We’ve positioned the arrows absolutely within the slideshow frame and added an opacity change on hover. In our example, we’ve used a CSS triangle trick37 to style the arrows with straight CSS, but feel free to use an image if you want richer graphics.

Finally, let’s build the required interaction into our JavaScript:

$(function() {
    function changeSlide( newSlide ) {
        // cancel any timeout
        clearTimeout( slideTimeout );
        
        // change the currSlide value
        currSlide = newSlide;
        
        // make sure the currSlide value is not too low or high
        if ( currSlide > maxSlide ) currSlide = 0;
        else if ( currSlide < 0 ) currSlide = maxSlide;
        
        // animate the slide reel
        $slideReel.animate({
            left : currSlide * -900
        }, 400, 'swing', function() {
            // hide / show the arrows depending on which frame it's on
            if ( currSlide == 0 ) $slidePrevNav.hide();
            else $slidePrevNav.show();
            
            if ( currSlide == maxSlide ) $slideNextNav.hide();
            else $slideNexNav.show();
            
            // set new timeout if active
            if ( activeSlideshow ) slideTimeout = setTimeout(nextSlide, 1200);
        });
        
        // animate the navigation indicator
        $activeNavItem.animate({
            left : currSlide * 150
        }, 400, 'swing');
    }
    
    function nextSlide() {
        changeSlide( currSlide + 1 );
    }
    
    // define some variables / DOM references
    var activeSlideshow = true,
    currSlide = 0,
    slideTimeout,
    $slideshow = $('#slideshow'),
    $slideReel = $slideshow.find('#slideshow-reel'),
    maxSlide = $slideReel.children().length - 1,
    $slidePrevNav = $slideshow.find('#slideshow-prev'),
    $slideNextNav = $slideshow.find('#slideshow-next');
    
    // set navigation click events
    
    // left arrow
    $slidePrevNav.click(function(ev) {
        ev.preventDefault();
        
        activeSlideshow = false;
        
        changeSlide( currSlide - 1 );
    });
    
    // right arrow
    $slideNextNav.click(function(ev) {
        ev.preventDefault();
        
        activeSlideshow = false;
        
        changeSlide( currSlide + 1 );
    });
    
    // start the animation
    slideTimeout = setTimeout(nextSlide, 1200);
});

Here, we’ve added quite a bit of new interaction. First, look at the bottom of this script, where we’ve added click event listeners to both of our navigational items.

In these functions, we have first set activeSlideshow to false, which disables the automatic animation of the reel. This provides a better user experience by allowing the user to control the reel manually. Then, we trigger either the previous or next slide using changeSlide(). Next, in the changeSlide() function, we’ve added a clearTimeout()38. This works in conjunction with the activeSlideshow value, cancelling any hanging iteration from a setTimeout.

Finally, in the callback of the animate() function, we’ve added some code to hide and show the arrow navigation. This hides the left arrow when the slideshow is showing the left-most slide, and vice versa.

Animating the Bottom Navigation

The basic slideshow works with the previous and next arrows. Let’s take it to the next level by adding the animated navigation. Please note that I am using a more complex markup because it avoids the use of images and is ultimately simpler. It would have to use three background images otherwise — one for the center sections and one for each cap to allow the clickable areas to be larger). However, you could clean up the bottom navigation with a background-image.

Here is the jQuery code for animation:

$(function() {
    function changeSlide( newSlide ) {
        // cancel any timeout
        clearTimeout( slideTimeout );
        
        // change the currSlide value
        currSlide = newSlide;
        
        // make sure the currSlide value is not too low or high
        if ( currSlide > maxSlide ) currSlide = 0;
        else if ( currSlide < 0 ) currSlide = maxSlide;
        
        // animate the slide reel
        $slideReel.animate({
            left : currSlide * -900
        }, 400, 'swing', function() {
            // hide / show the arrows depending on which frame it's on
            if ( currSlide == 0 ) $slidePrevNav.hide();
            else $slidePrevNav.show();
            
            if ( currSlide == maxSlide ) $slideNextNav.hide();
            else $slideNextNav.show();
            
            // set new timeout if active
            if ( activeSlideshow ) slideTimeout = setTimeout(nextSlide, 1200);
        });
        
        // animate the navigation indicator
        $activeNavItem.animate({
            left : currSlide * 150
        }, 400, 'swing');
    }
    
    function nextSlide() {
        changeSlide( currSlide + 1 );
    }
    
    // define some variables / DOM references
    var activeSlideshow = true,
    currSlide = 0,
    slideTimeout,
    $slideshow = $('#slideshow'),
    $slideReel = $slideshow.find('#slideshow-reel'),
    maxSlide = $slideReel.children().length - 1,
    $slidePrevNav = $slideshow.find('#slideshow-prev'),
    $slideNextNav = $slideshow.find('#slideshow-next'),
    $activeNavItem = $slideshow.find('#active-nav-item');
    
    // set navigation click events
    
    // left arrow
    $slidePrevNav.click(function(ev) {
        ev.preventDefault();
        
        activeSlideshow = false;
        
        changeSlide( currSlide - 1 );
    });
    
    // right arrow
    $slideNextNav.click(function(ev) {
        ev.preventDefault();
        
        activeSlideshow = false;
        
        changeSlide( currSlide + 1 );
    });
    
    // main navigation
    $slideshow.find('#slideshow-nav a.nav-item').click(function(ev) {
        ev.preventDefault();
        
        activeSlideshow = false;
        
        changeSlide( $(this).index() );
    });
    
    // start the animation
    slideTimeout = setTimeout(nextSlide, 1200);
});

We’ve added a couple of things to our script.

First, we’ve included a second animation in changeSlide(), this time to animate the active indicator in the navigation. This animate() is basically the same as the one we built for the reel, the main difference being that we want to move it only 150px per slide.

Finally, we added a click event listener to the items in the bottom navigation. Similar to the arrow navigation, we start by disabling the automatic animation, setting activeSlideshow to false. Next, we trigger changeSlide(), passing in the index of whichever slide was clicked, which is easy to determine using jQuery’s index()39 method.

Now the slideshow navigation animation is complete and ready to impress your visitors.

5. Animated Icons

Animated icons on CSS Tricks42

CSS-Tricks43 has a simple but elegant effect in its footer when the user mouses over various buttons. Besides the color changing and an icon being added, the effect is animated in browsers that support transition, making the icon appear to slide into place.

Let’s create a similar effect, starting with some mark-up:

<a href="#" class="hover-panel">
    <h3>Panel Title</h3>
    
    <p>Additional information about the panel goes in a paragraph here</p>
</a>

One thing to note about this mark-up is that it has block elements nested in an <a> element, which makes sense semantically, but it’s valid only if you’re using the HTML5 doc type.

Styling the Buttons

Let’s set up some basic CSS to style the block in its natural (non-hovered) state:

.hover-panel {
    background-color: #E6E2DF;
    color: #B2AAA4;
    float: left;
    height: 130px;
    width: 262px;
    margin: 0 10px 10px 0;
    padding: 15px;
}

.hover-panel h3 {
    font-family: tandelle-1, tandelle-2, Impact, Sans-serif, sans;
    font-size: 38px;
    line-height: 1;
    margin: 0 0 10px;
    text-transform: uppercase;
}

.hover-panel p {
    font-size: 12px;
    width: 65%;
}

Now let’s add a static hover effect to change some of the colors and add a drop shadow:

.hover-panel:hover {
    background-color: #237ABE;
}

.hover-panel:hover h3 {
    color: #FFF;
    text-shadow: rgba(0, 0, 0, 0.398438) 0px 0px 4px;
}

.hover-panel:hover p {
    color: #FFF:
}

Finally, let’s add a background image that pops into place on hover:

.hover-panel {
    background-image: url(hover-panel-icon.png);
    background-position: 292px 10px;
    background-repeat: no-repeat;
}

.hover-panel:hover {
    background-position: 180px 10px;
}

Here, we’ve added a few important styles to accomplish the hover effect. First, we’ve attached the background image to our .hover-panel. This is normally positioned outside of the button, but on mouseover, it is placed correctly. Also, note that we’ve placed it off to the right side of the panel, so that when we apply the transition animation, the icon will slide in from the right.

Animating the Transition

Finally, let’s add the transition:

.hover-panel {
     -moz-transition: all 0.2s ease; /* FF3.7+ */
       -o-transition: all 0.2s ease; /* Opera 10.5 */
  -webkit-transition: all 0.2s ease; /* Saf3.2+, Chrome */
          transition: all 0.2s ease;
}

The transition effect triggers the animation of the background image. Because we’ve flagged it to apply to all attributes, the transition will also be applied to the background-color change that we applied above.

Although this works in most modern browsers, it will not work in IE9. But even in unsupported browsers, the user will see the color change and icon; they just won’t see the animation effect.

On most websites, this enhancement wouldn’t be necessary for all users. But if support is a priority, look into this jQuery back-up45.

Finally, let’s bring all of the styles together:

.hover-panel {
    background-color: #E6E2DF;
    background-image: url(hover-panel-icon.png);
    background-position: 292px 10px;
    background-repeat: no-repeat;
    color: #B2AAA4;
    display: block;
    float: left;
    height: 130px;
    width: 262px;
    margin: 0 10px 10px 0;
    padding: 15px;
     -moz-transition: all 0.2s ease; /* FF3.7+ */
       -o-transition: all 0.2s ease; /* Opera 10.5 */
  -webkit-transition: all 0.2s ease; /* Saf3.2+, Chrome */
          transition: all 0.2s ease;
}

.hover-panel h3 {
    font-family: tandelle-1, tandelle-2, Impact, Sans-serif, sans;
    font-size: 38px;
    line-height: 1;
    margin: 0 0 10px;
    text-transform: uppercase;
}

.hover-panel p {
    font-size: 12px;
    width: 65%;
}

.hover-panel:hover {
    background-color: #237ABE;
    background-position: 180px 10px;
}

.hover-panel:hover h3 {
    color: #FFF;
    text-shadow: rgba(0, 0, 0, 0.398438) 0px 0px 4px;
}

.hover-panel:hover p {
    color: #FFF:
}

Final Thoughts

In this article, we’ve walked through a variety of interactive techniques that can add a bit of style and creativity to your website. Used correctly, techniques like these enhance websites, creating a more engaging and memorable user experience. But be subtle with the interactivity, ensuring that the bells and whistles do not get in the way of the website’s primary function, which is to providing meaningful content.

What do you think of the techniques presented here? Do you know of any ways to improve these scripts? What are some other interactive techniques that you’ve seen around the Web?

Image source: San Diego Air & Space Museum Archives48

(al)

Footnotes

  1. 1 #extruded-text
  2. 2 #animated-images
  3. 3 #mega-dropdown
  4. 4 #slideshow-navigation
  5. 5 #animated-icons
  6. 6 http://desandro.com/
  7. 7 http://desandro.com/
  8. 8 http://jonraasch.com/demo/extrude-on-hover
  9. 9 http://net.tutsplus.com/tutorials/html-css-techniques/css-fundametals-css-3-transitions/
  10. 10 https://gist.github.com/957199
  11. 11 http://jonraasch.com/demo/extrude-on-hover
  12. 12 http://lovenonsense.com/
  13. 13 http://www.gifmuseum.com/
  14. 14 http://lovenonsense.com/
  15. 15 http://jonraasch.com/demo/animated-image
  16. 16 http://jonraasch.com/demo/animated-image
  17. 17 http://jonraasch.com/demo/animated-image
  18. 18 http://net.tutsplus.com/tutorials/html-css-techniques/css-fundametals-css-3-transitions/
  19. 19 http://api.jquery.com/animate/
  20. 20 https://github.com/jquery/jquery-color
  21. 21 https://gist.github.com/957217
  22. 22 http://jonraasch.com/demo/animated-image
  23. 23 http://www.bohemiadesign.co.uk/
  24. 24 http://www.bohemiadesign.co.uk/
  25. 25 http://jonraasch.com/demo/huge-dropdown-menu
  26. 26 http://paulirish.com/2009/browser-specific-css-hacks/
  27. 27 http://bavotasan.com/tutorials/a-simple-mouseover-hover-effect-with-jquery/
  28. 28 http://api.jquery.com/position/
  29. 29 http://www.tutorialspoint.com/javascript/math_min.htm
  30. 30 http://cherne.net/brian/resources/jquery.hoverIntent.html
  31. 31 https://gist.github.com/957213
  32. 32 http://jonraasch.com/demo/huge-dropdown-menu
  33. 33 http://mckinney.com/
  34. 34 http://mckinney.com/
  35. 35 http://jonraasch.com/demo/fancy-slideshow-navigation
  36. 36 http://www.elated.com/articles/javascript-timers-with-settimeout-and-setinterval/
  37. 37 http://www.dinnermint.org/blog/css/creating-triangles-in-css/
  38. 38 http://programming.top54u.com/post/JavaScript-clearTimeout.aspx
  39. 39 http://api.jquery.com/index/
  40. 40 https://gist.github.com/957203
  41. 41 http://jonraasch.com/demo/fancy-slideshow-navigation
  42. 42 http://css-tricks.com
  43. 43 http://css-tricks.com
  44. 44 http://jonraasch.com/demo/animated-icons
  45. 45 http://jonraasch.com/blog/graceful-degradation-with-css3#transitions
  46. 46 https://gist.github.com/957236
  47. 47 http://jonraasch.com/demo/animated-icons
  48. 48 http://www.flickr.com/photos/sdasmarchives/5018420677/

↑ Back to topShare on Twitter

Jon Raasch is a front-end web developer / UI designer with endless love for jQuery, CSS3 and performance tuning. Follow him on Twitter or read his blog.

Advertising

Note: Our rating-system has caused errors, so it's disabled at the moment. It will be back the moment the problem has been resolved. We're very sorry. Happy Holidays!

  1. 1

    Thanks for these techniques. I look forward to trying them out! :)

  2. 2

    Regarding the slideshow: “This provides a better user experience by allowing the user to control the reel manually.”

    It makes perfect sense to pause the slideshow as long as it has the focus of the user – after all, a slide change while I read the current one would be extremely bothersome! However, I don’t think it’s a good idea to stop it altogether. As a user, I kinda expect the slideshow to go on after I focus on something else. Wouldn’t it be better to, at least for desktop users, just pause the slideshow as long as I hover it with the cursor, like The Quietus does?

  3. 3

    The McKinney carousel actually does a lot more than you give it credit for. It works on iOS and other mobile touch based OS’s when you slide the banners left or right. The ‘scrubber’ also works using touch.

    There is a GitHub project called lectric.js that is a public release from one of the devs there, pretty impressive stuff.

  4. 4

    Thank you for this article.

    While the megamenu tutorial certainly works, I feel we have a great opportunity to write better/smarter code and reinforce semantic markup.

    I would have relied more on markup taken from existing schemas.
    http://www.alistapart.com/articles/dropdowns

    You could have used nested unordered lists (dream inside a dream inside a dream) for all your megamenu elements, removed any classes pertaining to layout(column dd-column) and dropped 95% of your javascript by using css pseudo class (:hover) to trigger the drop down (special ie6 support of necessary with one line of js).

  5. 5

    Some of these approaches are good….some are horrendous from a coders point of view. Look at the example where you position the dropdown on hover. Instead of positioning each dropdown once, when the page loads, you position them every single time the user hovers over a tab…..what in the world are you thinking???

  6. 6

    Happy, please more, thank you .. :)
    (yes, pun intended)

  7. 7

    Johan Pettersson

    June 16, 2011 7:47 am

    Thanks! More of these kind of tip please :)

  8. 8

    Just a quick note – all your text shadow examples are incorrect. The color should come at the end, not the beginning, as per the spec:
    http://www.w3.org/TR/css3-text/#text-shadow and http://www.w3.org/TR/css3-background/#the-box-shadow (shadow definition)

  9. 9
  10. 10

    They are pretty cool, except none of them work as they should in ie yet…such a shame :(

  11. 11

    @Darren – That’s cool stuff, good to know, thanks for that link!

    @Garrett – Regarding the CSS :hover implementation, I mentioned that possibility in the end, but there are two downsides: you lose the dynamic positioning abilities, and also the hover delay capability (which is left out of the example for simplicity but nevertheless improves UX)

    @Adam – While I hear what you’re saying here, I think you’re overestimating the processing time of the positioning operation. If this sort of micro-optimization is important, you could certainly cache a variable or use the jQuery data() API, however bear in mind that this too would take a tiny amount of processing time, and would only be relevant if the user hovered over the same dropdown twice on a page (e.g. if they were “playing with” the dropdown).

  12. 12

    There are some things that degrade in IEs but for the most part these work in IE6+ (and I described ways that you can build in a backup for the transition if it’s really important). So if you build in the backup, the only thing that you’ll be unable to support in IEs is the first example.

  13. 13

    Great article! I would love to see more articles like these! Keep them coming!

  14. 14

    Nice examples. Thank you for the lineup.

  15. 15

    This was insanely insightful. Thanks.

  16. 16

    Learned a lot today:)

    (vynora.com/youss-design)

  17. 17

    FYI, <li> can’t be a child of <nav> (you use it to start with in your mega navigation section). Check your code with the W3C’s validator and you’ll get the following error:

    Element li not allowed as child of element nav in this context.
    Contexts in which element li may be used:
    Inside ol elements.
    Inside ul elements.
    Inside menu elements.

    The spec also suggests that <li> can’t be a direct descendant of <nav> .

  18. 18

    the mega dropdown menu is easily made with css only.

    – apply postion relative for li
    – apply display none and position absolute for the div.main-nav-dd. arrange its position with top option.
    – apply display block for li.main-nav-item:hover

    The code wroted in this article its necessary if you want an jquery.fadeIn/fadeOut

  19. 19

    nice article! i thought i had fallen out of love with some of these techniques, but seeing them built simply and executed suavely makes me happy to look at them again, especially the slideshow and animated icons.

    [and, wow, i had no idea about the css triangle trick. very cool.]

    thanks!

  20. 20

    Wondering does Extruded effect can be applied other than text?

  21. 21

    Hi,

    I have a question is there any way to randomize the css color choice for this css styling Animating A Background Image?

    thanks

    Nick

  22. 22

    If you only use CSS you can’t position the dropdown as well…for instance on the right side, the dropdown is positioned to the left of the tabs, to keep it confined beneath them. If you use a CSS-only alternative, it will always be positioned off to the right of each tab (unless you hardcode the positioning).

  23. 23

    You can do something similar with box-shadow, however it will only work on rectangular elements.

  24. 24

    I don’t know of a way to do this with CSS, but you can certainly make it happen with JavaScript.

  25. 25

    Today I got Solution for some of my issues.

  26. 26

    Hi Smashing Magazine Team and the author of this great post!
    This post is exactly what I want to see on SM more. Keep them coming =)

  27. 27

    This is simply good, very helpful man,
    I like the way you disect CSS and jQuery, please more of this…
    get more inspiration and ideas at some CSS gallery sites, hopefully.

  28. 28

    This post is amazing after long time ! Thanks For sharing it Jon.

  29. 29

    Hey I’m commented below but I think it might have gotten a bit lost.

    In the article I mentioned that a CSS-only solution is possible for the dropdown, but you won’t be able to position the dropdown as well. If you only use CSS, the dropdown will fall directly below and out to the right of each of the tabs, which can cause overflow issues with the tabs on the right. So the script positions it more dynamically, pushing any overflow underneath the tabs. You could however accomplish this with straight CSS as well, however you’d have to hardcode these positions.

    Also I know the markup here isn’t the prettiest, but it’s necessary for the multiple columns / headlines / link lists within each dropdown panel. If you click through to the example you’ll see some nested lists, but with a lot of other content as well.

  30. 30

    Hey you’re absolutely right, this must have gotten added in the editing process, since li’s should definitely not be nested within a nav. I’ll talk to the editors and try to get this cleared up.

  31. 31

    Hey I commented below because I didn’t realize I could reply directly, but I think it got a bit lost.

    While I hear what you’re saying here, I think you’re overestimating the processing time of the positioning operation. If this sort of micro-optimization is important, you could certainly cache a variable or use the jQuery data() API, however bear in mind that this too would take a tiny amount of processing time, and would only be relevant if the user hovered over the same dropdown twice on a page (e.g. if they were “playing with” the dropdown).

  32. 32

    ! loads of good stuff here. I like the Animated Icons the bestest. Thanks!

  33. 33

    amazing…
    thanks for the great technique m/

  34. 34

    excited to learn these cool stuffs! thanks

  35. 35

    Thanks for sharing all these useful stuff. I enjoyed the CSS-Tricks footer the most and that is what I was looking for…have downloaded it. Thanks once again..

  36. 36

    Good post. You should note, though, that Love Nonsense doesn’t use graphics for those little bug images – it’s actually the Bagarozz font (http://www.fontsquirrel.com/fonts/Bagarozz). The color of the font goes red when you hover over it and the title. But you have the right idea on how to get a similar effect when using images!

  37. 37

    On the megadropdown, if you have a menu item with parenthesis’s in it (e.g. Products (Something) ), the parenthesis will display a line return on the initial hover, but not on the secondary. If you add white-space: nowrap; to the text container, the link will then display correctly.

    I was pulling my hair out for awhile, before I nailed the issue down. Hope this helps someone.

  38. 38

    God Bless mate ..

    What a lovely tutorial post .. love it, the first time I can see a proper useful implementation of CSS3 .. I can’t wait to implement them all soon

    Keep the good work .. Cheers

  39. 39

    Hi Jon,
    Thanks for mentioning Love Nonsense! There is a But though: I don’t animate the color of the images by changing the background color.
    I use a much simpler technique, I just change the color of the images on :hover and I use rgba as a unit. If you check the code you will see that the images are in fact fonts without spaces and that they represent the first few letters of the title of each article. There are no images at all on Love Nonsense. Thanks again for linking though!

  40. 40

    The huge dropdown is totally messed up in IE 6 and up. Even if it looks good in FF or chrome it’s totally useless that way.

  41. 41

    Thanks for this article!
    You forgot the html code for the bottom navigation…

  42. 42

    Useful One! Keep them coming SM.

  43. 43

    It is time let IE6 go people.

    “But –insert small percentage here– still uses IE 6″, comes the reply.

    Take a stand. If you are willing to code for it then you are just as much to blame as the people still using it.

  44. 44

    at first I thought animations are all done with JS. Now I learned something brilliant. I can’t wait to use those techniques.

  45. 45

    Thanks for the jQuery sliding banner! I modified it and am using it in my next website!

  46. 46

    Slideshow – How do I get rid of auto-slide? I want the user to have full control right from the first slide.

  47. 47

    Awesom!

  48. 48

    what is the best way to add multiple icons in the Animated Icon example? do i just need to make a new ID for each icon or is their a simpler way? Thanks!

  49. 49

    Hello, I like to read more about this field. I appreciate you for publishing this.

  50. 50

    i have been to pages that have 100 jquery examples but may be only 2 or 3 of them are useful.. but on this page there r only 5 and seriously all 5 are awesome.. dont know you will read this comment or not but then also.. i appreciate your reasearch on jquery :)

  51. 51

    Very nice, thanks!

  52. 52

    Great resource here:

    On number 5: How do you alternate the icon for a different box ? say you have several boxes and you want a different icon on hover… short of creating a new class for each box ( which would work because I’m using this on a static page ) is there a way of defining the icon to use, along with the box ?

    I think I’m being very slow but any help much appreciated. Best method I’ve found is to apply multiple classes so apply an additional class to each box alongside ‘hover-panel’

    e.g.

    class =”hover-panel box1″
    class =”hover-panel box2″
    class =”hover-panel box3″

    Then defining the hover icon boxes on their own e.g.

    .box1 { background image and position and repeat info for box 1 }
    .box1 :hover { adjusted position } …. and so on for box 2 and 3. Just feel like I’m making this harder than it needs to be.

  53. 53

    new class works see my post below.

  54. 54

    Regarding Animated Slideshow Navigation
    I have tried to integrate this slideshow in my website , but have run into a problem. I use WordPress with the theme Atahualpa. I have put the images and css in a folder, and the rest of the code I put directly in the page. When I take the html code demo and put the images and the css in separate folders it all works. I think I got it all except that the slider does not work for me in the WordPress setup. Would it be possible for you to take a look and see if you can see what I do wrong?

  55. 55

    Hi,I just added the secondary menu to a child theme I am odveleping for twentyten. it was good, I liked it, but I want us to get a bit further. You know, the standard way that menu are being passed by wordpress to the template in HTML is using unordered list but I want the menu to be parsed our using , do you know of a way we can archive this in WordPress?

  56. 56

    What are your thoughts on not using li inside nav at all, just having plain links?

  57. 57

    McKinney slider – Would love to know how to make the arrows disappear when its the first/last slide like they do on McKinney’s site. Their open source code doesn’t have this feature.

  58. 58

    4. Animated Slideshow Navigation

    this anchor is break :(

↑ Back to top