CSS

Using display:table has semantic effects in some screen readers

Sometimes you may want the layout properties that HTML tables have, but you don’t want the semantics of a table since you’re not really working with tabular data. A couple of examples are creating equal height boxes and making an unknown number of items flexibly occupy all available horizontal space.

In situations like these you can use CSS to tell any HTML elements you want to behave like they were tables, table rows, and table cells by using a combination of display:table, display:table-row, and display:table-cell. You get the layout you want without littering your markup with tables that shouldn’t be there. But there is a slight catch.

Read full post

Posted in , , .

Copyright © Roger Johansson



Styling button elements to look like links

Here’s a common scenario: you’re coding up a form with lots of buttons or need to add some elements that trigger JavaScript functions, and in the design comp some of these elements look like links. You intuitively reach for the a element, put some in the markup, add event handlers to them, and style them to match the design.

But wait a bit. Leaving the issue of putting elements that may rely on JavaScript to work in the markup for another time, should those elements really be links? What does the text on them say? What happens when you click them? If they trigger some kind of action that doesn’t match the normal link behaviour of going to another URL, it’s quite likely that you should really be using buttons.

Yes, I know. The designer says these elements need to look like links, period. And there was a time when making HTML buttons look like links wasn’t really possible in a cross-browser way. But these days you can get very, very close. It’s a bit tricky, but possible.

Read full post

Posted in .

Copyright © Roger Johansson



A Quick Look Into The Math Of Animations With JavaScript





 



 


In school, I hated math. It was a dire, dry and boring thing with stuffy old books and very theoretical problems. Even worse, a lot of the tasks were repetitive, with a simple logical change in every iteration (dividing numbers by hand, differentials, etc.). It was exactly the reason why we invented computers. Suffice it to say, a lot of my math homework was actually done by my trusty Commodore 64 and some lines of Basic, with me just copying the results later on.

These tools and the few geometry lessons I had gave me the time and inspiration to make math interesting for myself. I did this first and foremost by creating visual effects that followed mathematical rules in demos, intros and other seemingly pointless things.

There is a lot of math in the visual things we do, even if we don’t realize it. If you want to make something look natural and move naturally, you need to add a bit of physics and rounding to it. Nature doesn’t work in right angles or linear acceleration. This is why zombies in movies are so creepy. This was covered here before in relation to CSS animation, but today let’s go a bit deeper and look at the simple math behind the smooth looks.

Going From 0 To 1 Without Being Boring

If you’ve just started programming and are asked to go from 0 to 1 with a few steps in between, you would probably go for a for loop:

for ( i = 0; i <= 1; i += 0.1 ) {
  x = i;
  y = i;
…
}

This would result in a line on a graph that is 45 degrees. Nothing in nature moves with this precision:

45 degree graph, a result of a simple for loop

A simple way to make this movement a bit more natural would be to simply multiply the value by itself:

for ( i = 0; i <= 1; i += 0.1 ) {
  x = i;
  y = i * i;
}

This means that 0.1 is 0.01, 0.2 is 0.04, 0.3 is 0.09, 0.4 is 0.16, 0.5 is 0.25 and so on. The result is a curve that starts flat and then gets steeper towards the end:

graph of the value multiplied with itself

You can make this even more pronounced by continuing to multiply or by using the “to the power of� Math.pow() function:

for ( i = 0; i <= 1; i += 0.1 ) {
  x = i;
  y = Math.pow( i, 4 );
}

graph with several multiplications

This is one of the tricks of the easing functions used in libraries such as jQuery and YUI, as well as in CSS transitions and animations in modern browsers.

You can use this the same way, but there is an even simpler option for getting a value between 0 and 1 that follows a natural motion.

Not A Sin, Just A Natural Motion

Sine waves are probably the best thing ever for smooth animation. They happen in nature: witness a spring with a weight on it, ocean waves, sound and light.
In our case, we want to move from 0 to 1 smoothly.

To create a movement that goes from 0 to 1 and back to 0 smoothly, we can use a sine wave that goes from 0 to π in a few steps. The full sine wave going from 0 to π × 2 (i.e. a whole circle) would result in values from -1 to 1, and we don’t want that (yet).

var counter = 0;

// 100 iterations
var increase = Math.PI / 100;

for ( i = 0; i <= 1; i += 0.01 ) {
  x = i;
  y = Math.sin(counter);
  counter += increase;
}

