CSS

Create An Animated Bar Graph With HTML, CSS And jQuery





 



 


People in boardrooms across the world love a good graph. They go nuts for PowerPoint, bullet points and phrases like “run it up the flagpole,� “blue-sky thinking� and “low-hanging fruit,� and everything is always “moving forward.� Backwards is not an option for people who facilitate paradigm shifts in the zeitgeist. Graphs of financial projections, quarterly sales figures and market saturation are a middle-manager’s dream.

screenshot

How can we as Web designers get in on all of this hot graph action? There are actually quite a few ways to display graphs on the Web. We could simply create an image and nail it to a Web page. But that’s not very accessible or interesting. We could use Flash, which is quite good for displaying graphs — but again, not very accessible. Besides, designers, developers and deities are falling out of love with Flash. Technologies such as HTML5 can do many of the same things without the need for a plug-in. The new HTML5 <canvas> element could even be adapted to the task. Plenty of charting tools are online that we might use. But what if we wanted something a little more tailored?

There are pros and cons to the wide range of resources available to us, but this tutorial will not explore them all. Instead, we’ll create our graph using a progressively enhanced sprinkling of CSS3 and jQuery. Because we can.

What Are We Making?

We’re making this. And more! Here are some possibilities on how you can extend the techniques explored in this tutorial:

  • A progress bar that indicates how long until the end of all humanity in the event of a zombie plague;
  • A graph indicating the decline in safe outdoor activities during a zombie plague;
  • A frighteningly similar graph indicating the decline in manners during a zombie plague;
  • The increase of people who were unaware of the zombie plague because they were sharing with all of their now-deceased friends on Facebook what they did on FarmVille.

Or you could create a graph or quota bar that simply illustrates something useful and less full of dread and zombies. So, let’s get on with it.

What You’ll Need

  • A text or HTML editor. Take your pick; many are out there.
  • jQuery. Practice safe scripting and get the latest one. Keep the jQuery website open so that you can look up the documentation as you go.
  • Possibly an image editor, such as Paint, to mock up what your graph might look like.
  • A modern and decent Web browser to preview changes.

That should do it. Please note that this tutorial is not designed as an introduction to either HTML, CSS, jQuery or zombies. Some intermediate knowledge of these three technologies and the undead is assumed.

The Mark-Up

You can create the underlying HTML for a graph in a number of ways. In this tutorial, we’ll start with a table, because it will make the most sense visually if JavaScript or CSS is not applied. That’s a big checkmark in the column for accessibility.

Quick! You’ve just been given some alarming figures. The population of tanned zombies is projected to spiral out of control in the next few years. The carbon tigers and blue monkeys are under immediate threat. Then the tanned zombies will probably come for us. But you’re just a designer. What could you possibly do to help?

I know! You could make a Web page that illustrates our imminent demise with nice, calming, smoothly animated graphics!

To begin, let’s put this data into a table, with columns for each year, and rows for the different species.

<!doctype html>
<html lang="en">
   <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=1024">
      <title>Example 01: No CSS</title>
   </head>

   <body>
      <div id="wrapper">
         <div class="chart">
            <h3>Population of endangered species from 2012 to 2016</h3>
            <table id="data-table" border="1" cellpadding="10" cellspacing="0"
            summary="The effects of the zombie outbreak on the populations
            of endangered species from 2012 to 2016">
               <caption>Population in thousands</caption>
               <thead>
                  <tr>
                     <td>&nbsp;</td>
                     <th scope="col">2012</th>
                     <th scope="col">2013</th>
                     <th scope="col">2014</th>
                     <th scope="col">2015</th>
                     <th scope="col">2016</th>
                  </tr>
               </thead>
               <tbody>
                  <tr>
                     <th scope="row">Carbon Tiger</th>
                     <td>4080</td>
                     <td>6080</td>
                     <td>6240</td>
                     <td>3520</td>
                     <td>2240</td>
                  </tr>
                  <tr>
                     <th scope="row">Blue Monkey</th>
                     <td>5680</td>
                     <td>6880</td>
                     <td>6240</td>
                     <td>5120</td>
                     <td>2640</td>
                  </tr>
                  <tr>
                     <th scope="row">Tanned Zombie</th>
                     <td>1040</td>
                     <td>1760</td>
                     <td>2880</td>
                     <td>4720</td>
                     <td>7520</td>
                  </tr>
               </tbody>
            </table>
         </div>
      </div>
   </body>
</html>

View the example below to see how it looks naked, with no CSS or JavaScript applied. The accessibility of this table will enable people using screen readers to understand the data and the underlying message, which is “Run for your life! The zombies are coming!�

screenshot

The easy part is now out of the way. Now, let’s tap into the power of CSS and JavasScript (via jQuery) to really illustrate what the numbers are telling us. Technically, our aim is to create a graph that works in all modern browsers, from IE 8 on.

Did I say all modern browsers? IE 8 is lucky: it gets to hang out with the cool kids. Browsers that support CSS3 will get a few extra sprinkles.

“By Your Powers Combined…�

If you wish to summon Captain Planet, you may have to look elsewhere. If you want to learn how to combine CSS and jQuery to create a graph that illustrates our impending doom at the hands of a growing army of zombies who prefer bronzer over brains, then read on.

The first thing to do is style our table with some basic CSS. This is a nice safety net for people who haven’t enabled JavaScript in their browser.

screenshot

Getting Started In jQuery

We’ll use jQuery to create our graph on the fly, separate from the original data table. To do this, we need to get the data out of the table and store it in a more usable format. Then, we can add to our document new elements that use this data in order to construct our graph.

Let’s get started by creating our main createGraph() function. I’ve abbreviated some of the inner workings of this function so that you get a clearer picture of the structure. Don’t forget: you can always refer to the source code that comes with this tutorial.

Here’s our basic structure:

// Wait for the DOM to load everything, just to be safe
$(document).ready(function() {

   // Create our graph from the data table and specify a container to put the graph in
   createGraph('#data-table', '.chart');

   // Here be graphs
   function createGraph(data, container) {
      // Declare some common variables and container elements
      …

      // Create the table data object
      var tableData = {
         …
      }

      // Useful variables to access table data
      …

      // Construct the graph
      …

      // Set the individual heights of bars
      function displayGraph(bars) {
         …
      }

      // Reset the graph's settings and prepare for display
      function resetGraph() {
         …
         displayGraph(bars);
      }

      // Helper functions
      …

      // Finally, display the graph via reset function
      resetGraph();
   }
});

We pass two parameters to this function:

  1. The data, in the form of a table element;
  2. A container element, where we’d like to place our graph in the document.

Next up, we’ll declare some variables to manage our data and container elements, plus some timer variables for animation. Here’s the code:

// Declare some common variables and container elements
var bars = [];
var figureContainer = $('<div id="figure"></div>');
var graphContainer = $('<div class="graph"></div>');
var barContainer = $('<div class="bars"></div>');
var data = $(data);
var container = $(container);
var chartData;
var chartYMax;
var columnGroups;

// Timer variables
var barTimer;
var graphTimer;

Nothing too exciting here, but these will be very useful later.

Getting The Data

Besides simply displaying the data, a good bar chart should have a nice big title, clearly labelled axes and a color-coded legend. We’ll need to strip the data out of the table and format it in a way that is more meaningful in a graph. To do that, we’ll create a JavaScript object that stores our data in handy little functions. Let’s give birth to our tableData{} object:

// Create table data object
var tableData = {
   // Get numerical data from table cells
   chartData: function() {
      …
   },
   // Get heading data from table caption
   chartHeading: function() {
      …
   },
   // Get legend data from table body
   chartLegend: function() {
      …
   },
   // Get highest value for y-axis scale
   chartYMax: function() {
      …
   },
   // Get y-axis data from table cells
   yLegend: function() {
      …
   },
   // Get x-axis data from table header
   xLegend: function() {
      …
   },
   // Sort data into groups based on number of columns
   columnGroups: function() {
      …
   }
}

We have several functions here, and they are explained in the code’s comments. Most of them are quite similar, so we don’t need to go through each one. Instead, let’s pick apart one of them, columnGroups:

// Sort data into groups based on number of columns
columnGroups: function() {
   var columnGroups = [];
   // Get number of columns from first row of table body
   var columns = data.find('tbody tr:eq(0) td').length;
   for (var i = 0; i < columns; i++) {
      columnGroups[i] = [];
      data.find('tbody tr').each(function() {
         columnGroups[i].push($(this).find('td').eq(i).text());
      });
   }
   return columnGroups;
}

