Author Archive

Five Useful Interactive CSS/jQuery Techniques Deconstructed

Advertisement in Five Useful Interactive CSS/jQuery Techniques Deconstructed
 in Five Useful Interactive CSS/jQuery Techniques Deconstructed  in Five Useful Interactive CSS/jQuery Techniques Deconstructed  in Five Useful Interactive CSS/jQuery Techniques Deconstructed

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 effects,
  2. Animated images without GIFs,
  3. More engaging drop-down menus,
  4. Fancier slideshow navigation,
  5. Animated icons 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 in Five Useful Interactive CSS/jQuery Techniques Deconstructed

The footer of David DeSandro’s website 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 transition 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-images in Five Useful Interactive CSS/jQuery Techniques Deconstructed

While we can easily animate text with a few lines of code, animating an image usually requires bigger and slower assets, such as animated GIFs 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 Nonsense 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:

Inverse-negative-space in Five Useful Interactive CSS/jQuery Techniques Deconstructed

Notice in the demo 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 transition 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() method does not support color animations, so you’ll need to use a color plug-in.

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 in Five Useful Interactive CSS/jQuery Techniques Deconstructed

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 Design 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 hack 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 listener 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() method 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() method 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-in, 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 in Five Useful Interactive CSS/jQuery Techniques Deconstructed

There are a lot of JavaScript slideshow techniques, but the animated navigation on McKinney 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 timeout 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 trick 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(). 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() method.

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

5. Animated Icons

Animated-icons-on-css-tricks in Five Useful Interactive CSS/jQuery Techniques Deconstructed

CSS-Tricks 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-up.

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?

(al)


© Jon Raasch for Smashing Magazine, 2011. | Permalink | Post a comment | Smashing Shop | Smashing Network | About Us
Post tags: ,


How To Build A Mobile Website

Smashing-magazine-advertisement in How To Build A Mobile WebsiteSpacer in How To Build A Mobile Website
 in How To Build A Mobile Website  in How To Build A Mobile Website  in How To Build A Mobile Website

Over the past few years, mobile web usage has considerably increased to the point that web developers and designers can no longer afford to ignore it. In wealthy countries, the shift is being fueled by faster mobile broadband connections and cheaper data service. However, a large increase has also been seen in developing nations where people have skipped over buying PCs and gone straight to mobile.

Unfortunately, the mobile arena introduces a layer of complexity that can be difficult for developers to accommodate. Mobile development is more than cross-browser, it should be cross-platform. The vast number of mobile devices makes thorough testing a practical impossibility, leaving developers nostalgic for the days when they only had to support legacy browsers.

In addition to supporting different platforms, each device may use any number of mobile web browsers. For instance, an Android user could access your site using the native Android browser, or could have also installed Opera Mini or Firefox Mobile. It’s fine as long as the smartphone uses a progressive web browser (and it’s safe to say that most browsers are progressive nowadays), but it doesn’t have to.

Smartphone in How To Build A Mobile Website
Source: Nielsen Study, Image credit

The mobile web reintroduces several issues that have been largely ignored in recent years. First, even with 4G networks, bandwidth becomes a serious issue for mobile consumers. Additionally, mobile devices have a significantly reduced screen size, which presents screen real estate issues that have not existed since the days of projection monitors. Combine these issues with cross-platform compatibility problems, and it isn’t hard to see how mobile development is a lot like ‘stepping backwards in time’. So let’s tackle these issues one at a time and create a road map for mobile web development:

How To Implement Mobile Stylesheets

The first step to adding mobile support to a website is including a special stylesheet to adjust the CSS for mobile devices:

Server-side Methods & The UA String

One approach to including mobile stylesheets involves detecting the user agent string with a server-side language such as PHP. With this technique, the site detects mobile devices and either serves an appropriate stylesheet or redirects the user to a mobile subdomain, for instance m.facebook.com. This server-side approach has several advantages: it guarantees the highest level of compatibility and also allows the website to serve special mark-up/content to mobile users.

Facebook-mobile in How To Build A Mobile Website
Large image

While this technique is perfect for enterprise level websites, there are practical concerns that make it difficult to implement on most sites. New user agent strings come out almost daily, so keeping the UA list current is next to impossible. Additionally, this approach depends on the device to relay its true user agent. Even though, browsers have spoofed their UA string to get around this type of detection in the past. For instance, most UA strings still start with “Mozilla” to get through the Netscape checks used in the 90′s, and for several years Opera pretended to be IE. As Peter-Paul Koch writes:

“It’s an arms race. If device detection really catches on, browsers will start to spoof their user agent strings to end up on the right side of the detects.”

Client-side Methods & Media Queries

Alternately, the easiest approach involves detecting the mobile device on the client side. One of the earliest techniques for including mobile stylesheets involves taking advantage of the stylesheet’s media type, for instance:

<link rel="stylesheet" href="site.css" media="screen" />
<link rel="stylesheet" href="mobile.css" media="handheld" />

Here we’ve included two stylesheets, the first site.css targets desktops and laptops using the screen media type, while the second mobile.css targets mobile devices using handheld. While this would otherwise be an excellent approach, device support is another issue. Older mobile devices tend to support the handheld media type, however they vary in their implementation: some disable the screen stylesheets and only load handheld, whereas others load both.

Additionally, most newer devices have done away with the handheld distinction altogether, in order to serve their users fully-featured web pages as opposed to duller mobile layouts. To support newer devices, we’ll need to use media queries, which allow us to target styles to the device width (you can see another practical adaptation of media queries in Ethan Marcotte’s article Responsive Web Design). Since mobile devices typically have smaller screens, we can target handheld devices by detecting screens that are 480px and smaller:

<link rel="stylesheet" href="mobile.css" media="only screen and (max-device width:480px)"/>

While this targets most newer devices, many older devices don’t support media queries, so we’ll need a hybrid approach to get the largest market penetration.

First, define two stylesheets: screen.css with everything for normal browsers and antiscreen.css to overwrite any styles that you don’t want on mobile devices. Tie these two stylesheets together in another stylesheet core.css:

@import url("screen.css");
@import url("antiscreen.css") handheld;
@import url("antiscreen.css") only screen and
(max-device-width:480px);

Finally, define another stylesheet handheld.css with additional styling for mobile browsers and link them on the page:

<link rel="stylesheet" href="core.css" media="screen"/>
<link rel="stylesheet" href="handheld.css" media="handheld,
only screen and (max-device-width:480px)"/>

While this technique reaches a large market share of mobile devices, it is by no means perfect. Some mobile devices such as iPad are more than 480 pixels wide and will not work with this method. However, these larger devices arguably don’t need a condensed mobile layout. Moving forward, there will likely be more devices that don’t fit into this mold. Unfortunately, it is very difficult to future-proof mobile detection, since standards are still emerging.

Besides device detection, the media query approach also presents other issues. Mainly, media queries can only style content differently and provide no control over content delivery. For instance, a media query can be used to hide a side column’s content, but it cannot prevent that mark-up from being downloaded by your users. Given mobile bandwidth issues, this additional HTML should not simply be ignored.

User Initiated Method

Ikea-website in How To Build A Mobile Website