half a sine wave

A quick aside on numbers for sine and cosine: Both Math.sin() and Math.cos() take as the parameter an angle that should be in radians. As humans, however, degrees ranging from 0 to 360 are much easier to read. That’s why you can and should convert between them with this simple formula:

var toRadian = Math.PI / 180;
var toDegree = 180 / Math.PI;

var angle = 30;

var angleInRadians = angle * toRadian;
var angleInDegrees = angleInRadians * toDegree;

Back to our sine waves. You can play with this a lot. For example, you could use the absolute value of a full 2 × π loop:

var counter = 0;
// 100 iterations
var increase = Math.PI * 2 / 100;

for ( i = 0; i <= 1; i += 0.01 ) {
  x = i;
  y = Math.abs( Math.sin( counter ) );
  counter += increase;
}

absolute value of a sine wave

But again, this looks dirty. If you want the full up and down, without a break in the middle, then you need to shift the values. You have to half the sine and then add 0.5 to it:

var counter = 0;
// 100 iterations
var increase = Math.PI * 2 / 100;

for ( i = 0; i <= 1; i += 0.01 ) {
  x = i;
  y = Math.sin( counter ) / 2 + 0.5;
  counter += increase;
}

halfed and moved sine wave

So, how can you use this? Having a function that returns -1 to 1 to whatever you feed it can be very cool. All you need to do is multiply it by the values that you want and add an offset to avoid negative numbers.

For example, check out this sine movement demo:

Sine jump demo

Looks neat, doesn’t it? A lot of the trickery is already in the CSS:

.stage {
  width:200px;
  height:200px;
  margin:2em;
  position:relative;
  background:#6cf;
  overflow:hidden;
}

.stage div {
  line-height:40px;
  width:100%;
  text-align:center;
  background:#369;
  color:#fff;
  font-weight:bold;
  position:absolute;
}

The stage element has a fixed dimension and is positioned relative. This means that everything that is positioned absolutely inside it will be relative to the element itself.

The div inside the stage is 40 pixels high and positioned absolutely. Now, all we need to do is move the div with JavaScript in a sine wave:

var banner = document.querySelector( '.stage div' ),
    start = 0;
function sine(){
  banner.style.top = 50 * Math.sin( start ) + 80 + 'px';
  start += 0.05;
}
window.setInterval( sine, 1000/30 );

The start value changes constantly, and with Math.sin() we get a nice wave movement. We multiply this by 50 to get a wider wave, and we add 80 pixels to center it in the stage element. Yes, the element is 200 pixels high and 100 is half of that, but because the banner is 40 pixels high, we need to subtract half of that to center it.

Right now, this is a simple up-and-down movement. Nothing stops you, though, from making it more interesting. The multiplying factor of 50, for example, could be a sine wave itself with a different value:

var banner = document.querySelector( '.stage div' ),
    start = 0,
    multiplier = 0;
function sine(){
  multiplier = 50 * Math.sin( start * 2 );
  banner.style.top = multiplier * Math.sin( start ) + 80 + 'px';
  start += 0.05;
}
window.setInterval( sine, 1000/30 );

The result of this is a banner that seems to tentatively move up and down. Back in the day and on the very slow Commodore 64, calculating the sine wave live was too slow. Instead, we had tools to generate sine tables (arrays, if you will), and we plotted those directly. One of the tools for creating great sine waves so that you could have bouncing scroll texts was the Wix Bouncer:

Wixbouncer - a tool to create sine waves

Circles In The Sand, Round And Round…

Circular motion is a thing of beauty. It pleases the eye, reminds us of spinning wheels and the earth we stand on, and in general has a “this is not computer stuff� feel to it. The math of plotting something on a circle is not hard.

It goes back to Pythagoras, who, as rumor has it, drew a lot of circles in the sand until he found his famous theorem. If you want to use all the good stuff that comes from this theorem, then try to find a triangle with a right angle. If this triangle’s hypothenuse is 1, then you can easily calculate the horizontal leg as the cosine of the angle and the vertical leg as the sine of the angle:

Sincos

How is this relevant to a circle? Well, it is pretty simple to find a right-angle triangle in a circle to every point of it:

Circle

This means that if you want to plot something on a circle (or draw one), you can do it with a loop and sine and cosine. A full circle is 360°, or 2 × π in radians. We could have a go at it — but first, some plotting code needs to be done.