Here’s how it breaks down:

  • Create the columnGroups[] array to store the data;
  • Get the number of columns by counting the table cells (td) in the first row;
  • For each column, find the number of rows in the table body (tbody), and create another array to store the table cell data;
  • Then loop through each row and grab the data from each table cell (via the jQuery text() function), and then add it to the table cell data array.

Once our object is full of juicy data, we can start creating the elements that make up our graph.

Using The Data

Using the jQuery $.each function, we can now loop through our data at any point and create the elements that make up our graph. One of the trickier bits involves inserting the bars that represent each species inside the yearly columns.

Here’s the code:

// Loop through column groups, adding bars as we go
$.each(columnGroups, function(i) {
   // Create bar group container
   var barGroup = $('<div class="bar-group"></div>');
   // Add bars inside each column
   for (var j = 0, k = columnGroups[i].length; j < k; j++) {
      // Create bar object to store properties (label, height, code, etc.) and add it to array
      // Set the height later in displayGraph() to allow for left-to-right sequential display
      var barObj = {};
      barObj.label = this[j];
      barObj.height = Math.floor(barObj.label / chartYMax * 100) + '%';
      barObj.bar = $('<div class="bar fig' + j + '"><span>' + barObj.label + '</span></div>')
         .appendTo(barGroup);
      bars.push(barObj);
   }
   // Add bar groups to graph
   barGroup.appendTo(barContainer);
});

Excluding the headings, our table has five columns with three rows. For our graph, this means that for each column we create, three bars will appear in that column. The following image shows how our graph will be constructed:

screenshot

Breaking it down:

  • For each column, create a container div;
  • Loop inside each column to get the row and cell data;
  • Create a bar object (barObj{}) to store the properties for each bar, such as its label, height and mark-up;
  • Add the mark-up property to the column, applying a CSS class of '.fig' + j to color code each bar in the column, wrapping the label in a span;
  • Add the object to our bars[] array so that we can access the data later;
  • Piece it all together by adding the columns to a container element.

Bonus points if you noticed that we didn’t set the height of the bars. This is so that we have more control later on over how the bars are displayed.

Now that we have our bars, let’s work on labelling our graph. Because the code to display the labels is quite similar, talking you through all of it won’t be necessary. Here’s how we display the y-axis:

// Add y-axis to graph
var yLegend   = tableData.yLegend();
var yAxisList   = $('<ul class="y-axis"></ul>');
$.each(yLegend, function(i) {
   var listItem = $('<li><span>' + this + '</span></li>')
      .appendTo(yAxisList);
});
yAxisList.appendTo(graphContainer);

This breaks down as follows:

  • Get the relevant table data for our labels,
  • Create an unordered list (ul) to contain our list items;
  • Loop through the label data, and create a list item (li) for each label, wrapping each label in a span;
  • Attach the list item to our list;
  • Finally, attach the list to a container element.

By repeating this technique, we can add the legend, x-axis labels and headings for our graph.

Before we can display our graph, we need to make sure that everything we’ve done is added to our container element.

// Add bars to graph
barContainer.appendTo(graphContainer);      

// Add graph to graph container
graphContainer.appendTo(figureContainer);

// Add graph container to main container
figureContainer.appendTo(container);

Displaying The Data

All that’s left to do in jQuery is set the height of each bar. This is where our earlier work, storing the height property in a bar object, will come in handy.

We’re going to animate our graph sequentially, one by one, uno por uno.

One possible solution is to use a callback function to animate the next bar when the last animation is complete. However, the graph would take too long to animate. Instead, our graph will use a timer function to display each bar after a certain amount of time, regardless of how long each bar takes to grow. Rad!

Here’s the displayGraph() function:

// Set the individual height of bars
function displayGraph(bars, i) {
   // Changed the way we loop because of issues with $.each not resetting properly
   if (i < bars.length) {
      // Animate the height using the jQuery animate() function
      $(bars[i].bar).animate({
         height: bars[i].height
      }, 800);
      // Wait the specified time, then run the displayGraph() function again for the next bar
      barTimer = setTimeout(function() {
         i++;
         displayGraph(bars, i);
      }, 100);
   }
}

What’s that you say? “Why aren’t you using the $.each function like you have everywhere else?� Good question. First, let’s discuss what the displayGraph() function does, then why it is the way it is.

The displayGraph() function accepts two parameters:

  1. The bars to loop through,
  2. An index (i) from which to start iterating (starting at 0).

Let’s break down the rest:

  • If the value of i is less than the number of bars, then keep going;
  • Get the current bar from the array using the value of i;
  • Animate the height property (calculated as a percentage and stored in bars[i].height);
  • Wait 100 milliseconds;
  • Increment i by 1 and repeat the process for the next bar.

“So, why wouldn’t you just use the $.each function with a delay() before the animation?”

You could, and it would work just fine… the first time. But if you tried to reset the animation via the “Reset graph� button, then the timing events wouldn’t clear properly and the bars would animate out of sequence.

I would like to be proven wrong, and if there is a better way to do this, feel free to sound off in the comments section.

Moving on, here’s resetGraph():

// Reset graph settings and prepare for display
function resetGraph() {
   // Stop all animations and set the bar's height to 0
   $.each(bars, function(i) {
      $(bars[i].bar).stop().css('height', 0);
   });

   // Clear timers
   clearTimeout(barTimer);
   clearTimeout(graphTimer);

   // Restart timer
   graphTimer = setTimeout(function() {
      displayGraph(bars, 0);
   }, 200);
}

Let’s break resetGraph() down:

  • Stop all animations, and set the height of each bar back to 0;
  • Clear out the timers so that there are no stray animations;
  • Wait 200 milliseconds;
  • Call displayGraph() to animate the first bar (at index 0).

Finally, call resetGraph() at the bottom of createGraph(), and watch the magic happen as we bask in the glory of our hard work.

Not so fast, sunshine! Before we go any further, we need to put some clothes on.

The CSS

The first thing we need to do is hide the original data table. We could do this in a number of ways, but because our CSS will load well before the JavaScript, let’s do this in the easiest way possible:

#data-table {
   display: none;
}

Done. Let’s create a nice container area to put our graph in. Because a few unordered lists are being used to make our graph, we’ll also reset the styles for those. Giving the #figure and .graph elements a position: relative is important because it will anchor the place elements exactly where we want in those containers.

/* Containers */

#wrapper {
   height: 420px;
   left: 50%;
   margin: -210px 0 0 -270px;
   position: absolute;
   top: 50%;
   width: 540px;
}

#figure {
   height: 380px;
   position: relative;
}

#figure ul {
   list-style: none;
   margin: 0;
   padding: 0;
}

.graph {
   height: 283px;
   position: relative;
}