Considering the difficulties with mobile UA detection and the pitfalls of media queries, some companies such as IKEA have opted to simply allow the user to decide whether to view the mobile version of their website. While this has the clear disadvantage of requiring more user interaction, it is arguably the most fool-proof method and also the easiest to accomplish.

The site contains a link that reads “Visit our mobile site” which transports the user to a mobile subdomain. This approach has some drawbacks. Of course, some mobile users may miss the link, and other non-mobile visitors may click it, since it is visible regardless of what device is being used. Even though, this technique has the advantage of allowing the user to make the mobile decision. Some users prefer a condensed layout that is optimized for their device, whereas other users may prefer to access the entire website, without the restrictions of a limited mobile layout.

What To Change With Mobile Stylesheets

Now that we’ve implemented mobile stylesheets, it’s time to get down to the nuts and bolts of which styles we actually want to change.

Increase & Alter Screen Real Estate

Cnn-regular-vs-mobile1 in How To Build A Mobile Website

The primary goal of mobile stylesheets is to alter the layout for a smaller display. First and foremost this means reducing multi-column layouts to single columns. Most mobile screens are vertical, so horizontal space becomes even more “expensive” and mobile layouts can rarely afford more than one column of content. Next, reduce clutter throughout the page by setting display: none; on any less important elements. Finally, save additional pixels by reducing margins and padding to create a tighter layout.

Reduce Bandwidth

Another goal of mobile stylesheets is to reduce bandwidth for slower mobile networks. First make sure to remove or replace any large background images, especially if you use a background image for the whole site. Additionally set display: none on any unnecessary content images.

If your site uses images for buttons or navigation, consider replacing these with plain-text / CSS counterparts. Finally if you’d like to force the browser to use the alternate text for any of your images, use this snippet (and use JavaScript to add the as-text class for img and make sure that alt-attributes are properly defined in your markup):

img.as-text { content: attr(alt); }

Other Changes

Besides addressing screen size and bandwidth concerns, there are a few additional changes that should be made in any mobile stylesheet. First, you can improve readability by increasing the font size of any small or medium-sized text. Next, clicking is generally less precise on mobile devices, so make sure to increase the clickable areas of any important buttons or links by setting display: block and adding padding to the clickable elements.

Additionally, floated elements can cause problems for mobile layouts, so consider removing any floats that aren’t absolutely necessary. Remember that horizontal real estate is especially expensive on mobile, so you should always opt for adding vertical scrolling as opposed to horizontal.

Finally, mouseover states do not work with most mobile devices, so make sure to have proper definitions of :active-states. Also, sometimes it may be useful to apply definitions from the already defined :hover states to the :active states. This pseudo-class is displayed when the user clicks an item, and therefore will work on mobile devices. However this only enhances the user experience and should not be relied on for more important elements, such as drop-down navigation. In these cases it is best to show the links at all times in mobile devices.

Beyond Stylesheets

In addition to mobile stylesheets, we can add a number of special mobile features through mark-up.

Clickable Phone Numbers

First, most handheld devices include a phone, so let’s make our phone numbers clickable:

<a href="tel:15032084566" class="phone-link">(503) 208-4566</a>

Now mobile users can click this number to call it, however there are a few things to note. First, the number in the actual link starts with a 1 which is important since the web is international (1 is the US country code).

Second, this link is clickable whether or not the user has a mobile device. Since we’re not using the server-side method described above, our best option is to simply hide the fact that the number is clickable via CSS. So use the phone-link class to disable the link styling in your screen stylesheet, and then include it again for mobile.

Special Input Types

Iphone-html5-input-types in How To Build A Mobile Website

When it comes to mobile browsing, another concern is the difficulty of typing compared to a standard full-sized keyboard. But we can make it easier on our users by taking advantage of some special HTML5 input types:

<input type="tel" />
<input type="email" />

These input types allow devices such as iPhone to display a contextual keyboard that relates to the input type. In the example above type="tel" triggers a numeric keypad ideal for entering phone numbers, and type="email" triggers a keypad with @ and . buttons.

HTML5 input types also provide in-browser validation and special input menus that are useful in both mobile and non-mobile browsing. Furthermore, since non-supportive browsers naturally degrade to view these special input types as <input type="text" />, there’s no loss in using HTML5 input types throughout your websites today.

See a complete list of HTML5 input types. You can find some information about the current browser support of HTML5 input attributes in the post HTML5 Input Attributes & Browser Support by Estelle Weyl.

Viewport Dimensions & Orientation

When modern mobile devices render a webpage, they scale the page content to fit inside their viewport, or visible area. Although the default viewport dimensions work well for most layouts, it is sometimes useful to alter the viewport. This can be accomplished using a <meta> tag that was introduced by Apple and has since been picked up by other device manufacturers. In the document’s <head> include this snippet:

<meta name="viewport" content="width=320" />

In this example we’ve set the viewport to 320, which means that 320 pixels of the page will be visible across the width of the device.

The viewport meta tag can also be used to disable the ability to resize the page:

<meta name="viewport" content="width=320,user-scalable=false" />

However, similar to disabling the scrollbars, this technique takes control away from the user and should only be used for a good reason.

Additionally, it is possible to add certain styles based on the device orientation. This means that different styles can be applied depending on whether the user is holding their phone vertically or horizontally.

To detect the device orientation, we can use a media query similar to the client-side device detection we discussed earlier. Within your stylesheet, include:

@import url("portrait.css") all and
(orientation:portrait);
@import url("landscape.css") all and
(orientation:landscape);

Here portrait.css styles will be added for vertical devices and the landscape.css will be added for horizontal.

However orientation media queries have not been adopted by all devices, so this is best accomplished with the max-width media query. Simply apply different max-width queries for the different orientation widths you want to target. This is a much more robust approach, since presumably the reason to target different orientations is to style for different widths.

Special Concerns For iPhone / iPad

Iphone-41 in How To Build A Mobile Website

With a market share of 28% and estimates of as much as 50% of mobile browsing going through iPhone, it makes sense that developers make special accommodations for the mobile giant.

No Flash

Regardless of Apple’s ethics, the reality is that iPhones do not play Flash unless they are jailbroken. Fortunately, there are alternatives to Flash, and iPhone’s issues with this technology are often easy to get around. The main use for Flash in modern websites is Flash video, which can easily be circumvented using HTML5 video. However since older browsers don’t support HTML5, make sure to include a Flash backup for non-supportive browsers (this is why the whole debate about Flash vs. HTML5 is a bit pointless, because you can actually offer both to your users and the user’s device will pick up the one it can render automatically).

Beyond video, it is usually best to use JavaScript to accommodate any simple functionality. JavaScript libraries such as jQuery make it easy to build rich interactive applications without Flash. Regardless of your desire to support iPhone, these JavaScript apps typically have a number of additional advantages over Flash alternatives.

Finally, certain applications are simply too hard to recreate with HTML5 and Javascript. For these, iPhone users will have to be left out, however make sure to include appropriate alternate content.

Apple-loves-adobe in How To Build A Mobile Website
A spoof of Adobe’s “We Love Apple” campaign, where the heart is replaced by the broken plugin icon.