A Quick DOM Plotting Routine

Normally, my weapon of choice here would be canvas, but in order to play nice with older browsers, let’s do it in plain DOM. The following helper function adds div elements to a stage element and allows us to position them, change their dimensions, set their color, change their content and rotate them without having to go through the annoying style settings on DOM elements.

Plot = function ( stage ) {

  this.setDimensions = function( x, y ) {
    this.elm.style.width = x + 'px';
    this.elm.style.height = y + 'px';
    this.width = x;
    this.height = y;
  }
  this.position = function( x, y ) {
    var xoffset = arguments[2] ? 0 : this.width / 2;
    var yoffset = arguments[2] ? 0 : this.height / 2;
    this.elm.style.left = (x - xoffset) + 'px';
    this.elm.style.top = (y - yoffset) + 'px';
    this.x = x;
    this.y = y;
  };
  this.setbackground = function( col ) {
    this.elm.style.background = col;
  }
  this.kill = function() {
    stage.removeChild( this.elm );
  }
  this.rotate = function( str ) {
    this.elm.style.webkitTransform = this.elm.style.MozTransform =
    this.elm.style.OTransform = this.elm.style.transform =
    'rotate('+str+')';
  }
  this.content = function( content ) {
    this.elm.innerHTML = content;
  }
  this.round = function( round ) {
    this.elm.style.borderRadius = round ? '50%/50%' : '';
  }
  this.elm = document.createElement( 'div' );
  this.elm.style.position = 'absolute';
  stage.appendChild( this.elm );

};

The only things that might be new here are the transformation with different browser prefixes and the positioning. People often make the mistake of creating a div with the dimensions w and h and then set it to x and y on the screen. This means you will always have to deal with the offset of the height and width. By subtracting half the width and height before positioning the div, you really set it where you want it — regardless of the dimensions. Here’s a proof:

offset issue

Now, let’s use that to plot 10 rectangles in a circle, shall we?

Simple circle

var stage = document.querySelector('.stage'),
    plots = 10;
    increase = Math.PI * 2 / plots,
    angle = 0,
    x = 0,
    y = 0;

for( var i = 0; i < plots; i++ ) {
  var p = new Plot( stage );
  p.setBackground( 'green' );
  p.setDimensions( 40, 40 );
  x = 100 * Math.cos( angle ) + 200;
  y = 100 * Math.sin( angle ) + 200;
  p.position( x, y );
  angle += increase;
}

We want 10 things in a circle, so we need to find the angle that we want to put them at. A full circle is two times Math.PI, so all we need to do is divide this. The x and y position of our rectangles can be calculated by the angle we want them at. The x is the cosine, and the y is the sine, as explained earlier in the bit on Pythagoras. All we need to do, then, is center the circle that we’re painting in the stage (200,200 is the center of the stage), and we are done. We’ve painted a circle with a radius of 100 pixels on the canvas in 10 steps.

The problem is that this looks terrible. If we really want to plot things on a circle, then their angles should also point to the center, right? For this, we need to calculate the tangent of the right-angle square, as explained in this charming “Math is fun� page. In JavaScript, we can use Math.atan2() as a shortcut. The result looks much better:

Tancircle

var stage = document.querySelector('.stage'),
    plots = 10;
    increase = Math.PI * 2 / plots,
    angle = 0,
    x = 0,
    y = 0;

for( var i = 0; i < plots; i++ ) {
  var p = new Plot( stage );
  p.setBackground( 'green' );
  p.setDimensions( 40, 40 );
  x = 100 * Math.cos( angle ) + 200;
  y = 100 * Math.sin( angle ) + 200;
  p.rotate( Math.atan2( y - 200, x - 200 ) + 'rad' );
  p.position( x, y );
  angle += increase;
}

Notice that the rotate transformation in CSS helps us heaps in this case. Otherwise, the math to rotate our rectangles would be much less fun. CSS transformations also take radians and degrees as their value. In this case, we use rad; if you want to rotate with degrees, simply use deg as the value.

How about animating the circle now? Well, the first thing to do is change the script a bit, because we don’t want to have to keep creating new plots. Other than that, all we need to do to rotate the circle is to keep increasing the start angle:

var stage = document.querySelector('.stage'),
    plots = 10;
    increase = Math.PI * 2 / plots,
    angle = 0,
    x = 0,
    y = 0,
    plotcache = [];