Now for the legend. We position the legend right down to the bottom of its container (#figure) and line up the items horizontally:

/* Legend */

.legend {
   background: #f0f0f0;
   border-radius: 4px;
   bottom: 0;
   position: absolute;
   text-align: left;
   width: 100%;
}

.legend li {
   display: block;
   float: left;
   height: 20px;
   margin: 0;
   padding: 10px 30px;
   width: 120px;
}

.legend span.icon {
   background-position: 50% 0;
   border-radius: 2px;
   display: block;
   float: left;
   height: 16px;
   margin: 2px 10px 0 0;
   width: 16px;
}

The x-axis is very similar to the legend. We line up the elements horizontally and anchor them to the bottom of its container (.graph):

/* x-axis */

.x-axis {
   bottom: 0;
   color: #555;
   position: absolute;
   text-align: center;
   width: 100%;
}

.x-axis li {
   float: left;
   margin: 0 15px;
   padding: 5px 0;
   width: 76px;
}

The y-axis is a little more involved and requires a couple of tricks. We give it a position: absolute to break it out of the normal flow of content, but anchored to its container. We stretch out each li to the full width of the graph and add a border across the top. This will give us some nice horizontal lines in the background.

Using the power of negative margins, we can offset the numerical labels inside the span so that they shift up and to the left. Lovely!

/* y-axis */

.y-axis {
   color: #555;
   position: absolute;
   text-align: right;
   width: 100%;
}

.y-axis li {
   border-top: 1px solid #ccc;
   display: block;
   height: 62px;
   width: 100%;
}

.y-axis li span {
   display: block;
   margin: -10px 0 0 -60px;
   padding: 0 10px;
   width: 40px;
}

Now for the meat in our endangered species sandwich: the bars themselves. Let’s start with the container element for the bars and the columns:

/* Graph bars */

.bars {
   height: 253px;
   position: absolute;
   width: 100%;
   z-index: 10;
}

.bar-group {
   float: left;
   height: 100%;
   margin: 0 15px;
   position: relative;
   width: 76px;
}

Nothing too complicated here. We’re simply setting some dimensions for the container, and setting a z-index to make sure it appears in front of the y-axis markings.

Now for each individual .bar:

.bar {
   border-radius: 3px 3px 0 0;
   bottom: 0;
   cursor: pointer;
   height: 0;
   position: absolute;
   text-align: center;
   width: 24px;
}

.bar.fig0 {
   left: 0;
}

.bar.fig1 {
   left: 26px;
}

.bar.fig2 {
   left: 52px;
}

The main styles to note here are:

  • position: absolute and bottom: 0, which means that the bars will be attached to the bottom of our graph and grow up;
  • the bar for each species (.fig0, .fig1 and .fig2), which will be positioned within .bar-group.

Now, why don’t we minimize the number of sharp edges on any given page by using the border-radius property to round the edges of the top-left and top-right corners of each bar? OK, so border-radius isn’t really necessary, but it adds a nice touch for browsers that support it. Thankfully, the latest versions of the most popular browsers do support it.

Because we’ve placed the values from each table cell in each bar, we can add a neat little pop-up that appears when you hover over a bar:

.bar span {
   #fefefe url(../images/info-bg.gif) 0 100% repeat-x;
   border-radius: 3px;
   left: -8px;
   display: none;
   margin: 0;
   position: relative;
   text-shadow: rgba(255, 255, 255, 0.8) 0 1px 0;
   width: 40px;
   z-index: 20;

   -webkit-box-shadow: rgba(0, 0, 0, 0.6) 0 1px 4px;
   box-shadow: rgba(0, 0, 0, 0.6) 0 1px 4px;
}

.bar:hover span {
   display: block;
   margin-top: -25px;
}

First, the pop-up is hidden from view via display: none. Then, when a .bar element is hovered over, we’ve set display: block to bring it into view, and set a negative margin-top to make it appear above each bar.

The text-shadow, rgba and box-shadow properties are currently supported by most modern browsers as is. Of these modern browsers, only Safari requires a vendor prefix (-webkit-) to make box-shadow work. Note that these properties are simply enhancements to our graph and aren’t required to understand it. Our baseline of Internet Explorer 8 simply ignores them.

Our final step in bringing everything together is to color code each bar:

.fig0 {
   background: #747474 url(../images/bar-01-bg.gif) 0 0 repeat-y;
}

.fig1 {
   background: #65c2e8 url(../images/bar-02-bg.gif) 0 0 repeat-y;
}

.fig2 {
   background: #eea151 url(../images/bar-03-bg.gif) 0 0 repeat-y;
}

In this example, I’ve simply added a background-color and a background-image that tiles vertically. This will update the styles for the bars and the little icons that represent them in the legend. Nice.

And, believe it or not, that is it!

The Finished Product

screenshot

That about wraps it up. I hope we’ve done enough to alert the public to the dangers of zombie over-population. More than that, however, I hope you’ve gained something useful from this tutorial and that you’ll continue to push the boundaries of what can be done in the browser — especially with proper Web standards and without the use of third-party plug-ins. If you’ve got ideas on how to extend or improve anything you’ve seen here, don’t hesitate to leave a comment below, or find me on Twitter @derek_mack.

Bonus: Unleashing The Power Of CSS3

This bonus is not as detailed as our main example. It serves mainly as a showcase of some features being considered in the CSS3 specification.

Because support for CSS3 properties is currently limited, so is their use. Although some of the features mentioned here are making their way into other Web browsers, Webkit-based ones such as Apple Safari and Google Chrome are leading the way.

We can actually create our graph using no images at all, and even animate the bars using CSS instead of jQuery.

Let’s start by removing the background images from our bars, replacing them with the -webkit-gradient property:

.fig0 {
   background: -webkit-gradient(linear, left top, right top, color-stop(0.0, #747474), color-stop(0.49, #676767), color-stop(0.5, #505050), color-stop(1.0, #414141));
}

.fig1 {
   background: -webkit-gradient(linear, left top, right top, color-stop(0.0, #65c2e8), color-stop(0.49, #55b3e1), color-stop(0.5, #3ba6dc), color-stop(1.0, #2794d4));
}

.fig2 {
   background: -webkit-gradient(linear, left top, right top, color-stop(0.0, #eea151), color-stop(0.49, #ea8f44), color-stop(0.5, #e67e28), color-stop(1.0, #e06818));
}

We can do the same with our little number pop-ups:

.bar span {
   background: -webkit-gradient(linear, left top, left bottom, color-stop(0.0, #fff), color-stop(1.0, #e5e5e5));
   …
}

For more information on Webkit gradients, check out the Surfin’ Safari blog.

Continuing with the pop-ups, let’s introduce -webkit-transition. CSS transitions are remarkably easy to use and understand. When the browser detects a change in an element’s property (height, width, color, opacity, etc.), it will transition to the new property.

Again, refer to Surfin’ Safari for more information on -webkit-transition and CSS3 animation.

Here’s an example:

.bar span {
   background: -webkit-gradient(linear, left top, left bottom, color-stop(0.0, #fff), color-stop(1.0, #e5e5e5));
   display: block;
   opacity: 0;

   -webkit-transition: all 0.2s ease-out;
}

.bar:hover span {
   opacity: 1;
}

When you hover over the bar, the margin and opacity of the pop-up will change. This triggers a transition event according to the properties we have set. Very cool.

Thanks to -webkit-transition, we can simplify our JavaScript functions a bit:

// Set individual height of bars
function displayGraph(bars, i) {
   // Changed the way we loop because of issues with $.each not resetting properly
   if (i < bars.length) {
      // Add transition properties and set height via CSS
      $(bars[i].bar).css({'height': bars[i].height, '-webkit-transition': 'all 0.8s ease-out'});
      // Wait the specified time, then run the displayGraph() function again for the next bar
      barTimer = setTimeout(function() {
         i++;
         displayGraph(bars, i);
      }, 100);
   }
}
// Reset graph settings and prepare for display
function resetGraph() {
   // Set bar height to 0 and clear all transitions
   $.each(bars, function(i) {
      $(bars[i].bar).stop().css({'height': 0, '-webkit-transition': 'none'});
   });

   // Clear timers
   clearTimeout(barTimer);
   clearTimeout(graphTimer);

   // Restart timer
   graphTimer = setTimeout(function() {
      displayGraph(bars, 0);
   }, 200);
}

Here are the main things we’ve changed:

  • Set the height of the bars via the jQuery css() function, and allowed CSS transitions to take care of the animation;
  • When resetting the graph, turned transitions off so that the height of the bars is instantly set to 0.

Check out the example if you have the latest version of Safari or Chrome installed.

Ultra-Mega Webkit Bonus: Now In 3-D!

For a sneak peek of what the future holds, check out a little experiment that I put together, with a 3-D effect and CSS transforms. Again, it requires the latest versions of Safari or Chrome:

As in our previous Webkit example, there are no images, and all animation is handled via CSS. Kiss my face!

I can’t tell you what to do with all this information. But I do caution you about the potential misuse of your new powers. In the words of our friend Captain Planet, “The power is yours!�

Use it wisely.

(al) (kw) (il)


© Derek Mack for Smashing Magazine, 2011.


Screen readers, list items and list-style:none

It’s more or less common practice these days to use real HTML lists when what you’re marking up makes logical sense as a list. If you don’t want it to look like a standard ordered or unordered list, that’s easy to fix with a bit of CSS. The underlying semantics will still be there for people using browsers without CSS support or screen readers.

But will it? The short answer is no, not always.

Read full post

Posted in , .

Copyright © Roger Johansson



Help The Community: Report Browser Bugs


  

You’re developing a new website and have decided to use some CSS3 and HTML5, now that many of the new specifications are gaining widespread support. As you’re coding the theme and thinking of how much easier these new technologies are making your job, you decide to stop for a while and test in other browsers, feeling a bit guilty for getting carried away and having forgotten to do so for a while. “Please work,� you whisper to your computer, while firing up all of the browsers you have installed. Browser A, check. You smile, feeling a bit relieved. Browser B, check. Your smile widens, and you start to feel better already. Browser C, “FFFFUUUUUUUUUUU…!�

Sound familiar? You might be surprised to hear that this is not necessarily your fault. With the competition in the browser market these days and the fast pace at which the new specifications are developing, browser makers are implementing new stuff in a hurry, sometimes without properly testing it. CSS3 and HTML5 are much more complex than their predecessors. The number of possible combinations of new features is huge, which leads to the most common cause of bugs: two (or more) things that weren’t tested together. As a result, developers these days stumble upon browser bugs much more frequently than they used to.

Why Should I Bother Reporting Bugs?

If you don’t, perhaps no one else will. Maybe the bug you’ve discovered is so rare that no one else will stumble on it. Or maybe they will, but they won’t know how to report it. They might think that it’s their fault, just as you originally did. Besides, if you’ve used these new technologies in a way that triggers the bug now, you will likely do so again in the future as well, so you would directly benefit from the bug getting fixed. And in the process, you’d be helping thousands of other developers avoid the frustration you’ve faced.

You might think that reporting the bug would be pointless, because it would take ages to fix, and would take even longer for users to upgrade to the fixed version. However, for all browsers except Internet Explorer (IE), this is not true anymore. Users of Firefox, Opera, Safari and Chrome upgrade really quickly these days, because the software pushes them to do so or (in the case of Chrome) doesn’t even give them a choice. Also, some bugs get fixed quite quickly, especially the ones that come with a decent report. Keep reading, and your own bug reports will likely fall in this latter category.

Making A Reduction

The first step is to reduce the problem to its bare minimum. If it turns out to be a browser bug, you will need to include this “reduction� in your bug report. Also, this will help you figure out a potential workaround until the browser vendor fixes it. Even if it’s not actually a browser bug, doing this will help you realize what you did wrong and fix it. Lastly, it’s a valuable aid in debugging in general.

Here is the process I follow to create reductions:

  1. Make a copy of your project. If it includes server-side code, then first save the rendered page locally; the rest of the process will be identical from this point on.
  2. Start removing CSS and JavaScript files. Eventually, you’ll find that removing one makes the problem go away. Add that one back and remove the others (except any files it depends on). In some rare cases, you might find that the bug persists even after removing all CSS and JavaScript code. In these cases, the bug is more than likely HTML-related.
  3. Now you need to find the exact code in the file that triggers the problem. Start commenting out parts of the code until the problem goes away (being careful not to introduce any new problems in the process). I find that the quickest way to do this is like doing a binary search: first, comment out around half of the code; if the bug persists, then remove that code and comment out half of the remaining code, and so on; if the bug disappears, then remove the uncommented code and proceed with that. You might find that deleting and undoing is quicker than commenting and uncommenting. Sometimes you have to do this process twice in the same file, because some bugs can be reproduced only with a particular combination of different code parts.
  4. Put the remaining CSS and JavaScript code inline by transferring it from the external file to a <style> or <script> element in the HTML document. This will make the reduction even simpler because it will be contained in only one file.
  5. Now, simplify the HTML. For example, if it’s a CSS bug, then remove everything that CSS rules don’t apply to. If the rules apply to a nested element, try applying them to the <body> instead and see whether the bug reproduces. If it is, then remove all of the <body>’s descendants.
  6. Change the document’s <title> to something relevant to the bug. Check the whole thing carefully for details that you wouldn’t want other people to see, because you usually can’t edit it after attaching it to your bug report. (I learned this the hard way.)

Now that you have your reduction, examine the code. Is it actually correct? Browser makers can’t be held accountable for the way their products handle invalid code — except for HTML5 markup, which has strictly defined error-handling. Validating the code might help, but take its output with a grain of salt. (Note that CSS vendor prefixes are valid, even if the CSS validator disagrees.)

If you have some time and want to be extra nice, here are some other things you can do to make an even better reduction:

  • Test to see whether the bug is more general than the case you have discovered. For example, if you discovered that an engine doesn’t handle border-radius: 50% correctly, then test whether the same thing happens with other percentage-based values. Or if a CSS gradient from black to transparent does not display correctly, see whether the same thing happens when you use a transition from background-color: transparent to background-color: black; if it does, then that would mean the problem stems from general interpolation and is not limited to CSS gradients. Even if you find that it’s not more general than the case you originally stumbled on, do mention your experiments in the bug description, so that the developers don’t have to repeat them.
  • Try to find a workaround. Can you change or add something in the code to make the bug go away? This could be as easy as converting ems to pixels or as hard as adding a whole new declaration. Be sure to mention the workaround in the bug report.
  • Make it function like a test case, or create an additional test case. These are the special kinds of reductions that QA engineers make for automated testing systems. Such tests show the color green in browsers that don’t have the bug and red in the ones that do. Other colors may be shown, but not red and green at the same time. This is an easy task with some bugs, and incredibly hard with others.

Sometimes the nature of the problem is quite obvious, so creating a simple test case from scratch is quicker. I’ve found JSFiddle to be an invaluable aid in this. However, bear in mind that browser vendors usually prefer that you upload your own simple HTML files rather than provide JSFiddle links. If you do decide to use JSFiddle, then uncheck the “Normalized CSS� setting, remove any JavaScript libraries (unless your bug needs them to be reproduced), and append /show to the URL, so that it leads only to your test case, without the rest of the JSFiddle UI.

If you don’t have the time to make a reduction, reporting the bug is still a good idea. A bad bug report is better than none at all, and the same goes for reductions. In this case, the browser developers will have to create the reduction themselves. The difference is that they’re burdened with doing this for many more bugs than you can imagine. You only have to do it for one: yours.

Should I Report It?

There are many reasons why you might not need to report the problem as a bug after all:

  • It turns out it’s not really a bug,
  • It has already been fixed in the latest nightly build,
  • It has already been reported.

Let’s tackle these one by one.

Is It Really a Bug?

In most cases, when you isolate the problem to a simple reduction, it’s fairly obvious whether it’s a browser bug or not. However, there are some caveats to this.

A while ago, I realized that even though outline-color: invert was in the CSS specification, it didn’t work in all browsers that support outlines. In particular, it didn’t work in Webkit browsers or Firefox. Those browsers didn’t drop the declaration, but just treated it as though it was currentColor. So, I went ahead, created a reduction, and filed bug reports with both browsers. After a while, I was informed that a footnote in the specification actually permits user agents to do this, so it wasn’t actually a bug. The moral of the story is to check the specification carefully — not just the table that is included in every CSS property, but the whole thing. Knowing these details will make you a better developer anyway.

On another occasion, I was reading the “CSS3 Backgrounds and Borders� module and found that it allowed percentages to be used for border-width, unlike CSS 2.1. I tested it, and it didn’t work in any browser. So, I filed bug reports in some of them, only to be informed that this was dropped in the “dev� version (i.e. the not-yet-published version) of the specification. The moral of this story is that, for specs still under development, don’t check the published specifications to determine whether your issue is actually a bug. Instead, look at dev.w3.org, where the most up-to-date versions of the specs reside.

Of course, in many cases, a bug is not really a bug or a lack of understanding of the spec, but just one of those stupid mistakes that we all do (aka brain farts). I remember once how distraught I was over my JavaScript not working at all in Safari, even though it gave no errors. After a while of struggling to make a reduction, I realized that I had previously disabled JavaScript in that browser to test how a website worked without it and had forgotten to enable it.

Likewise, a few days ago, my SVGs weren’t displaying as backgrounds in Firefox, even though they displayed when I opened them in new tabs. I then realized that I had two background images in the same declaration, the other one being a CSS gradient, and I had forgotten to add the -moz- version.

The one I’m most embarrassed about is when I actually reported a bug to Opera about pointer-events not working in <select> menus and was then informed that Opera hadn’t implemented pointer-events in HTML elements at all. D’oh!

In some rare cases, the bug is indeed a bug but not a browser bug. Specifications have their fair share of bugs, too. If the spec defines something other than what happens or if it defines something that conflicts with the rest of the spec, then it most likely has a bug. Such bugs should be reported in the relevant mailing list (www-style for CSS) or the W3C bug tracker. Even if this is the case, many of the guidelines mentioned below still apply.

Is It Reproducible in the Latest Nightly Builds?

If you haven’t already installed the nightlies of browsers, you should. These are the latest (potentially unstable) versions of browsers. Download them from these links:

Obviously, if your bug is not reproducible in the latest nightly of the browser, then you don’t have to report it. Just wait until the build propagates to a stable release. In other words, all you need is patience, young Padawan.

Has It Already Been Reported?

If after checking the specifications and the latest nightly, you’re still confident that it is a bug, then you need to search whether it has already been reported. Your best bet is to use the search engine of the relevant bug tracker. Don’t forget to search all statuses, because the default on some bug-tracking systems is to search only confirmed and open bugs (excluding unconfirmed and fixed or otherwise closed ones).

Be vague in your search, especially if the bug affects a feature that’s not very popular. For example, for this Webkit bug, a search for “multiple file� would show the bug, whereas a search for “input file multiple dom property� would not; I was inexperienced when I filed it and didn’t know the exact terminology at the time. If the bug tracker is public, sometimes searching on Google also helps (adding site:url-of-bug-tracker after your keywords).

If your issue has indeed been reported, some bug trackers allow voting. Mozilla’s Bugzilla gives every user a limited number of votes (the limit is in the thousands), which the user can use on any bug they wish. Also, Chrome’s bug tracker features a star in the top-left corner, which you can click to indicate that you consider the bug important. I’m not yet sure whether the developers take this into account, but voting certainly doesn’t hurt.

Different Engines, Different Bug Trackers

Every browser has its own bug-tracking system (BTS).

Safari and Chrome share the same engine (Webkit), so bugs that can be reproduced in both should be reported in Webkit’s BTS. Chrome has its own BTS as well, intended for bugs that are reproducible only in it. Also, if you’re dealing with a JavaScript bug in Chrome, report it to the V8 bug tracker.

You will need to create a free account to file bugs with any of these bug trackers (except Opera’s Wizard). But it’s a one-time thing, and it’s useful because it allows you to easily track bugs that you’ve reported.

All of the browsers’ bug trackers are public, with one exception: Opera’s. You can report Opera bugs through the public form I linked to above, but to access the BTS and to discuss your bug and monitor its progress, you will need to become an Opera volunteer (or an employee!) and sign an NDA. Volunteering is by invitation only, but if you submit a lot of good bug reports, there’s a good chance you’ll be invited.

Filing A Good Bug Report

The most important part of a good bug report (and the one most commonly done wrong) is the reduction. Hopefully, you’ve done that already, so the hardest part is over with. The rest probably won’t take you more than five minutes.

Providing a Good Summary

A good summary is the second-most important part of a bug report. Don’t be afraid to be verbose, if it actually adds something (don’t just babble). To take one from an actual report,

Background image disappears when body{display:table} is used (common CSS hack for correct centering + scrolling in Firefox)

… is better than “Background image disappears when body{display:table} is used,� which in turn is better than “Disappearing background image.� Of course, all three are better than “CSS broke. Please fix!!!!11�

Sometimes you may want to add keywords to the beginning of the summary to make the report more findable. For example, if your bug is about CSS3 gradients, you could prepend the summary with “[css3-images].� To get an idea of the exact tags used in a module, look at other bug reports. It will usually be the same as the id of the specification, which is located at the end of its URL path. For example, for the CSS3 module “Backgrounds and Borders,� the URL is http://www.w3.org/TR/css3-background/, and the spec’s id is css3-background. Also, these summary “tags� can be OS-specific. For example, if your bug is reproducible only in Mac OS X, then prepend your summary with “[Mac].� If the bug is about something that used to work fine in previous versions, then prepend your summary with “[Regression],� or add “regression� as a keyword if the BTS has such a feature.

Categorizing the Bug

The category to which your bug belongs is usually quite obvious, provided you take a few seconds to check them all. For CSS bugs, these are the most common candidates:

  • Internet Explorer: “CSS and HTMLâ€�;
  • Firefox: “Style System (CSS),â€� all the “Layoutâ€� components;
  • Opera Wizard: “Web page problemâ€�;
  • Webkit: “CSS, Layout and Renderingâ€�;
  • Chrome: doesn’t let you categorize bugs (its developers do it for you).

John Resig suggests some ways to categorize JavaScript bugs.

Other Fields

  • You can be as verbose in the “Descriptionâ€� field as you need to be. Explain the bug in detail (what you expected to see, what was actually displayed, etc.) and any interaction needed to reproduce it. Then mention any workarounds you found, how other browsers handle the case, and any other notable observations. But don’t start babbling about what you were doing when you discovered the bug, no matter how funny or interesting you think it is. QA time is precious; please don’t waste it with irrelevant detail.
  • The “Productâ€� will usually be “Core.â€� If you have a choice between “Coreâ€� and the browser’s name, choose “Core,â€� because bugs filed under the browser’s name are usually for the UI.
  • Regarding “Platformâ€� and “OS,â€� try to test in other operating systems if you can. (You do test your websites in different operating systems, right?) If the bug is reproducible in all OS’, then select “All.â€� If it’s reproducible in only one, then mention that in your description and/or summary.
  • Avoid changing the “Severityâ€� or “Priorityâ€� fields, because you will tend to overestimate.
  • Most people who report bugs don’t fill in the “CCâ€� field. But if you know someone who works for a given browser vendor, especially someone who frequently replies to similar bug reports (browse the reports if you’re not sure), then cc’ing them might help the bug get noticed more quickly. In some cases, this could mean the difference between a bug report getting noticed in a few days and one going unnoticed for months.
  • If you have the time to take a screenshot, by all means do so, especially if the bug is reproducible in only one OS.

What Not to Do

Never, ever report multiple bugs in the same report. Handling these is very hard for browser developers. Think about it: what status should they assign to a report if they fix one bug, but the other turns out to be a duplicate? Or only one of the two turns out to be a bug? You get the idea.

I can understand that you might be frustrated from having had to deal with that bug, but being rude won’t help. Stay polite, and keep thoughts like “I can’t believe you can’t even get this right, you morons!� to yourself.

Some Examples

Example 1: Reducing the Original Problem, Realizing It Was Your Mistake

While developing twee+, a handy little app for posting long tweets (and my entry in the 10K Apart contest), I found out that even though it worked in mobile Safari for reading, it crashed when you tried to make an edit. I had no idea what might have been causing this, so I made a copy and started reducing. After commenting out parts of the JavaScript, I found that if I removed the onresize event handler, the problem stopped occurring. And then it made total sense: I adjust the rows of the textarea when the user resizes the window. However, in Mobile Safari, this triggered a resize event, resulting in a dreaded infinite loop. So I removed the resize event handler for mobile. It’s not like the user can resize the window there anyway.

Example 2: Making a Reduction From Scratch, Filing a Bug

A big part of my upcoming CSS3 workshop in Amsterdam is hands-on challenges. Attendees will download my slide deck (which is essentially an HTML + CSS + JavaScript app) and try to solve some 5- or 10-minute challenges on everything taught. A challenge slide would look like this:

I prepared a lot of the slides in Chrome. When I opened them in Firefox, I was greeted with this ugly sizing of the textarea:

In this case, I didn’t follow the reduction process laid out above, because I had a hunch that the bug was related to the way I sized the textarea. So, I fired up JSFiddle and made this simple example, in which the bug could still be reproduced. I then tested it in Opera and observed that it behaved like Firefox, so it was probably Webkit that was buggy. I tested it in the Webkit nightlies and saw that it hadn’t yet been fixed.

Before going any further, I tried to see whether the bug was more generic. Does it happen only with textareas or with all replaced elements? I went ahead and tested <img> and <input> and found that it happens only with form fields. I did another test to see whether it also happened with top/bottom rather than left/right. It did not. I also tested on Windows, and it’s reproducible there as well.

The specification confirmed that it was indeed a bug: “The used value of ‘width’ and ‘height’ is determined as for inline replaced elements.� After a bit of searching on Google, I found this blog post, which describes the bug but does not mention an official bug report. So, I searched Webkit’s bug tracker for “textarea absolute,� “textarea positioned� and “input positioned� and couldn’t find anything relevant. It was bug-reporting time!

I went ahead and created this bug report. Let’s hope it goes well.

What Happens Next?

At some point, usually after a few days or weeks, someone will modify your bug’s status. If it turns out to be a “duplicate,� don’t feel bad: it happens to the best of us, even employees of the browser vendors themselves. If the status gets “confirmed� (usually with the status “new�), this is a good indication that it is indeed a bug and that you did the right thing by reporting it. Last but not least, if the new status is “assigned,� it means someone is actively working on the issue (or plans to do so soon), so it has a high chance of getting fixed soon.

When your bug gets a status of “resolved,� check the “resolution� field. If it says “wontfix,� it means that they’re not planning to rectify the issue, for reasons usually stated in detail in an accompanying comment. The reason is usually either that it’s not a bug (in which case, the most appropriate resolution status is “invalid�) or that they just don’t want to work on it for the time being. If the latter, you could argue your case and explain why the bug is important, but don’t get your hopes up. Last but not least, if it’s “fixed,� you can congratulate yourself on doing your part to make the Web a better place.

Further Reading

Thanks a lot to David Storey, Divya Manian, Paul Irish, Elika Etemad and Oli Studholme for their helpful tips and reviews.

Front Cover: Image source

(al)


© Lea Verou for Smashing Magazine, 2011.


Writing CSS For Others

Advertisement in Writing CSS For Others
 in Writing CSS For Others  in Writing CSS For Others  in Writing CSS For Others

I think a lot of us CSS authors are doing it wrong. We are selfish by nature; we get into our little bubbles, writing CSS (as amazing as it may be) with only ourselves in mind. How many times have you inherited a CSS file that’s made you say “WTF� at least a dozen times?

Labyrinth-comic in Writing CSS For Others

(Image: Toca Boca)

HTML has a standard format and syntax that everyone understands. For years, programmers have widely agreed on standards for their respective languages. CSS doesn’t seem to be there yet: everyone has their own favorite format, their own preference between single-line and multi-line, their own ideas on organization, and so on.

A New Way of Thinking

Recently, I have begun to think that CSS authors could take a leaf from the programmers’ book. We need to write CSS that others can understand and use with ease. Programmers have been writing sharable code since day one, and it’s high time that CSS be written with as much organization and openness.

In writing inuit.css and working on a huge front-end framework at my job, it has become more apparent to me that writing code that can be easily picked up by others is extremely important. I wouldn’t say that I’ve nailed everything yet, but I’ll share with you some things that I think are vital when writing code, specifically CSS, that will be used by others.

First, the reasoning: my number one tip for developers is to always code like you’re working on a team, even if you’re not. You may be the only developer on your project right now, but it might not stay that way:

  • Your project could be taken to another developer, agency or team. Even though this is not the best situation to find yourself in, handing over your work smoothly and professionally to the others is ideal.
  • If you’re doing enough work to warrant employing someone else or expanding the team at all, then your code ceases to be yours and becomes the team’s.
  • You could leave the company, take a vacation or be off sick, at which point someone else will inherit your code, even if only temporarily.
  • Someone will inevitably poke through your source code, and if they’ve never met you, this could be the only basis on which they judge your work. First impressions count!

Comments Are King!

One thing I’ve learned from building a massive front-end framework at work and from producing inuit.css is that comments are vital. Comments, comments, comments. Write one line of code, then write about it.

It might seem like overkill at first, but write about everything you do. The code might look simple to you, but there’s bound to be someone out there who has no idea what it does. Write it down. I had already gotten into this habit when I realized that this was the same technique that a good friend and incredibly talented developer, Nick Payne, told me about. That technique is called “rubber-duck debugging�:

… an unnamed expert programmer would keep a rubber duck by his desk at all times, and debug his code by forcing himself to explain it, line by line, to the duck.

Write comments like you’re talking to a rubber duck!

Good comments take care of 99% of what you hand over and — more importantly —  take care of your documentation. Your code should be the documentation.

Comments are also an excellent way to show off. Ever wanted to tell someone how awesome a bit of your code is but never found the chance? This is that chance! Explain how clever it is, and just wait for people to read it.

Egos aside, though, comments do force you to write nicer code. I’ve found that writing extensive comments has made me a better developer. I write cleaner code, because writing comments reminds me that I’m intending for others to read the code.

Multi-Line CSS

This issue really divides developers: single-line versus multi-line CSS. I’ve always written multi-line CSS. I love it and despise single-line notation. But others think the opposite — and they’re no more right or wrong than I am. Taste is taste, and consistency is what matters.

Having said that, when working on a team, I firmly believe that multi-line CSS is the way to go. Multi-line ensures that each CSS declaration is accounted for. One line represents one piece of functionality (and can often be attributed to one person).

As a result, each line will show up individually on a diff between two versions. If you change, say, only one hex value in a color declaration, then that is all that needs to be flagged. A diff on a single-line document would flag an entire rule set as having been changed, even when it hasn’t.

Take the following example:

Cfo-01-700 in Writing CSS For Others

Above, we just changed a color value in a rule set, but because it was a single-line CSS file, the entire rule set appears to have changed. This is very misleading, and also not very readable or obvious. At first glance, it appears that a whole rule set has been altered. But look closely and you’ll see that only #333 has been changed to #666. We can make this distinction far more obvious by using multi-line CSS, like so:

Cfo-02 in Writing CSS For Others

Having said all this, I am by no means a version-control expert. I’ve only just started using GitHub for inuit.css, so I’m very new to it all. Instead, I’ll leave you with Jason Cale’s excellent article on the subject.

Furthermore, single-line CSS makes commenting harder. Either you end up with one comment per rule set (which means your comments might be less specific than had they been done per line), or you get a messy single line of comment, then code, then comment again, as shown here:

Cfo-03 in Writing CSS For Others

With multi-line CSS, you have a much neater comment structure:

Cfo-04 in Writing CSS For Others

Ordering CSS Properties

Likewise, the order in which people write their CSS properties is very personal.

Many people opt for alphabetized CSS, but this is counter-intuitive. I commented briefly on the subject on GitHub; my reasoning is that ordering something by a meaningless metric makes no sense; the initial letter of a declaration has no bearing on the declaration itself. Ordering CSS alphabetically makes as much sense as ordering CDs by how bright their covers are.

A more sensible approach is to order by type and relevance. That is, group your color declarations together, your box-model declarations together, your font declarations together and so on. Moreover, order each grouping according to its relevance to the selector. If you are styling an h1, then put font-related declarations first, followed by the others. For example:

#header {
   /* Box model */
   width: 100%;
   padding: 20px 0;
   /* Color */
   color: #fff;
   background: #333;
}

h1 {
   /* Font */
   font-size: 2em;
   font-weight: bold;
   /* Color */
   color: #c00;
   background: #fff;
   /* Box model */
   padding: 10px;
   margin-bottom: 1em;
}

Ordering CSS Files

Ordering CSS files is always tricky, and there is no right or wrong way. A good idea, though, is to section the code into defined groups, with headings, as well as a table of contents at the top of the file. Something like this:

/*------------------------------------*\
   CONTENTS
\*------------------------------------*/
/*
MAIN
TYPE
IMAGES
TABLES
MISC
RESPONSIVE
*/

/*------------------------------------*\
   $MAIN
\*------------------------------------*/
html {
   styles
}

body {
   styles
}

/*------------------------------------*\
   $TYPE
\*------------------------------------*/

And so on.

This way, you can easily read the contents and jump straight to a particular section by performing a quick search (Command/Control + F). Prepending each heading with a dollar sign makes it unique, so that a search will yield only headings.

The “Shared� Section

All CSS files should have a section for sharing, where you tether selectors to a single declaration, rather than write the same declaration over and over.

So, instead of writing this…

/*------------------------------------*\
   $TYPE
\*------------------------------------*/
h1 {
   font-size: 2em;
   color: #c00;
}

h2 {
   font-size: 1.5em;
   color: #c00;
}

a {
   color: #c00;
   font-weight: bold;
}

#tagline {
   font-style: italic;
   color: #c00;
}

… you would write this:

/*------------------------------------*\
   $TYPE
\*------------------------------------*/
h1 {
   font-size: 2em;
}
h2 {
   font-size: 1.5em;
}
a {
   font-weight: bold;
}
#tagline {
   font-style: italic;
}

/*------------------------------------*\
   $SHARED
\*------------------------------------*/
h1, h2, a, #tagline {
   color:#c00;
}

This way, if the brand color of #c00 ever changes, a developer would only ever need to change that value once. This is essentially using variables in CSS.

Multiple CSS Files For Sections, Or One Big File With All Sections?

A lot of people separate their sections into multiple files, and then use the @import rule to put them all back together in one meta file. For example:

@import url(main.css)
@import url(type.css)
@import url(images.css)
@import url(tables.css)
@import url(misc.css)
@import url(responsive.css)

This is fine, and it does keep everything in sections, but it does lead to a lot more HTTP requests than is necessary; and minimizing requests is one of the most important rules for a high-performance website.

Compare this…

Firebug-1 in Writing CSS For Others

… to this:

Firebug-2 in Writing CSS For Others

If you section and comment your CSS well enough, using a table of contents and so forth, then you avoid the need to split up your CSS files, thus keeping those requests down.

If you really want to break up your CSS into multiple style sheets, you can do that — just combine them into one at build time. This way, your developers can work across multiple files, but your users will download one concatenated file.

Learning From Programmers

Programmers have been doing this for ages, and doing it well. Their job is to write code that is as readable as it is functional. We front-end developers could learn a lot from how programmers deal with code.

The code of my good friend (and absolutely awesome chap) Dan Bentley really struck a chord with me. It’s beautiful. I don’t understand what it does most of the time, but it’s so clean and lovely to look at. So much white space, so neat and tidy, all commented and properly looked after. His PHP, Ruby, Python or whatever-he-decides-to-use-that-day always looks so nice. It made me want to write my CSS the same way.

White space is your friend. You can remove it before you go live if you like, but the gains in cleanliness and readability are worth the few extra bytes (which you could always cut back down on by Gzip’ing your files anyway).

Make the code readable and maintainable first and foremost, then worry about file size later. Happy developers are worth more than a few kilobytes in saved weight.

Code Should Take Care Of Itself

So far, we’ve talked about people maintaining your code, but what about actually using it?

You can do a number of things to make the life of whoever inherits your code much easier — and to make you look like a saint. I can’t think of many generic examples, but I have a few specific ones, mainly from inuit.css.

Internationalize Your Selectors

Inuit.css has a class named .centered, which is spelt in US English. CSS is written in US English anyway, so we’re used to this; but as an English developer, I always end up typing UK English at least once in a project. Here is the way I have accounted for this:

.centred, .centered {
   [style]
}

Both classes do the same thing, but the next developer doesn’t have to remember to be American!

If your selectors include words that have US and UK spelling variants, include both.

Let the Code Do the Heavy Lifting

Also in inuit.css, I devised a method to not need class="end" for the last column in a row of grids. Most frameworks require this class, or something similar, to omit the margin-right on the last item in a list and thus prevent the grid system from breaking.

Remembering to add this class isn’t a big deal, but it’s still one more thing to remember. So, I worked out a way to remove it.

In another major inuit.css update, I removed a .grid class that used to be required for every single grid element. This was a purely functional class that developers had to add to any <div> that they wanted to behave like a grid column. For example:

<div class="grid grid-4">
    …
</div>

This .grid class, in conjunction with the .grid-4 class, basically says, “I want this <div> to be a grid item and to span four columns.� This isn’t a huge burden on developers, but again, it’s one more thing that could be removed to make their lives easier.

The solution was to use a regex CSS attribute selector: [class^="grid-"]{}. This says, “Select any element whose class begins with .grid-,� and it allows the developer’s mark-up to now read as follows:

<div class="grid-4">
    …
</div>

CSS attribute selectors may be less efficient than, say, classes, but not to the point that you’d ever notice it (unless you were working on a website with massive traffic, like Google). The benefits of making the mark-up leaner and the developer’s life easier far outweigh the performance costs.

Do the hard work once and reap the benefits later. Plus, get brownie points from whoever picks up your project from you.

Be Pre-emptive, Think About Edge Cases

An example of being pre-emptive in inuit.css is the grid system. The grids are meant to be used in a series of sibling columns that are all contained in one parent, with a class of .grids. This is their intended use. But what if someone wants a standalone grid? That’s not their intended use, but let’s account for it should it happen.

Note: inuit.css has changed since this was written, but the following is true as of version 2.5.

Another and perhaps better example is the 12-column grid system in inuit.css. By default, the framework uses a 16-column grid, with classes .grid-1 through .grid-16 for each size of column.

A problem arises, though, when you attempt to switch from the 16-column system to the 12-column system. The .grid-15 class, for example, doesn’t exist in a 12-column layout; and even if it did, it would be too big.

What I did here was to make .grid-13 through .grid-16 use the exact same properties as .grid-12. So, if you switch from a 16-column layout to a 12-column one, your .grid-13 through .grid-16 would’t break it — they would all just become .grid-12s.

This means that developers can switch between them, and inuit.css will take care of everything else.

Pre-empt the developer’s next problem, and solve it for them.

That’s It

There you have it: a few humble suggestions on how CSS authors can write code that is perfect for other developers to inherit, understand, maintain, extend and enjoy.

If you have any other tips, do please add them in the comments.

(al)


© Harry Roberts for Smashing Magazine, 2011.


100 Great CSS Menu Tutorials


  

Navigation is such an important part of your website. It’s how your visitors navigate to the main areas of your site and makes it easy for them to find your good content.

CSS is of course the perfect language for designing beautiful navigation menus. It can be applied to any type of website and is very flexible. Don’t be alarmed if your own CSS skills are fairly limited as there are a lot of great tutorials out there that walk you through how to add clean and professional looking CSS menus to your website. You can either copy and paste the code into your own design or modify the menu to suit your needs.

Today we would like to show you 100 of these tutorials; 75 horizontal CSS menu tutorials and 25 vertical CSS menu tutorials.

Horizontal CSS Menu Tutorials

1. Advanced CSS Menu Trick

Advanced CSS Menu Trick

View Tutorial | Demo

2. Elegant Drop Menu with CSS Only

Elegant Drop Menu with CSS Only

View Tutorial | Demo

3. Bulletproof CSS Sliding Doors

Bulletproof CSS Sliding Doors

View Tutorial & Demo

4. Tabbed Navigation Using CSS

Tabbed Navigation Using CSS

View Tutorial | Demo

5. Create an Advanced CSS3 Menu – Version 2

Create an Advanced CSS3 Menu – Version 2

View Tutorial | Demo

6. Create a Slick Menu using CSS3

Create a Slick Menu using CSS3

View Tutorial | Demo

7. How to Make a Smooth Animated Menu with jQuery

How to Make a Smooth Animated Menu with jQuery

View Tutorial | Demo

8. How to Make a CSS Sprite Powered Menu

How to Make a CSS Sprite Powered Menu

View Tutorial

9. Simple jQuery Dropdowns

Simple jQuery Dropdowns

View Tutorial | Demo

10. Designing the Digg Header: How To & Download

Designing the Digg Header: How To & Download

View Tutorial | Demo

11. Dynamic Page / Replacing Content

Dynamic Page / Replacing Content

View Tutorial | Demo

12. Create a Fun Animated Navigation Menu With Pure CSS

Create a Fun Animated Navigation Menu With Pure CSS

View Tutorial | Demo

13. How-to: DropDown CSS Menu

How-to: DropDown CSS Menu

View Tutorial | Demo

14. Flexible CSS Menu

Flexible CSS Menu

View Tutorial & Demo

15. Creating a glassy non div navigation bar

Creating a glassy non div navigation bar

View Tutorial | Demo

16. CSS Sliding Door using only 1 image

CSS Sliding Door using only 1 image

View Tutorial | Demo

17. CSS UL LI – Horizontal CSS Menu

CSS UL LI - Horizontal CSS Menu

View Tutorial

18. How to Build a Kick-Butt CSS3 Mega Drop-Down Menu

How to Build a Kick-Butt CSS3 Mega Drop-Down Menu

View Tutorial | Demo

19. A Different Top Navigation

A Different Top Navigation

View Tutorial | Demo

20. Create a Cool Animated Navigation with CSS and jQuery

Create a Cool Animated Navigation with CSS and jQuery

View Tutorial | Demo

21. Navigation Bar

Navigation Bar

View Tutorial & Demo

22. CSS: drop down menu tutorial

CSS: drop down menu tutorial

View Tutorial | Demo

23. RocketBar – A jQuery And CSS3 Persistent Navigation Menu

RocketBar – A jQuery And CSS3 Persistent Navigation Menu

View Tutorial | Demo

24. A Great CSS Horizontal Drop-Down Menu

A Great CSS Horizontal Drop-Down Menu

View Tutorial & Demo

25. Overlay Effect Menu with jQuery

Overlay Effect Menu with jQuery

View Tutorial | Demo

26. Grungy Random Rotation Menu with jQuery and CSS3

Grungy Random Rotation Menu with jQuery and CSS3

View Tutorial | Demo

27. Rocking and Rolling Rounded Menu with jQuery

Rocking and Rolling Rounded Menu with jQuery

View Tutorial | Demo

28. Slide Down Box Menu with jQuery and CSS3

Slide Down Box Menu with jQuery and CSS3

View Tutorial | Demo

29. Advanced CSS Menu

Advanced CSS Menu

View Tutorial | Demo

30. CSS3 Dropdown Menu

CSS3 Dropdown Menu

View Tutorial | Demo

31. How To Create A Simple Drop Down Menu With CSS3

How To Create A Simple Drop Down Menu With CSS3

View Tutorial | Demo

32. Pastel color menu with dynamic submenu using CSS

Pastel color menu with dynamic submenu using CSS

View Tutorial | Demo

33. Creating an Animated CSS3 Horizontal Menu

Creating an Animated CSS3 Horizontal Menu

View Tutorial | Demo

34. Tutorial to create a Beautiful, simple, horizontal CSS menu

Tutorial to create a Beautiful, simple, horizontal CSS menu

View Tutorial & Demo

35. CSS Sprites2 – It’s JavaScript Time

CSS Sprites2 - It’s JavaScript Time

View Tutorial | Demo

36. Image Menu with Jquery

Image Menu with Jquery

View Tutorial | Demo

37. How to Code an Overlapping Tabbed Main Menu

How to Code an Overlapping Tabbed Main Menu

View Tutorial | Demo

38. Pure CSS Horizontal Menu

Pure CSS Horizontal Menu

View Tutorial | Demo

39. Pure CSS Menu With Infinite Sub Menus Tutorial

Pure CSS Menu With Infinite Sub Menus Tutorial

View Tutorial | Demo

40. Animated horizontal tabs

Animated horizontal tabs

View Tutorial & Demo

41. CSS Sprite Navigation Tutorial

CSS Sprite Navigation Tutorial

View Tutorial | Demo

42. Create your own drop down menu with nested submenus using CSS and a little JavaScript

Create your own drop down menu with nested submenus

View Tutorial | Demo

43. CSS Drop Down Menu Tutorial

CSS Drop Down Menu Tutorial

View Tutorial & Demo

44. Nicer Navigation with CSS Transitions

Nicer Navigation with CSS Transitions

View Tutorial | Demo

45. CSS Navigation Menus

CSS Navigation Menus

View Tutorial

46. Pure CSS Fish Eye Menu

Pure CSS Fish Eye Menu

View Tutorial | Demo

47. How to Create a CSS3 Tabbed Navigation

How to Create a CSS3 Tabbed Navigation

View Tutorial | Demo

48. Create an apple style menu and improve it via jQuery

Create an apple style menu and improve it via jQuery

View Tutorial | Demo

49. Create a multilevel Dropdown menu with CSS and improve it via jQuery

Create a multilevel Dropdown menu with CSS and improve it via jQuery

View Tutorial | Demo

50. Sweet tabbed navigation using CSS3

Sweet tabbed navigation using CSS3

View Tutorial | Demo

51. Create an Advanced CSS Menu Using the Hover and Position Properties

Create an Advanced CSS Menu Using the Hover and Position Properties

View Tutorial | Demo

52. Sexy Drop Down Menu w/ jQuery & CSS

Sexy Drop Down Menu w/ jQuery & CSS

View Tutorial | Demo

53. How to Create a Horizontal Dropdown Menu with HTML, CSS and jQuery

How to Create a Horizontal Dropdown Menu with HTML, CSS and jQuery

View Tutorial | Demo

54. CSS Express Drop-Down Menus

CSS Express Drop-Down Menus

View Tutorial | Demo

55. Professional Dark CSS Menu

Professional Dark CSS Menu

View Tutorial | Demo

56. Creating a Simple yet Stylish CSS Jquery Menu

Creating a Simple yet Stylish CSS Jquery Menu

View Tutorial | Demo

57. jQuery Drop Line Tabs

jQuery Drop Line Tabs

View Tutorial & Demo

58. Animated Menus Using jQuery

Animated Menus Using jQuery

View Tutorial | Demo

59. Make a Mega Drop-Down Menu with jQuery

Make a Mega Drop-Down Menu with jQuery

View Tutorial | Demo

60. Animated Navigation with CSS & jQuery

Animated Navigation with CSS & jQuery

View Tutorial | Demo

61. Horizontal Subnav with CSS

Horizontal Subnav with CSS

View Tutorial | Demo

62. Mega Drop Down Menus w/ CSS & jQuery

Mega Drop Down Menus w/ CSS & jQuery

View Tutorial | Demo

63. CSS dropdown menu without javascripting or hacks

CSS dropdown menu without javascripting or hacks

View Tutorial & Demo

64. CSS Drop Down Navigation Tutorial

CSS Drop Down Navigation Tutorial

View Tutorial

65. Sleek Pointer Menu 2

Sleek Pointer Menu 2

View Tutorial & Demo

66. CSS Overlapping Tabs Menu

CSS Overlapping Tabs Menu

View Tutorial | Demo

67. Horizontal CSS Menu With Icons

Horizontal CSS Menu With Icons

View Tutorial | Demo

68. Creating a Multi-Level Dropdown Menu using CSS and jQuery

Creating a Multi-Level Dropdown Menu using CSS and jQuery

View Tutorial | Demo

69. Create The Fanciest Dropdown Menu You Ever Saw

Create The Fanciest Dropdown Menu You Ever Saw

View Tutorial | Demo

70. Create A Speaking Block Navigation Menu Using Pure CSS

Create A Speaking Block Navigation Menu Using Pure CSS

View Tutorial | Demo

71. Horizontal CSS List Menu

Horizontal CSS List Menu

View Tutorial | Demo

72. CSS3 dropdown menu

CSS3 dropdown menu

View Tutorial | Demo

73. Making a CSS3 Animated Menu

Making a CSS3 Animated Menu

View Tutorial | Demo

74. How To Create A Clean CSS3 Navigation Bar

How To Create A Clean CSS3 Navigation Bar

View Tutorial | Demo

75. How to Create a Modern Ribbon Banner Navigation Bar with Pure HTML/CSS3

How to Create a Modern Ribbon Banner Navigation Bar with Pure HTML/CSS3

View Tutorial | Demo

Vertical CSS Menu Tutorials

76. CSS Pop-Out Menu Tutorial

CSS Pop-Out Menu Tutorial

Tutorial | Demo

77. CSS graphic menu with rollovers

CSS graphic menu with rollovers

Tutorial | Demo

78. Vertical CSS Menu With a ‘Behavior’ File

Vertical CSS Menu With a ‘Behavior’ File

Tutorial | Demo

79. Super Fantastic CSS Navigation Image Rollovers

Super Fantastic CSS Navigation Image Rollovers

Tutorial | Demo

80. Vertical Menu with Hover Effect using CSS

Vertical Menu with Hover Effect using CSS

Tutorial | Demo

81. How To Create A ‘Mootools Homepage’ Inspired Navigation Effect Using jQuery

How To Create A ‘Mootools Homepage’ Inspired Navigation Effect Using jQuery

Tutorial | Demo

82. Simple CSS Vertical Menus

Simple CSS Vertical Menus

View Tutorial | Demo

83. Create a Social Media Sharing Menu Using CSS and jQuery

Create a Social Media Sharing Menu Using CSS and jQuery

Tutorial | Demo

84. CSS3 Minimalistic Navigation Menu

CSS3 Minimalistic Navigation Menu

Tutorial | Demo

85. Beautiful Slide Out Navigation: A CSS and jQuery Tutorial

Beautiful Slide Out Navigation: A CSS and jQuery Tutorial

Tutorial | Demo

86. Awesome Cufonized Fly-out Menu with jQuery and CSS3

Awesome Cufonized Fly-out Menu with jQuery and CSS3

Tutorial | Demo

87. Two CSS vertical menu with show/hide effects

Two CSS vertical menu with show/hide effects

Tutorial | Demo

88. Animated Drop Down Menu with jQuery

Animated Drop Down Menu with jQuery

Tutorial | Demo

89. Clean and Attractive jQuery Vertical Menu Tutorial

Clean and Attractive jQuery Vertical Menu Tutorial

Tutorial | Demo

90. Nested Side Bar Menu

Nested Side Bar Menu

Tutorial & Demo

91. CSS menus

CSS menus

Tutorial | Demo

92. Simple Vertical CSS Menu

Simple Vertical CSS Menu

Tutorial

93. Sliding Jquery Menu

Sliding Jquery Menu

Tutorial | Demo

94. Reinventing a Drop Down with CSS and jQuery

Reinventing a Drop Down with CSS and jQuery

Tutorial | Demo

95. Drop-Down Menus, Horizontal Style

Drop-Down Menus, Horizontal Style

Tutorial | Demo

96. CSS Vertical Navigation with Teaser

CSS Vertical Navigation with Teaser

Tutorial | Demo

97. jQuery style menu with CSS3

jQuery style menu with CSS3

Tutorial | Demo

98. Green Vertical Navigation Menu

Green Vertical Navigation Menu

Tutorial | Demo

99. CSS: Sexy Vertical Popup Menu with CSS

CSS: Sexy Vertical Popup Menu with CSS

Tutorial | Demo

100. Uberlink CSS List Menus

Uberlink CSS List Menus

Tutorial | Demo

Overview

We hope you have enjoyed this list of CSS navigation menus and found something useful for your site (We made a point of including a mix of different menu styles: basic menus, flashy menus, menus which use jquery, menus that use pure CSS etc). If you know of any other great CSS menu tutorials, please feel free to share them in the comment area. :)


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