Other Shortcomings

Besides Flash, there are a few additional caveats to supporting iPhones and iPads.

First, iPhone does not support <input type="file" />, since it does not have an accessible internal file structure. While most mobile devices connect to a computer as an external hard-drive, Apple has taken steps to ensure that the iPhone file structure remains obfuscated.

Next, iPhone will only cache files that are 25 kb or less, so try to keep any reused files under this restriction. This can be a bit counter-intuitive, as it often means breaking out large image sprites and concatenated JavaScripts into smaller chunks. However be careful to serve these files only to iPhone, or it will cause extra HTTP requests in all other browsers.

Finally, when it comes to @font-face font embedding, iPhone’s Mobile Safari doesn’t fully support it and supports the SVG file format instead. However, SVG fonts are only supported by Chrome, Opera and iPhone, so we’ll need a hybrid approach to target all browsers. In addition to the SVG, we’ll need an .otf or .ttf for Firefox and Safari, as well as an EOT for IE (IE has actually supported @font-face since IE4).

After obtaining the necessary files, tie them all together with the appropriate CSS:

@font-face {
    font-family: 'Comfortaa Regular';
    src: url('Comfortaa.eot');
    src: local('Comfortaa Regular'),
         local('Comfortaa'),
         url('Comfortaa.ttf') format('truetype'),
         url('Comfortaa.svg#font') format('svg');
}

For more information, read this article on cross-platform font-face support.

Special iPhone / iPad Enhancements

Despite iPhone’s various shortcomings, the device offers a wonderfully rich user experience that developers can leverage in ways not possible with older mobile devices.

First, there are a variety of JavaScript libraries that can be used to access some of the more advanced functionality available in iPhone. Take a look at Sencha Touch, jQTouch and iui. These three libraries allow you to better interface with the iPhone, and also work on similar devices such as Android. Additionally, keep an eye on the much anticipated jQuery Mobile which has just been released in alpha.

Next, the App Store isn’t the only way to get an icon on your users’ iPhones: you can simply have them bookmark your page. Unfortunately the default bookmark icon is a condensed screen shot of the page, which doesn’t usually look very good, so let’s create a special iPhone icon. Also check the Icon Reference Chart by Jon Hicks for further details.

Start by saving a 57 x 57 pixel PNG somewhere on your website, then add this snippet within your <head> tag:

<link rel="apple-touch-icon" href="/customIcon.png"/>

Don’t worry about rounded corners or a glossy effect, iPhone will add those by default.

Conclusion

As the worldwide shift to mobile continues, handheld device support will become increasingly important. Hopefully this article has left you with both the desire and toolset necessary to make mobile support a reality in your websites.

Although mobile occupies a significant chunk of global web browsing, the technology is still very much in its infancy. Just as standards emerged for desktop browsing, new standards are emerging to unify mobile browsers. This means that the techniques described in this article are only temporary, and it is your responsibility to stay on top of this ever-changing technology.

In fact, the only thing in web development that remains constant is the perpetual need to continue learning!

Additional Reading

Buy our eBook “Mobile Design For iPhone And iPad”!

Ipad-300px in How To Build A Mobile Website

This article is a free sample of our new eBook Mobile Design For iPhone And iPad (just $9.90). This eBook presents articles on professional mobile design for the iPhone as well as the iPad, including studies of trends in mobile design and guidelines for the development of mobile web pages.

These articles are a selection of the best from Smashing Magazine in 2009 and 2010, dealing with mobile design for the iPhone and iPad, plus an exclusive 90-page study about mobile web design trends.

The authors are: Alexander Dawson, Alexander Komarov, Cameron Chapman, Jen Gordon, Jon Raasch, Kim Pimmel, Luke Wroblewski, Marc Edwards, Michael Flarupp, Nick Francis, Rachel Andrew and Steven Snell. Available as a PDF, ePub and Mobipocket formats.

(ik) (vf)


© Jon Raasch for Smashing Magazine, 2010. | Permalink | Post a comment | Add to del.icio.us | Digg this | Stumble on StumbleUpon! | Tweet it! | Submit to Reddit | Forum Smashing Magazine
Post tags: , ,


Five Useful CSS/jQuery Coding Techniques For More Dynamic Websites

Smashing-magazine-advertisement in Five Useful CSS/jQuery Coding Techniques For More Dynamic WebsitesSpacer in Five Useful CSS/jQuery Coding Techniques For More Dynamic Websites
 in Five Useful CSS/jQuery Coding Techniques For More Dynamic Websites  in Five Useful CSS/jQuery Coding Techniques For More Dynamic Websites  in Five Useful CSS/jQuery Coding Techniques For More Dynamic Websites

Interactivity can transform a dull static website into a dynamic tool that not only delights users but conveys information more effectively. In this post, we’ll walk through five different coding techniques that can be easily implemented on any website to provide a richer user experience.

The techniques will allow you to better display difficult content, help users find information more effectively and provide meaningful UI cues without overwhelming the user.

  1. On-page text search
  2. Drag controls for oversized content
  3. Subtle hover effects
  4. Comment count bars
  5. Full-page slider

[Offtopic: by the way, did you know that there is a Smashing eBook Series? Book #2 is Successful Freelancing for Web Designers, 260 pages for just $9,90.]

1. On-Page Text Search

E-read-search-instant in Five Useful CSS/jQuery Coding Techniques For More Dynamic Websites

Websites often have search boxes to allow users to find content from their archives. But what if you want to find content on the given page? Information Architects has had on-page text search that provides a great user experience. Let’s recreate this using jQuery.

Mark-Up and Interaction

First let’s build an input box for the search:

<input type="text" id="text-search" />

Next we’ll need jQuery to attach a listener to track changes to the input box:

$(function() {
    $('#text-search').bind('keyup change', function(ev) {
        // pull in the new value
        var searchTerm = $(this).val();
    )};
});

Here we bound our function to both the keyup and change events. This ensures that our operation fires regardless of whether the user types or pastes the text.

Now, let’s turn to Highlight, a useful and lightweight jQuery plug-in that handles text highlighting. After including the plug-in source, let’s add a highlight() call to our JavaScript:

$(function() {
    $('#text-search').bind('keyup change', function(ev) {
        // pull in the new value
        var searchTerm = $(this).val();

        // disable highlighting if empty
        if ( searchTerm ) {
            // highlight the new term
            $('body').highlight( searchTerm );
        }
    });
});

In addition to highlighting the given text, we’ve also added a check to make sure the search term isn’t empty (which causes an infinite loop).

This snippet highlights the search query throughout the page, but we can also limit the scope to a given id:

$('#myId').highlight( searchTerm );

Or we can search only within a certain element:

$('p').highlight( searchTerm );

This text highlighting by default is case insensitive. If you’d prefer case-sensitive highlighting, remove the .toUpperCase() on both lines 21 and 41 of the Highlight plug-in.

Styling the Highlighted Text

Now that the JavaScript is attached, we’ll need to style our highlighted items. The Highlight plug-in wraps the highlighted terms in <span class="highlight"></span>, which we can style with CSS.

First, let’s change the background color and then add rounded corners and a drop-shadow for all browsers except IE:

.highlight {
    background-color: #fff34d;
    -moz-border-radius: 5px; /* FF1+ */
    -webkit-border-radius: 5px; /* Saf3-4 */
    border-radius: 5px; /* Opera 10.5, IE 9, Saf5, Chrome */
    -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.7); /* FF3.5+ */
    -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.7); /* Saf3.0+, Chrome */
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.7); /* Opera 10.5+, IE 9.0 */
}