for( var i = 0; i < plots; i++ ) {
  var p = new Plot( stage );
  p.setBackground( 'green' );
  p.setDimensions( 40, 40 );
  plotcache.push( p );
}

function rotate(){
  for( var i = 0; i < plots; i++ ) {
    x = 100 * Math.cos( angle ) + 200;
    y = 100 * Math.sin( angle ) + 200;
    plotcache[ i ].rotate( Math.atan2( y - 200, x - 200 ) + 'rad' );
    plotcache[ i ].position( x, y );
    angle += increase;
  }
  angle += 0.06;
}

setInterval( rotate, 1000/30 );

Want more? How about a rotating text message based on this? The tricky thing about this is that we also need to turn the characters 90° on each iteration:

Rotated message

var stage = document.querySelector('.stage'),
    message = 'Smashing Magazine '.toUpperCase(),
    plots = message.length;
    increase = Math.PI * 2 / plots,
    angle = -Math.PI,
    turnangle = 0,
    x = 0,
    y = 0,
    plotcache = [];

for( var i = 0; i < plots; i++ ) {
  var p = new Plot( stage );
  p.content( message.substr(i,1) );
  p.setDimensions( 40, 40 );
  plotcache.push( p );
}
function rotate(){
  for( var i = 0; i < plots; i++ ) {
    x = 100 * Math.cos( angle ) + 200;
    y = 100 * Math.sin( angle ) + 200;
    // rotation and rotating the text 90 degrees
    turnangle = Math.atan2( y - 200, x - 200 ) * 180 / Math.PI + 90 + 'deg';
    plotcache[ i ].rotate( turnangle );
    plotcache[ i ].position( x, y );
    angle += increase;
  }
  angle += 0.06;
}

setInterval( rotate, 1000/40 );

Again, nothing here is fixed. You can make the radius of the circle change constantly, as we did with the bouncing banner message earlier (below is only an excerpt):

multiplier = 80 * Math.sin( angle );
for( var i = 0; i < plots; i++ ) {
  x = multiplier * Math.cos( angle ) + 200;
  y = multiplier * Math.sin( angle ) + 200;
  turnangle = Math.atan2( y - 200, x - 200 ) * 180 / Math.PI + 90 + 'deg';
  plotcache[ i ].rotate( turnangle );
  plotcache[ i ].position( x, y );
  angle += increase;
}
angle += 0.06;

And, of course, you can move the center of the circle, too:

rx = 50 * Math.cos( angle ) + 200;
ry = 50 * Math.sin( angle ) + 200;
for( var i = 0; i < plots; i++ ) {
  x = 100 * Math.cos( angle ) + rx;
  y = 100 * Math.sin( angle ) + ry;
  turnangle = Math.atan2( y - ry, x - rx ) * 180 / Math.PI + 90 + 'deg';
  plotcache[ i ].rotate( turnangle );
  plotcache[ i ].position( x, y );
  angle += increase;
}
angle += 0.06;

For a final tip, how about allowing only a certain range of coordinates?

function rotate() {
  rx = 70 * Math.cos( angle ) + 200;
  ry = 70 * Math.sin( angle ) + 200;
  for( var i = 0; i < plots; i++ ) {
    x = 100 * Math.cos( angle ) + rx;
    y = 100 * Math.sin( angle ) + ry;
    x = contain( 70, 320, x );
    y = contain( 70, 320, y );
    turnangle = Math.atan2( y - ry, x - rx ) * 180 / Math.PI + 90 + 'deg';
    plotcache[ i ].rotate( turnangle );
    plotcache[ i ].position( x, y );
    angle += increase;
  }
  angle += 0.06;
}
function contain( min, max, value ) {
  return Math.min( max, Math.max( min, value ) );
}

Summary

This was just a quick introduction to using exponentials and sine waves and to plotting things on a circle. Have a go with the code, and play with the numbers. It is amazing how many cool effects you can create with a few changes to the radius or by multiplying the angles. To make it easier for you to do this, below are the examples on JSFiddle to play with:

(il) (al)


© Christian Heilmann for Smashing Magazine, 2011.


Designers Know Your Code: Web Design Tutorials


  

As almost any web designer worth their salt, and a large percentage of web developers will tell you, to be fully considered a web designer you have to have some background in code. Not to the depth that full on developers must, but it really is unfair to the rest of those working on a website with us if we do not have some knowledge in a handful of key areas. Which is where these web design tutorials come in.

In this post we have gathered a handful of useful tutorials from these various areas of code that designers should have their hands in. We have standard CSS and CSS3 tutorials, HTML5 and also Javascript tuts as well. A little something for all three of the main code branches that web designers need to always be improving their grasps on. We hope that you find these web design tutorials helpful in your next or current project!

CSS Tutorials

30 CSS Best Practices for Beginners – CSS is a language that is used by nearly every developer at some point. While it’s a language that we sometimes take for granted, it is powerful and has many nuances that can help (or hurt) our designs. Here are thirty of the best CSS practices that will keep you writing solid CSS and avoiding some costly mistakes.

6 Ways To Improve Your Web Typography – Typography on the web is anything but simple, and for many, it is a troubling mystery. Today, we’re going to review six ways that web designers and developers can improve the typography of the sites they create.

3 Easy and Fast CSS Techniques for Faux Image Cropping – This article is a summary of a 3 fast and easy CSS techniques you can use to display only a portion of an image in your content. All techniques explained here actually need only couple of lines of CSS.

Build Multi-level Multi-column Multi Menus with pure CSS – works perfectly in most browsers, including IE 6, using absolutely no javascript

CSS Absolute Positioning: Create A Fancy Link Block – some tricks to create a fancy link block that make our links more attractive.

How to Create a Beautiful Dropdown Blogroll Without JavaScript – Dropdown menus are a great way of including a long list of links without cluttering up your page. The issue though is that they can be hard to style, but look quite ugly if you don’t. There isn’t a lot of flexibility with HTML’s select tags.

CSS3 Tutorials

CSS3 Minimalistic Navigation Menu – a simple CSS3 animated navigation menu, which degrades gracefully in older browsers and is future-proofed to work with the next generation of browsers.

CSS3 Tutorial: Sleek Card Pockets using CSS Only – learn how to create web card pockets using some great new CSS3 techniques.

CSS3 Animated Vignette Buttons – This tutorial uses a patterned background and places vignette-style .pngs over the top which are animated using transition.

CSS3 Music Player Menu – This tutorial maximizes power of CSS3 to create a CSS Music Player Menu with a Photoshop-like effect.

3D Animation Using Pure CSS3 – This tutorial uses the perspective property to create the 3d effect and transform and transition, to animate it.

Create a Swish CSS3 Folded Ribbon in 5 Minutes – Take one line of markup, a couple of CSS3 rules (no images), and you can have yourself a swish folded ribbon effect in five minutes.

HTML5 Tutorials

HTML5 : The Basics – This tutorial introduces HTML5 and its basic features as well as explains the key differences from HTML 4.01 and XHTML 1.0 so you can start preparing yourself and your sites for the transition.

Have A Field Day With HTML5 Forms – Take a look at how to style a beautiful HTML5 form using some advanced CSS and latest CSS3 techniques.

Preparing for HTML5 with Semantic Class Names – A brief introduction to the new structural elements in the HTML 5 Working Draft, and how to use semantic class names in HTML 4.01 or XHTML 1.0 markup that correspond to the names of those structural elements.

Drag and Drop – This tutorial will teach you how to create a HTML 5 page that uses the new drag and drop feature.

How to Make an HTML5 iPhone App – This tutorial will show you how to create an offline HTML5 iPhone application, specifically, a tetris game.

Create Vector Masks Using the HTML5 Canvas – This tutorial looks at how to use the canvas tag and clipping to create images that aren’t so rectangular.

Javascript Tutorials

Javascript – An easy introduction – Javascript is used to add interactivity and functionality to a site. It has many uses, from detecting the viewers web browser to validating form input.

Nested Arrays in Javascript – Like most programming languages, JavaScript lets you create arrays inside arrays, known as nested arrays. In a nested array, the elements of one array are themselves arrays.

jQuery for Absolute Beginners – Fifteen video tutorials that teach you EXACTLY how to use the jQuery library. Start by downloading the library and eventually work up to creating an AJAX style-switcher.

iPhoto-like image resizing using Javascript – This tutorial uses the script.aculo.us slider control to capture input values, then converts those values into something useful.

Learn How To Detect Browser in Javascript – In this tutorial you will learn how to detect the browser in javascript so that you can then serve the suitable information.

Words Validation with Javascript – This tutorial will explain you how to filter out inappropriate words from being updated or sent from your website.

(rb)


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.


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