Although the highlighting is now visible, it still appears a bit tight around the text and could use some padding. But we’ll have to be careful not to adjust the layout of text. These spans are inline elements, and if we simply add padding, the text will shift around on the page. So, let’s include padding with a negative margin to compensate:

.highlight {
    padding:1px 4px;
    margin:0 -4px;
}

Finishing the Interaction

Last but not least, let’s make sure to remove the highlighted text whenever the user edits text in the input box:

$(function() {
    $('#text-search').bind('keyup change', function(ev) {
        // pull in the new value
        var searchTerm = $(this).val();

        // remove any old highlighted terms
        $('body').removeHighlight();

        // disable highlighting if empty
        if ( searchTerm ) {
            // highlight the new term
            $('body').highlight( searchTerm );
        }
    });
});

Here we added a call to remove any text highlighting, which is performed outside of the empty field check. This ensures that the highlight is also removed if the user clears the field.

Although removeHighlight() works well in most browsers, it will crash IE6. This is due to an IE6 bug with node.normalize().

We can get the Highlight plug-in working in IE6 by rewriting this function. Simply replace lines 45-53 of highlight.js with the following:

jQuery.fn.removeHighlight = function() {
 function newNormalize(node) {
    for (var i = 0, children = node.childNodes, nodeCount = children.length; i < nodeCount; i++) {
        var child = children[i];
        if (child.nodeType == 1) {
            newNormalize(child);
            continue;
        }
        if (child.nodeType != 3) { continue; }
        var next = child.nextSibling;
        if (next == null || next.nodeType != 3) { continue; }
        var combined_text = child.nodeValue + next.nodeValue;
        new_node = node.ownerDocument.createTextNode(combined_text);
        node.insertBefore(new_node, child);
        node.removeChild(child);
        node.removeChild(next);
        i--;
        nodeCount--;
    }
 }

 return this.find("span.highlight").each(function() {
    var thisParent = this.parentNode;
    thisParent.replaceChild(this.firstChild, this);
    newNormalize(thisParent);
 }).end();
};

This new function replaces the standard Javascript normalize() with a custom function that works in all browsers.

Download the complete example.

2. Drag Controls For Oversized Content

Moscow in Five Useful CSS/jQuery Coding Techniques For More Dynamic Websites

When layout constraints bump up against the need for large images, finding a quality solution can be difficult. Mospromstroy uses a creative technique to handle this situation: a "drag and drop" control bar that allows users to pan through images.

We can accomplish something similar using jQuery UI's draggable behavior.

Mark-Up and CSS

First let's set up some mark-up for the content and controls:

<div id="full-sized-area">
    <div id="full-sized-content">
    Your content here
    </div>
</div>

<div id="drag-controls-area">
    <div id="drag-controls"></div>
</div>

Next, let's apply some basic CSS:

#full-sized-area {
    position: relative;
    overflow: hidden;
    width: 800px;
    height: 400px;
}

#full-sized-content {
    position: absolute;
    top: 0;
    left: 0;
}

#drag-controls-area {
    position: relative;
    width: 300px;
    height: 50px;
}

#drag-controls {
    position: absolute;
    top: 0;
    left: 0;
    height: 48px;
    border: 1px solid white;
}

Here we applied an absolute position to both the #full-sized-content and #drag-controls, and we also hid any overflow from the large image. Additionally, we applied some arbitrary dimensions to the content and drag controls wrappers; make sure to adjust these as needed.

Building Interactivity With jQuery

Now, let's use jQuery UI to build the interaction. Begin by including jQuery UI with the draggable module.

Before attaching the controls, let's resize the drag control box to the right dimensions:

$(function() {
    var $fullArea = $('#full-sized-area');
    var $fullContent = $('#full-sized-content', $fullArea);

    // find what portion of the content is displayed
    var contentRatio = $fullArea.width() / $fullContent.width();

    // scale the controls box
    var $controlsArea = $('#drag-controls-area');
    var $controls = $('#drag-controls', $controlsArea);

    $controls.css('width', $controlsArea.width() * contentRatio);
});

Here, we've determined what portion of the content is visible in the content area and then scaled the width of the control box accordingly.

Next, let's attach the draggable behavior:

$(function() {
    var $fullArea = $('#full-sized-area');
    var $fullContent = $('#full-sized-content', $fullArea);

    // find what portion of the content is displayed
    var contentRatio = $fullArea.width() / $fullContent.width();

    // scale the controls box
    var $controlsArea = $('#drag-controls-area');
    var $controls = $('#drag-controls', $controlsArea);

    $controls.css('width', $controlsArea.width() * contentRatio);

    // determine the scale difference between the controls and content
    var scaleRatio = $controlsArea.width() / $fullContent.width();

    // attach the draggable behavior
    $controls.draggable({
        axis : 'x', // confine dragging to the x-axis
        containment : 'parent',
        drag : function(ev, ui) {
            // move the full sized content
            $fullContent.css('left', -1 * ui.position.left / scaleRatio );
        }
    });
});

Here, we've attached a draggable event and set a couple options. First, we set axis to restrict dragging to the x-axis, and then we set containment to confine dragging to the parent element (i.e. the controls wrapper).

Finally, we set up a drag listener to move the full-sized content according to how far the user has dragged the control. For this, we negatively positioned the content to the left by the drag amount multiplied by the ratio of the controls to the content.

Custom Cursors

The draggable content is working, but we still have room for improvement.

First let's add some more styling to the control box to make it more interactive. jQuery UI's draggable attaches two class names that we can use for this: ui-draggable and ui-draggable-dragging.

#drag-controls.ui-draggable {
    cursor: -moz-grab !important;
    cursor: -webkit-grab !important;
    cursor: e-resize;
}

#drag-controls.ui-draggable-dragging {
    cursor: -moz-grabbing !important;
    cursor: -webkit-grabbing !important;
    border-color: yellow;
}

In addition to applying a new border color to the active controls, this snippet also attaches a number of cursor properties, which use proprietary UI cursors available in Firefox and Safari, with a back-up for IE.

Because of the implementation of the cursor property, we had to "bootstrap" this together using !important. This ensures that the proprietary cursors are used if available, while allowing the default cursor to overwrite them in IE. Unfortunately, Chrome does not currently support -webkit-grab, so we leave it out of this implementation. If you'd prefer to use the back-up e-resize cursor in both Chrome and Safari, just remove the -webkit-grab and -webkit-grabbing properties.

Parallax Effect

Let's make the sliding animation more three-dimensional by adding a two-layer parallax effect. To do so, we simply add a background to our full-sized content area and animate it at a slower rate.

Add the mark-up first:

<div id="full-sized-area">
    <div id="full-sized-background">
    Your background here
    </div>

    <div id="full-sized-content">
    Your content here
    </div>
</div>

<div id="drag-controls-area">
    <div id="drag-controls"></div>
</div>

And then some basic styling:

#full-sized-background {
    position: absolute;
    top: 0;
    left: 0;
}

Here, we use absolute positioning to lock the background in place. Note that we did not need to attach a z-index, because we placed the background element before the content area in the mark-up.

Finally, let's add the background animation to our drag event:

    $fullBackground = $('#full-sized-background');

    $controls.draggable({
        axis : 'x', // confine dragging to the x-axis
        containment : 'parent',
        drag : function(ev, ui) {
            // move the full sized content
            var newContentPosition = -1 * ui.position.left / scaleRatio;
            $fullContent.css('left', newContentPosition);

            // move the background
            $fullBackground.css('left', newContentPosition * .4);
        }
    });

Here, we simply used the new position that we calculated for the main content and applied 40% of that change to the background. Adjust this value to change the speed of the parallax.

Download the complete example.

3. Subtle Hover Effects

Veerle in Five Useful CSS/jQuery Coding Techniques For More Dynamic Websites

Veerle's blog uses subtle transitions to create a natural feel for mouse interactions. These can be easily accomplished using CSS3's transition property (and a jQuery back-up for unsupported browsers).

First, let's attach some CSS with the class subtle to all elements:

.subtle {
    background-color: #78776C;
    color: #BBBBAD;
}

.subtle:hover, .subtle:focus {
    background-color: #F6F7ED;
    color: #51514A;
}

Here, we've styled these elements with a background and text color and included a hover state using the pseudo-class :hover. Additionally, we included the :focus pseudo-class for active input and text-area elements.

This CSS causes the style to change immediately on hover, but we can apply a smoother transition using CSS3:

.subtle {
    -webkit-transition: background-color 500ms ease-in; /* Saf3.2+, Chrome */
    -moz-transition: background-color 500ms ease-in; /* FF3.7+ */
    -o-transition: background-color 500ms ease-in; /* Opera 10.5+ */
    transition: background-color 500ms ease-in; /* futureproofing */
    background-color: #78776C;
    color: #BBBBAD;
}

.subtle:hover, .subtle:focus {
    background-color: #F6F7ED;
    color: #51514A;
}

Here, we've attached a CSS3 transition that works in all modern browsers except IE. The transition property consists of three different values. The first is the CSS property to animate, and the second is the duration of the animation—in our case, background-color and 500 milliseconds, respectively. The third value allows us to specify an easing function, such as ease-in or linear.

jQuery Back-Up

Our subtle transitions now work across a variety of browsers, but let's include support for all users by leveraging a jQuery back-up technique.

First we'll need to detect whether the user's browser supports transition:

// make sure to execute this on page load
$(function() {
    // determine if the browser supports transition
    var thisStyle = document.body.style,
    supportsTransition = thisStyle.WebkitTransition !== undefined ||
        thisStyle.MozTransition !== undefined ||
        thisStyle.OTransition !== undefined ||
        thisStyle.transition !== undefined;
});

Here, we check whether the body element can use any of the browser-specific transition properties that we defined above.

If the browser doesn't support transition, we can apply the animation using jQuery. However, jQuery's animate() function does not natively support color-based animations. To accommodate our background-color animation, we'll have to include a small chunk of jQuery UI: the effects core.

After including jQuery UI, we'll need to attach the animation to the hover and focus event listeners:

// make sure to execute this on page load
$(function() {
    // determine if the browser supports transition
    var thisStyle = document.body.style,
    supportsTransition = thisStyle.WebkitTransition !== undefined ||
        thisStyle.MozTransition !== undefined ||
        thisStyle.OTransition !== undefined ||
        thisStyle.transition !== undefined;

    // assign jQuery transition if the browser doesn't support
    if ( ! supportsTransition ) {
        var defaultCSS = {
            backgroundColor: '#78776C'
        },
        hoverCSS = {
            backgroundColor: '#F6F7ED'
        };

        // loop through each button
        $('.subtle').each(function() {
            var $subtle = $(this);

            // bind an event listener for mouseover and focus
            $subtle.bind('mouseenter focus', function() {
                $subtle.animate(hoverCSS, 500, 'swing' );
            });

            // bind the reverse for mouseout and blur
            $subtle.bind('mouseleave blur', function(ev) {
                if ( ev.type == 'mouseleave' && ev.target == document.activeElement ) return false;

                $subtle.animate(defaultCSS, 500, 'swing' );
            });
        });
    }
});

Here, we recreated the transition using jQuery's animate(). Notice how we used values that are to the CSS3 transition—500 specifies 500 milliseconds, and swing specifies an easing method that is close to ease-in.

While the mouse-over and focus event is fairly straightforward, notice the difference in the mouse-out and blur event. We added some code to end the function if the element is in focus. This retains the active state even if the user moves their mouse. jQuery's is() method does not support the :focus pseudo-class, so we have to rely on DOM's document.activeElement.

Download the complete example.

4. Comment Count Bars

Most-commented in Five Useful CSS/jQuery Coding Techniques For More Dynamic Websites

IT Expert Voice uses a nice method for displaying the "Most commented" posts in its sidebar. Let's recreate this using WordPress and a bit of CSS and jQuery (non-WordPress users can skip the first section).

Pulling Posts With WordPress

Let's start by pulling in the top-five most-commented posts:

<?php $most_commented = new WP_Query('orderby=comment_count&posts_per_page=5'); ?>

Here, we used WP_Query and a custom variable name so as not to disrupt any other post loops on the page.

Next, let's loop through the posts we've selected, outputting each as a list item:

<ul id="most-commented">

<?php $most_commented = new WP_Query('orderby=comment_count&posts_per_page=5'); ?>
	<?php while ($most_commented->have_posts()) : $most_commented->the_post(); ?>	

	<li>
	<a href="<?php the_permalink() ?>" rel="bookmark" title="<?php the_title_attribute(); ?>"><?php the_title(); ?></a>

	<span class="comment-bar"><span class="comment-count"><?php comments_number('0','1','%'); ?></span></span>
	</li>

<?php endwhile; ?>

</ul>

Here, we used a while() loop to run through each post. First, we output a link to the post using the_permalink() and the_title(), and then we output the comment count using comments_number() and some additional mark-up for styling.

Basic CSS Styling

Let's style the basic layout of the comments list using CSS:

#most-commented li {
    list-style: none;
}

#most-commented a {
    display: block;
}

We've removed any list styling and defined the links as a block element so that they stay separate from our comment bar visualizations.

Let's set up some base styles for the comment bar and comment count:

#most-commented .comment-bar {
    display: inline-block;
    position: relative;
    height: 30px;
    width: 0;
    margin: 5px 0;
    padding-left: 20px;
    background-color: #999;
}

#most-commented .comment-count {
    display: inline-block;
    position: absolute;
    right: -20px;
    top: -5px;
    width: 34px;
    height: 34px;
    border-width: 3px;
    border-style: solid;
    border-color: #FFF;
    -moz-border-radius: 20px;
    -webkit-border-radius: 20px;
    border-radius: 20px;
    text-align: center;
    line-height: 34px;
    background-color: #6CAC1F;
    font-size: 13px;
    font-weight: bold;
    color: #FFF;
}

Most of this styling is arbitrary, so feel free to attach a background image or otherwise tweak it to fit your theme. The main thing is to align the comment count to the right of the comment bar so that we can adjust the width of the bar at will.

Pay attention to the total width of the comment count, in our case 40px (34px wide plus 3px for the left and right borders). We're using half of that value to position the comment count: 20px of negative positioning so that the count hangs on the right, and 20px of left padding so that the comment bar reaches the center of the comment count.

Tying It All Together With jQuery

Finally, let's use jQuery to set the widths of the individual bars. We'll start by looping through the comments after the page loads:

$(function() {
    $('#most-commented li').each(function(i) {
        var $this = $(this);
        var thisCount = ~~$this.find('.comment-count').text();
    });
});

We loop through all of the <li> elements, pulling out the comment count from the mark-up. Notice that we've used the primitive data type ~~ to convert the text to an integer. This is significantly faster than alternatives such as parseInt().

Let's set up some key variables in the first iteration of our loop:

$(function() {
    // define global variables
    var maxWidth, maxCount;

    $('#most-commented li').each(function(i) {
        var $this = $(this);
        var thisCount = ~~$this.find('.comment-count').text();

        // set up some variables if the first iteration
        if ( i == 0 ) {
            maxWidth = $this.width() - 40;
            maxCount = thisCount;
        }
    });
});

Here, we started by defining variables outside of the each() loop. This allows us to use these values in every iteration.

Next, we subtracted 40 pixels from the width of the list item to define a maximum width for the comment bar. The 40 pixels compensate for the left-padding and negative position that we applied above.

We also set maxCount to the first value. Because we initially pulled the posts according to their number of comments, we can be sure that the first item will have the highest count.

Finally, let's calculate the width of each bar and animate the transition:

$(function() {
    // define global variables
    var maxWidth, maxCount;

    $('#most-commented li').each(function(i) {
        var $this = $(this);
        var thisCount = ~~$this.find('.comment-count').text();

        // set up some variables if the first iteration
        if ( i == 0 ) {
            maxWidth = $this.width() - 40;
            maxCount = thisCount;
        }

        // calculate the width based on the count ratio
        var thisWidth = (thisCount / maxCount) * maxWidth;

        // apply the width to the bar
        $this.find('.comment-bar').animate({
            width : thisWidth
        }, 200, 'swing');
    });
});

If you'd rather style the elements without any animation, simply replace the animate() with a static css().

Download the complete example.

5. Full-Page Slider

Wine-jax in Five Useful CSS/jQuery Coding Techniques For More Dynamic Websites

Sliding animation is an interactive way to show related content. But JAX Vineyards takes the standard sliding gallery to the next level by animating across the entire page. Let's create a similar effect using jQuery.

Mark-Up and CSS

Start by adding the mark-up:

<div id="full-slider-wrapper">
    <div id="full-slider">

        <div class="slide-panel active">
        Panel 1 content here
        </div>

        <div class="slide-panel">
        Panel 2 content here
        </div>

        <div class="slide-panel">
        Panel 3 content here
        </div>
    </div>
</div>

We set up the basic mark-up and wrappers that we need for the animation. Make sure that the full-slider-wrapper is not contained in any element that is narrower than the browser window—we'll need the full width of the browser to pull off the effect.

Now, let's add some basic CSS to handle overflow and to position the panels:

html {
    min-width: 800px;
}

#full-slider-wrapper {
    overflow: hidden;
}

#full-slider {
    position: relative;
    width: 800px;
    height: 600px;
    margin: 0 auto;
}

#full-slider .slide-panel {
    position: absolute;
    top: 0;
    left: 0;
    width: 800px;
    height: 600px;
    visibility: hidden;
}

#full-slider .slide-panel.active {
    visibility: visible;
}

We defined absolute positioning and set up some arbitrary dimensions for the panels and wrapper. Feel free to tweak these dimensions to your content.

We also attached overflow: hidden to our wrapper element, which will prevent scroll bars from appearing when we animate the panels. Because we hid the overflow, we also had to assign a min-width to the html document. This ensures that the content will get scroll bars if the browser window is too small.

Finally, we used the active class that we established in the mark-up to show the first panel.

jQuery Animation

Let's build the interaction using jQuery. We'll start by defining some variables and then create a function to handle the sliding animation in both directions:

$(function() {
    var $slider = $('#full-slider');
    var $sliderPanels = $slider.children('.slide-panel');

    function slidePanel( newPanel, direction ) {
        // define the offset of the slider obj, vis a vis the document
        var offsetLeft = $slider.offset().left;

        // offset required to hide the content off to the left / right
        var hideLeft = -1 * ( offsetLeft + $slider.width() );
        var hideRight = $(window).width() - offsetLeft;

        // change the current / next positions based on the direction of the animation
        if ( direction == 'left' ) {
            currPos = hideLeft;
            nextPos = hideRight;
        }
        else {
            currPos = hideRight;
            nextPos = hideLeft;
        }

        // slide out the current panel, then remove the active class
        $slider.children('.slide-panel.active').animate({
            left: currPos
        }, 500, function() {
            $(this).removeClass('active');
        });

        // slide in the next panel after adding the active class
        $( $sliderPanels[newPanel] ).css('left', nextPos).addClass('active').animate({
            left: 0
        }, 500 );
    }
});

Here our slidePanel() function accepts two arguments: the index of the panel that we want to slide into view, and the direction of the slide (i.e. left or right).

Although this function looks complicated, the concepts are fairly simple. We determined the amount of offset necessary to hide the panels on the left and right sides. To calculate these values, we used jQuery's offset() and the slider and window widths. These offsets represent the left position values needed to hide the content on either side.

Next, we have a switch based on the direction of the animation, which uses the two values we defined previously.

Finally, we trigger the animation using jQuery's animate(). We slide the active panel out of view and then remove the active class once the animation completes. Then we set the new panel's left position off the screen, attach the active class to make it visible and slide it into place.

Building the Controls

Our function now handles the animation, but we still have to build controls to leverage it.

Append navigation elements to the slider object that we defined previously:

    var $navWrap = $('<div id="full-slider-nav"></div>').appendTo( $slider );
    var $navLeft = $('<div id="full-slider-nav-left"></div>').appendTo( $navWrap );
    var $navRight = $('<div id="full-slider-nav-right"></div>').appendTo( $navWrap );

We could have included this navigation in the initial mark-up, but we're appending it with JavaScript for two reasons: it ensures that the navigation won't appear until the JavaScript is loaded, and it keeps the navigation from being displayed on the off chance that JavaScript isn't enabled.

Let's style the navigation:

#full-slider-nav {
    position: absolute;
    top: 0;
    right: 0;
}

#full-slider-nav-left, #full-slider-nav-right {
    display: inline-block;
    height: 0;
    width: 0;
    margin-left: 15px;
    border: 20px solid transparent;
    cursor: pointer;
}

#full-slider-nav-left {
    border-right-color: #BBB;
}

#full-slider-nav-left:hover {
    border-right-color: #999;
}

#full-slider-nav-right {
    border-left-color: #BBB;
}

#full-slider-nav-right:hover {
    border-left-color: #999;
}

Here we absolute position the navigation to the top right. We also use a CSS triangle trick to quickly style the controls.

Let's attach our new slider navigation to the slidePanel() function that we defined previously:

    var $navWrap = $('<div id="full-slider-nav"></div>').appendTo( $slider );
    var $navLeft = $('<div id="full-slider-nav-left"></div>').appendTo( $navWrap );
    var $navRight = $('<div id="full-slider-nav-right"></div>').appendTo( $navWrap );

    var currPanel = 0;

    $navLeft.click(function() {
        currPanel--;

        // check if the new panel value is too small
        if ( currPanel < 0 ) currPanel = $sliderPanels.length - 1;

        slidePanel(currPanel, 'right');
    });

    $navRight.click(function() {
        currPanel++;

        // check if the new panel value is too big
        if ( currPanel >= $sliderPanels.length ) currPanel = 0;

        slidePanel(currPanel, 'left');
    });

This snippet assigns click events to the left and right navigation. In each, we change the value of currPanel according to the direction. If this new value falls outside of the available panels, we loop to the other end of our set. Finally, we trigger the slidePanel() function with the new panel and appropriate direction.

In our example, we built controls only for left and right navigation, but you could easily tweak this to have buttons for each panel. Simply pass the correct panel index to slidePanel.

Let's bring all the jQuery code together:

$(function() {
    function slidePanel( newPanel, direction ) {
        // define the offset of the slider obj, vis a vis the document
        var offsetLeft = $slider.offset().left;

        // offset required to hide the content off to the left / right
        var hideLeft = -1 * ( offsetLeft + $slider.width() );
        var hideRight = $(window).width() - offsetLeft;

        // change the current / next positions based on the direction of the animation
        if ( direction == 'left' ) {
            currPos = hideLeft;
            nextPos = hideRight;
        }
        else {
            currPos = hideRight;
            nextPos = hideLeft;
        }

        // slide out the current panel, then remove the active class
        $slider.children('.slide-panel.active').animate({
            left: currPos
        }, 500, function() {
            $(this).removeClass('active');
        });

        // slide in the next panel after adding the active class
        $( $sliderPanels[newPanel] ).css('left', nextPos).addClass('active').animate({
            left: 0
        }, 500 );
    }

    var $slider = $('#full-slider');
    var $sliderPanels = $slider.children('.slide-panel');

    var $navWrap = $('<div id="full-slider-nav"></div>').appendTo( $slider );
    var $navLeft = $('<div id="full-slider-nav-left"></div>').appendTo( $navWrap );
    var $navRight = $('<div id="full-slider-nav-right"></div>').appendTo( $navWrap );

    var currPanel = 0;

    $navLeft.click(function() {
        currPanel--;

        // check if the new panel value is too small
        if ( currPanel < 0 ) currPanel = $sliderPanels.length - 1;

        slidePanel(currPanel, 'right');
    });

    $navRight.click(function() {
        currPanel++;

        // check if the new panel value is too big
        if ( currPanel >= $sliderPanels.length ) currPanel = 0;

        slidePanel(currPanel, 'left');
    });
});

Download the complete example.

Final Thoughts

In this post we walked through a variety of methods for adding dynamic functionality to your websites. These techniques can be easily adapted to work with almost any site. The majority of these techniques rely on jQuery to provide interaction, but there are plenty of other approaches, both with and without jQuery. Please post any alternate solutions in the comments below, or fork the example files on github.

Furthermore, these five methods represent only a small portion of interactive techniques. Please post any links to other dynamic techniques and functionality in the comments below.

Related Posts

You may be interested in the following related posts:

(al)


© Jon Raasch for Smashing Magazine, 2010. | Permalink | Post a comment | Add to del.icio.us | Digg this | Stumble on StumbleUpon! | Tweet it! | Submit to Reddit | Forum Smashing Magazine
Post tags: ,


jQuery Plugin Checklist: Should You Use That jQuery Plug-In?

Smashing-magazine-advertisement in jQuery Plugin Checklist: Should You Use That jQuery Plug-In?Spacer in jQuery Plugin Checklist: Should You Use That jQuery Plug-In?
 in jQuery Plugin Checklist: Should You Use That jQuery Plug-In?  in jQuery Plugin Checklist: Should You Use That jQuery Plug-In?  in jQuery Plugin Checklist: Should You Use That jQuery Plug-In?

jQuery plug-ins provide an excellent way to save time and streamline development, allowing programmers to avoid having to build every component from scratch. But plug-ins are also a wild card that introduce an element of uncertainty into any code base. A good plug-in saves countless development hours; a bad plug-in leads to bug fixes that take longer than actually building the component from scratch.

Fortunately, one usually has a number of different plug-ins to choose from. But even if you have only one, figure out whether it’s worth using at all. The last thing you want to do is introduce bad code into your code base.

[Offtopic: by the way, did you know that we are publishing a Smashing eBook Series? The brand new eBook #3 is Mastering Photoshop For Web Design, written by our Photoshop-expert Thomas Giannattasio.]

Do You Need A Plug-In At All?

The first step is to figure out whether you even need a plug-in. If you don’t, you’ll save yourself both file size and time.

1. Would Writing It Yourself Be Better?

If the functionality is simple enough, you could consider writing it yourself. jQuery plug-ins often come bundled with a wide variety of features, which might be overkill for your situation. In these cases, writing any simple functionality by hand often makes more sense. Of course, the benefits have to be weighed against the amount of work involved.

For example, jQuery UI’s accordion is great if you need advanced functionality, but it might be overkill if you just need panels that open and close. If you don’t already use jQuery UI elsewhere on your website, consider instead the native jQuery slideToggle() or animate().

2. Is It Similar to a Plug-In You’re Already Using?

After discovering that a particular plug-in doesn’t handle everything you need, finding another plug-in to cover loose ends might be tempting. But including two similar plug-ins in the same app is a sure path to bloated JavaScript.

Can you find a single plug-in that covers everything you need? If not, can you extend one of the plug-ins you have to cover everything you need? Again, in deciding whether to extend a plug-in, weigh the benefits against the development time involved.

For example, jQuery lightbox is a nice way to enable pop-up photos in a gallery, and simpleModal is a great way to display modal messages to users. But why would you use both on the same website? You could easily extend one to cover both uses. Better yet, find one plug-in that covers everything, such as Colorbox.

3. Do You Even Need JavaScript?

In some situations, JavaScript isn’t needed at all. CSS pseudo-selectors such as :hover and CSS3 transitions can cover a variety of dynamic functionality much faster than a comparable JavaScript solution. Also, many plug-ins apply only styling; doing this with mark-up and CSS might make more sense.

For example, plug-ins such as jQuery Tooltip are indispensable if you have dynamic content that requires well-placed tooltips. But if you use tooltips in only a few select locations, using pure CSS is better (see this example). You can take static tooltips a step further by animating the effect using a CSS3 transition, but bear in mind that the animation will work only in certain browsers.

Avoid Red Flags

When reviewing any plug-in, a number of warning signs will indicate poor quality. Here, we’ll look at all aspects of plug-ins, from the JavaScript to the CSS to the mark-up. We’ll even consider how plug-ins are released. None of these red flags alone should eliminate any plug-in from consideration. You get what you pay for, and because you’re probably paying nothing, you should be willing to cut any one a bit of slack.

If you’re fortunate enough to have more than one option, these warning signs could help you narrow down your choice. But even if you have only one option, be prepared to forgo it if you see too many red flags. Save yourself the headache ahead of time.

4. Weird Option or Argument Syntax

After using jQuery for a while, developers get a sense of how most functions accept arguments. If a plug-in developer uses unusual syntax, it stands to reason that they don’t have much jQuery or JavaScript experience.

Some plug-ins accept a jQuery object as an argument but don’t allow chaining from that object; for example, $.myPlugin( $('a') ); but not $('a').myPlugin(); This is a big red flag.

A green flag would be a plug-in in this format…

$('.my-selector').myPlugin({
 opt1 : 75,
 opt2 : 'asdf'
});

… that also accepts…

$.myPlugin({
 opt1 : 75,
 opt2 : 'asdf'
}, $('.my-selector'));

5. Little to No Documentation

Without documentation, a plug-in can be very difficult to use, because that is the first place you look for answers to your questions. Documentation comes in a variety of formats; proper documentation is best, but well-commented code can work just as well. If documentation doesn’t exist or is just a blog post with a quick example, then you might want to consider other options.

Good documentation shows that the plug-in creator cares about users like you. It also shows that they have dug into other plug-ins enough to know the value of good documentation.

6. Poor History of Support

Lack of support indicates that finding help will be difficult when issues arise. More tellingly, it indicates that the plug-in has not been updated in a while. One advantage of open-source software is all of the eye-balls that are debugging and improving it. If the author never speaks to these people, the plug-in won’t grow.

When was the last time the plug-in you’re considering was updated? When was the last time a support request was answered? While not all plug-ins need as robust a support system as the jQuery plug-ins website, be wary of plug-ins that have never been modified.

A documented history of support, in which the author has responded to both bug and enhancement requests, is a green flag. A support forum further indicates that the plug-in is well supported, if not by the author then at least by the community.

7. No Minified Version

Though a fairly minor red flag, if the plug-in’s creator doesn’t provide a minified version along with the source code, then they may not be overly concerned with performance. Sure, you could minify it yourself, but this red flag isn’t about wasted time: it’s about the possibility that the plug-in contains far worse performance issues.

On the other hand, providing a minified, packed and gzipped version in the download package is an indication that the author cares about JavaScript performance.

8. Strange Mark-Up Requirements

If a plug-in requires mark-up, then the mark-up should be of high quality. It should make semantic sense and be flexible enough for your purposes. Besides indicating poor front-end skills, strange mark-up makes integration more difficult. A good plug-in plugs into just about any mark-up you use; a bad plug-in makes you jump through hoops.

In certain situations, more rigid mark-up is needed, so be prepared to judge this on a sliding scale. Basically, the more specific the functionality, the more specific the mark-up needed. Completely flexible mark-up that descends naturally from any jQuery selector is the easiest to integrate.

9. Excessive CSS

Many jQuery plug-ins come packaged with CSS, and the quality of the style sheets is just as important as the JavaScript. An excessive number of styles is a sure sign of bad CSS. But what constitutes “excessive” depends on the purpose of the plug-in. Something very display-heavy, such as a lightbox or UI plug-in, will need more CSS than something that drives a simple animation.

Good CSS styles a plug-in’s content effectively while allowing you to easily modify the styles to fit your theme.

10. No One Else Uses It

With the sheer volume of jQuery users, most decent plug-ins will probably have something written about them, even if it’s a “50 jQuery [fill in the blank]” post. Do a simple Google search for the plug-in. If you get very few results, you might want to consider another option, unless the plug-in is brand new or you can verifiy that it is written by a professional.

Posts on prominent blogs are great, and posts by prominent jQuery programmers are even better.

Final Assessment

After you’ve given the plug-in the third degree, the only thing left to do is plug it in and test how well it performs.

11. Plug It In and See

Probably the best way to test a plug-in is to simply plug it on the development server and see the results. First, does it break anything? Make sure to look at JavaScript in the surrounding areas. If the plug-in includes a style sheet, look for layout and styling errors on any page that applies the style sheet.

Additionally, how does the plug-in perform? If it runs slowly or the page lags considerably when loading, it might be important to consider other options.

12. Benchmarking With JSPerf

To take your performance review to the next level, run a benchmark test using JSPerf. Benchmarking basically runs a set of operations a number of times, and then returns an average of how long it took to execute. JSPerf provides an easy way to test how quickly a plug-in runs. This can be a great way to pick a winner between two seemingly identical plug-ins.

Jsperf in jQuery Plugin Checklist: Should You Use That jQuery Plug-In?
An example of a performance test run in jsPerf.

13. Cross-Browser Testing

If a plug-in comes with a lot of CSS, make sure to test the styling in all of the browsers that you want to support. Bear in mind that CSS can be drawn from external style sheets or from within the JavaScript itself.

Even if the plug-in doesn’t have any styling, check for JavaScript errors across browsers anyway (at least in the earliest version of IE that you support). jQuery’s core handles most cross-browser issues, but plug-ins invariably use some amount of pure JavaScript, which tends to break in older browsers.

14. Unit Testing

Finally, you may want to consider taking cross-browser testing even further with unit tests. Unit testing provides a simple way to test individual components of a plug-in in any browser or platform you want to support. If the plug-in’s author has included unit tests in their release, you can bet that all components of the plug-in will work across browsers and platforms.

Unfortunately, very few plug-ins include unit test data, but that doesn’t mean you can’t perform your own test using the QUnit plug-in.

With minimal set-up, you can test whether the plug-in methods return the desired results. If any test fails, don’t waste your time with the plug-in. In most cases, performing your own unit tests is overkill, but QUnit helps you determine the quality of a plug-in when it really counts. For more information on how to use QUnit, see this tutorial

Qunit-example in jQuery Plugin Checklist: Should You Use That jQuery Plug-In?
An example of a unit test run in QUnit.

Conclusion

When assessing the quality of a jQuery plug-in, look at all levels of the code. Is the JavaScript optimized and error-free? Is the CSS tuned and effective? Does the mark-up make semantic sense and have the flexibility you need? These questions all lead to the most important question: will this plug-in be easy to use?

jQuery core has been optimized and bug-checked not only by the core team but by the entire jQuery community. While holding jQuery plug-ins to the same standard would be unfair, they should stand up to at least some of that same scrutiny.

Related Posts

You may be interested in the following related posts:

(al)


© Jon Raasch for Smashing Magazine, 2010. | Permalink | Post a comment | Add to del.icio.us | Digg this | Stumble on StumbleUpon! | Tweet it! | Submit to Reddit | Forum Smashing Magazine
Post tags: , ,


  •   
  • Copyright © 1996-2010 BlogmyQuery - BMQ. All rights reserved.
    iDream theme by Templates Next | Powered by WordPress