HTML5: Introduction to <canvas>

Canvas: Tutorial of basic canvas functionality, canvas properties and methods

The HTML5 Canvas specification is a JavaScript API for coding drawings. The canvas API allows the definition of a canvas context object as the <canvas> element on your HTML page inside which we can draw.

We can draw in both 2D and 3D (WebGL) context. 2D is available in all the modern Web browsers, IE9, and via excanvas.js in current versions of IE, and will be more thoroughly introduced below. 3D is still nascent, with only experimental implementations.

2D context provides a simple yet powerful API for performing quick drawing operation, on a 2D bitmap surface. There is no file format, and you can only draw using script. You do not have any DOM nodes for the shapes you draw — you’re drawing pixels, not vectors. OK, not true. You are drawing vectors, but once drawn, only the pixels are remembered.

Your first <canvas>

Being a very basic introduction to canvas, we are only going to cover basic shapes and lines. If you are unfamiliar with JavaScript, the syntax may at first seem a bit confusing. If you are familiar, it should make sense.

Step 1 is adding the <canvas> element to your document. In terms of HTML, the only step involved in adding a canvas to your document is adding the <canvas> element to your document:

<canvas id="flag" width="320" height="220">
You don't support Canvas. If you did, you would see a flag

That is it for the HTML part of it. . We could simply have written <canvas></canvas>. However, you should include an id for ease of JavaScript targeting, but you could also target via placement within the DOM. You can also define the width and height of the canvas, though you can define that in the CSS as well. We’ve also included alternative content for users that don’t support or otherwise can’t see your <canvas> content

With that, we’ve created your blank drawing board, or canvas. Everything else takes place in our JavaScript files. Step 2 is drawing on our canvas. From now on, everything is in javascript. We target the canvas node with getElementById(‘flag’) or getElementsByTagName(‘canvas’)[0], initialize a 2D context and start drawing using 2D context API commands. We can draw the Japanese flag:

var el= document.getElementById("flag");

if (el && el.getContext) {
var context = el.getContext('2d');
context.fillStyle = "#ffffff";
context.strokeStyle = "#CCCCCC";
context.lineWidth = 1;
context.shadowOffsetX = 5;
context.shadowOffsetY = 5;
context.shadowBlur = 4;
context.shadowColor = 'rgba(0, 0, 0, 0.4)';
context.strokeRect(10, 10, 300, 200);
context.fillRect(10, 10, 300, 200);
context.fillStyle = "#d60818";
context.arc(160, 107, 60, 0, Math.PI*2, false);


The first line finds your <canvas> element by matching the element’s id attribute. Before creating the 2D context, we check to make sure that the canvas element has been found AND that the browser supports canvas by checking for the existence of the getContext method.

We have to then create a reference to a context using the getContext(contextId) method of the canvas element –‘2d’ and ‘3d’ are the contextId value choices. If context creation is successful, we are finally free to draw in our canvas.

Before drawing a shape, we must define the look and feel of the shape we want to draw by setting properties on the context object. We define the look of the border (stroke and linewidth) properties and the shadow of our first rectangle, which we draw with the strokeRect() method. We pass the same parameters as our SVG example: (10, 10, 300, 200). The four values are the x-offset, the y-offset, width and height respectively. Once the script executes a command, the script forgets about what it has done, and moves onto the next line of code. Unlike our SVG example, the rectangle we’ve drawn on our canvas is not part of the DOM.

When we draw our second rectangle using the fillRect method, which paints rectangles using the previously set fillStyle property, we need to pass the coordinates again as the DOM does not remember our first rectangle, though it can access pixel information.

Both rectangle method calls have the same parameters — 10, 10, 300, 200 — we’ve drawn our fill rectangle directly on top of our dropshadow rectangle. We could have created an object with those coordinates and passed it to both methods, but we can’t tell the canvas to access the first rectangle’s coordinates and copy to the second after the method call

As mentioned above, once you paint onto the canvas, the DOM has no recollection of what you’ve painted. Yes, the JavaScript remembers the values of the properties you’ve set, but the pixels that are places on the canvas are just pixels of color. As we start the process of drawing the disc or sun on our flag, the DOM has no recollection of which pixels were painted with which colors, but it does remember some properties we set, like our shadowColor. As we don’t want a shadow on the red circle, we can set the shadowColor to transparent.

Next we define our circle. We are not actually drawing the circle yet. context . arc(x-offset of center, y-offset of center, radius, startAngle, endAngle, anticlockwise) adds points to an arced path creating a virtual circumference of a circle described by the arguments, starting at the given start angle, in our case 0, which is on the right horizon, and ending at the given end angle, going in the given direction, which in our case is clockwise. Had our endAngle been less than 2Π, our circle would have been flattened: the start and end points connected by a straight line. Π would have created a half circle. We also re-define the fill color, from white to red. We then paint the circle we created using the fill() method that fills the described arc in the fillStyle color.

We haven’t even touched the surface of what <canvas> can do. is a fun page to learn simple shapes, colors, shadows, text, images, transformation, animation and mouse movement with <canvas>.

Canvas functions and properties


Set the fillStyle


Set the strokeStyle


Line widths


Line join styles

   context.lineJoin="bevel || round || miter"

Line end styles

   context.lineCap="butt || round || square"


Draw a rectangle

   context.strokeRect(left, top, width, height)

Fill a rectangle

   context.fillRect(left, top, width, height)

Erase a rectangle

   context.clearRect(left, top, width, height)


Begin a path


Complete a path


Move the pen to a location

   context.moveTo(horizontal, vertical)

Draw a straight line from current point to a new location

   context.lineTo(horizontal, vertical)

Stroke the current path


Fill the current path



Shadow color


Shadow horizontal offset


Shadow vertical offset


Shadow blur


Canvas versus SVG

HTML5 Canvas and SVG may seem similar, in that they are both web technologies that allow you to create rich graphics inside the browser, but they are fundamentally different. In SVG, you ‘draw’ with XML. For canvas, you draw with JavaScript. Canvas is the painting of pixels onto a canvas, once painted, each pixel is forgotten. SVG, on the other hand, creates DOM nodes, accessible until deleted or until navigation away from the page. They both have their advantages and disadvantages.

SVG is resolution independent, making SVG an excellent choice for user interfaces of all sizes as it allows scaling for all screen resolutions. SVG is an XML file format enabling easy accessibility. SVG can be animated using a declarative syntax, or via JavaScript. Each element becomes part of and is accessible via the SVG DOM API in JavaScript. However, anything that accesses the DOM repeatedly slows the page down.

Canvas is all drawn in pixels. Zooming can lead to pixilation. Canvas is inherently less accsessible: accessibility is limited mainly to including fallback content should canvas not render. Interactivity requires redrawing of each pixel. There are no DOM nodes for anything you draw. There’s no animation API, instead timers are generally used for updating the canvas at quick intervals. Canvas gives you a surface to draw onto with the API of the context you choose. Canvas, however, is very well suited for editing of images, generating raster graphics such as for games or fractals, and operations requiring pixel-level manipulation. Canvas can also be exported to gif or jpeg.

Win a Ticket to Front End Conference

We have one free ticket for a lucky winner to for a lucky winner.

To enter the drawing Tweet “I wanna go to in Florida. Follow @estellevw and retweet to win. or something more imaginative, with a link to this post. One lucky retweeter / follower will be selected from the group of retweeters on Sunday night.

Here is more on the conference:
7 Awesome Speakers
July 23, 2010
A single day design conference focused on content, presentation and behavior.
Register Now for $129

Oh, and if you want to beg, you can do so in the comments.


Microdata let you create your own vocabularies beyond HTML5 and extend your web pages with custom semantics. Microdata uses the new to HTML5 attributes of itemscope, itemprop, itemref and itemtype. The itemscope attribute is used create an item. The itemprop attribute is used to add a property to an item. If an itemprop has associated properties that are not descendants of that itemprop, you can associate those properties with that itemprop by using the itemref attribute: the entity that has the itemscope attribute also accepts the itemref attribute that takes as it’s value a space separated list of id’s of entities that should be crawled in addition to the itemprop’s descendants.

Microdata is most useful when it is used in contexts where other authors and readers are able to cooperate to make new uses of the markup. You can create your own types of microdata markup marked up on a page that doesn’t expect its microdata to be re-used. Use the itemtype attribute to provide a URI. There doesn’t need to be anything at that URI, but all of the itemscopes of the same itemtype should reference the same URI. It is most useful, however, to not create your own vocabulary if one exists for a similar purpose. There are several microdata vocabularies that have been standardized that coincide with Microformat conventions.

Microformats are very similar to microdata. In fact, microdata can be viewed as an extension of the existing microformat idea that attempts to address the deficiencies of microformats without the complexity of systems such as RDFa. Instead of using the new itemscope, itemprop, itemtype, etc. attributes, Microformats repurpose the class attribute to provide human and machine readable semantic meaning to data, microdata

Microformats are standardized sets of vocabularies that are both human and machine-readable. They are web page conventions used to describe common information types including events, reviews, address book information and calendar events. Each entity, such as a person, event or business, has its own properties, such as name, address and phone number.

In general, microformats use the class attribute in opening HTML tags (often <span> or <div>) to assign brief, descriptive names to entities and their properties. Unlike Microdata, Microformats are NOT part of the HTML5 specification.

Here’s an example of a short HTML block showing my contact information for me.

<li><img src="" alt="photo of Estelle Weyl "/></li>
<li><a href="">Estelle Weyl</a></li>
<li>1234 Main Street<br />
San Francisco, CA 94114</li>

Here is the same HTML marked up with the hCard (person) microformat.

<ul id="hcard-Estelle-Weyl" class="vcard">
<li><img src="" alt="photo of Estelle Weyl" class="photo"/></li>
<li><a class="url fn" href="">Estelle Weyl</a></li>
<li class="adr">
<span class="street-address">1234 Main Street</span>
<span class="locality">San Francisco</span>, <span class="region">CA</span>, <span class="postal-code">94114</span> <span class="country-name hidden">USA</span>
<li class="tel">415.555.1212</li>

In the first line, class="vcard" indicates that the HTML enclosed in the <ul> describes a person: in this case, me. The microformat used to describe people is called hCard but is referred to in HTML as vcard. While confusing, it isn’t a typo.

The rest of the example describes properties of the person, including a photo, name, address, URL and phone, with each property having a class attribute describing the property. For example, fn describes my full name.
Properties can contain other properties. In the example above, the property adr encompasses all components of my fake address including street-address, locality, region and postal-code. With a little CSS we can hide the ‘hidden’ class and add a line break between street-address and locality. To create your own hcard, visit

The same content could be written with microdata:

<ul id="hcard-Estelle-Weyl" itemscope itemtype="">
<li><img src="" alt="photo of Estelle Weyl" class="photo"/></li>
<li><a href="" itemprop="fn">Estelle Weyl</a></li>
<li itemprop="adr">
<span itemprop="street-address">1234 Main Street</span>
<span itemprop="locality">San Francisco</span>, <span itemprop="region">CA</span>, <span itemprop="postal-code">94114</span> <span class="hidden" itemprop="country-name">USA</span>
<li itemprop="tel">415.555.1212</li>

Or you can combine the two:

<ul id="hcard-Estelle-Weyl" class="vcard" itemscope itemtype="">
<li><img src="" alt="photo of Estelle Weyl" class="photo"/></li>
<li><a class="url fn" href="" itemprop="fn">Estelle Weyl</a></li>
<li class="adr" itemprop="adr">
<span class="street-address" itemprop="street-address">1234 Main Street</span>
<span class="locality" itemprop="locality">San Francisco</span>, <span class="region" itemprop="region">CA</span>, <span class="postal-code" itemprop="postal-code">94114</span> <span class="country-name hidden" itemprop="country-name">USA</span>
<li class="tel" itemprop="tel">415.555.1212</li>
</ul> provides information about microdata.

Search engines will not display content that is not visible to the user. Providing search engines with more detailed information, even if you don’t want that information to be seen by visitors to your page, can be helpful. Event time in ISO data format helps ensure that events are placed in the right time sequence and correctly placed in calendars. Providing geo coordinates of latitude and longitude can help ensure correct mapping. Providing semantics around reviews provides Google with added meta data that it can use to better display your search results leading to a higher click thru rate.

To enable the web to be a single global database, being able to parse the available data into meaningful data points is required. Microdata and microformats help make otherwise non-descript data meaningful to parsers.

HTML5 Input Attributes & Browser Support

I have updated the HTML5 Web Form Browser support grid to include the various input attributes, for what input type each is relevant, and which browsers support each attribute for each type.



Text, search, url, tel Email Password Dateandtime
range color Checkbox, radio file
accept WK, O,
autocomplete O O O O O O O
autofocus WK, O WK, O WK,O WK, O WK, O WK, O WK, O WK, O
checked WK, O,
disabled WK, O,
WK, O,
WK, O,
WK, O,
WK, O,
WK, O,
WK, O,
WK, O,
WK, O,
Form O O O O O O O O
list WK, O WK, O WK, O WK, O WK, O WK, O
max O, WK O, WK O, WK
maxlength WK, O,
WK, O,
WK, O,
min O, WK O, WK O, WK
multiple FF, WK, IE FF, WK
Name WK, O,
WK, O,
WK, O,
WK, O,
WK, O,
WK, O,
WK, O, FF, IE WK, O,
WK, O,
pattern WK, O WK, O WK, O
placeholder WK WK WK
readonly WK, O,
WK, O,
WK, O,
WK, O,
WK, O,
required WK, O WK, O WK, O WK, O WK, O WK, O WK, O
size WK, O,
WK, O,
WK, O,
step O, WK O, WK O, WK
checked WK, O,
value WK, O,
WK, O,
WK, O,
WK, O,
WK, O,
WK, O,
WK, O, FF, IE WK, O,
WK, O,
  • WK = Webkit (tested Safari 5)
  • O = Opera (10.5 on Mac)
  • FF = Firefox (3.6.3 on Mac)
  • IE = Internet Explorer (IE8 on XP)

Browsers that don’t support the type attribute may still support other attributes in the input as the browser may support attributes on the text input type (such as maxlength or size), and will therefore support those attributes on a type it doesn’t support, as the input will default to text type. For example, while IE and FF don’t currently support the email type, they do support the multiple attribute on that type, since they will accept a text type including space separated email addresses.

Resources for this effort include:

Converting from HSL to RGB() & Hexadecimal Colors

I created a ‘spreadsheet’ of the HSL() (hue, saturation, lightness) colors. I noticed if you inspect the file in Firebug, the left hand console gives you the rgb() color, and the right hand inspector gives you the hexadecimal #RRGGBB color.

To translate a color from HSL() to RGB() or #FFF, visit the HSL() ‘spreadsheet’ and inspect the color in Firebug. Simple as that.

Of course, you don’t have to use my spreadsheet. Simply declare an inline hsl() value on a div in your own sandbox. Inspecting it in Firebug will give you both the rgb() value (in the left hand firebug console, inline on the element) and in the right hand console, under{} in the style console.

CSS Color Formats and HSL

Prior to CSS3, we had 3 types of color formats: there was the hexadecimal format (and shorthand hex format), rgb() format and named colors. CSS3 adds support for HSL, HSLA and RGBA. Here are the formats we have in CSS3:

Color Syntax Example Definition
#RRGGBB #FF00FF hexadecimal format (tutorial)
#RGB #F0F shorthand hexadecimal format
rgb(r,g,b) rgb(255, 0, 255) red, green blue (tutorial)
hsl(h,s,l) hsl(300, 100%, 50%) hue, saturation, lightness
cmyk(c,m,y,k) cmyk(29%, 55%, 0, 0) Cyan, Magenta, Yellow, Black
hsla(h,s,l,a) hsla(300, 100%, 50%, 1) hue, saturation, lightness, opacity
rgba(r,g,b) rgba(255, 0, 255, 1) red, green, blue, opacity
named colors fuchsia see color name tutorial
transparent transparent no color (transparent)
currentColor currentColor color of the text for that element

In part I we discussed #RRGGBB, #RGB, rgb(), rgba() and touched upon HSL and HSLA colors. In this section we go further into HSLA, and discuss the new keyterm currentColor, and the color type that didn’t make it into the CSS3 specifications: flavor.

Hue, Saturation and Lightness

HSL stands for hue, saturation and lightness. The hue value in included in degrees from 0 to 359, with percentages for saturation and lightness, with 50% being the norm for lightness and 100% being the norm for saturation.

Lightness of 0% will be white, 50% will be the actual hue, and 100% will be black. Saturation of 100% will be the hue, and saturation of 0 will give you a shade of gray from white to #808080 to black depending on the lightness.

Values for hues include: 0 = red, 60 = yellow, 120 = green, 180 = cyan, 240 = blue, 300 = magenta, and everything in between. Each table below represents one hue. Twelve equally spaced colors (i.e.
at 30° intervals) have been chosen from the color circle: red,
yellow, green, cyan, blue, magenta, with all the intermediate colors (the
last is the color between magenta and red).

The X axis of each table represents the saturation (100%, 75%, 50%,

The Y axis represents the lightness. The higher the percent, the lighter the color is, the lower the percent, the darker, with 50% being ‘normal’. 100% lightness has been omitted from the tables below, since it’s always white, no matter the hue. Similarly, 0% lightness has been omitted, since it always renders black, no matter the hue.

0° (Red)






hsl(0, 100%, 88%)

hsl(0, 75%, 75%)
63 hsl(0, 100%, 63%) hsl(0, 75%, 63%) hsl(0, 50%, 63%) hsl(0, 25%, 63%)
50 hsl(0, 100%, 50%) hsl(0, 75%, 50%) hsl(0, 50%, 50%) hsl(0, 25%, 50%)

13 hsl(60, 100%, 13%) hsl(60, 75%, 13%) hsl(60, 50%, 13%) hsl(60, 25%, 13%)
30° (Orange)






hsl(30, 100%, 88%) hsl(30, 75%, 88%) hsl(30, 50%, 88%) hsl(30, 25%, 88%)

hsl(30, 100%, 75%) hsl(30, 75%, 75%) hsl(30, 50%, 75%) hsl(30, 25%, 75%)
63 hsl(30, 100%, 63%)
50 hsl(30, 100%, 50%)

hsl(30, 100%, 38%)
25 hsl(30, 100%, 25%)
13 hsl(30, 100%, 13%) hsl(30, 25%, 13%)
60° (Yellow)






hsl(60, 100%, 88%) hsl(60, 75%, 88%) hsl(60, 50%, 88%) hsl(60, 25%, 88%)

hsl(60, 100%, 75%) hsl(60, 75%, 75%) hsl(60, 50%, 75%) hsl(60, 25%, 75%)
63 hsl(60, 100%, 63%) hsl(60, 75%, 63%) hsl(60, 50%, 63%) hsl(60, 25%, 63%)
50 hsl(60, 100%, 50%) hsl(60, 75%, 50%) hsl(60, 50%, 50%) hsl(60, 25%, 50%)

hsl(60, 100%, 38%) hsl(60, 75%, 38%) hsl(60, 50%, 38%) hsl(60, 25%, 38%)
25 hsl(60, 100%, 25%) hsl(60, 75%, 25%) hsl(60, 50%, 25%) hsl(60, 25%, 25%)
13 hsl(60, 100%, 13%) hsl(60, 75%, 13%) hsl(60, 50%, 13%) hsl(60, 25%, 13%)
90° Yellow-Green
100% 75% 50% 25%
88 hsl(90, 100%, 88%)
75 hsl(90, 25%, 75%)
63 hsl(90, 100%, 63%) hsl(90, 75%, 63%) hsl(90, 50%, 63%) hsl(90, 25%, 63%)
50 hsl(90, 100%, 50%) hsl(90, 25%, 50%)
38 hsl(90, 25%, 38%)
25 hsl(90, 10%, 25%) hsl(90, 75%, 25%) hsl(90, 50%, 25%) hsl(90, 25%, 25%)
13 hsl(90, 25%, 13%)
120° (Green)






hsl(120, 100%, 88%) hsl(120, 25%, 88%)
75 hsl(120, 25%, 75%)
63 hsl(120, 25%, 63%)
50 hsl(120, 100%, 50%) hsl(120, 25%, 50%)
38 hsl(120, 100%, 38%) hsl(120, 75%, 38%) hsl(120, 50%, 38%) hsl(120, 25%, 38%)
25 hsl(120, 25%, 25%)
13 hsl(120, 25%, 13%)
150° Green-Cyan

100% 75% 50% 25%

hsl(150, 100%, 88%) hsl(150, 75%, 88%) hsl(150, 50%, 88%) hsl(150, 25%, 88%)
75 hsl(150, 100%, 75%) hsl(150, 75%, 75%) hsl(150, 50%, 75%) hsl(150, 25%, 75%)
63 hsl(150, 100%, 63%) hsl(150, 75%, 63%) hsl(150, 50%, 63%) hsl(150, 25%, 63%)
50 hsl(150, 100%, 50%) hsl(150, 75%, 50%) hsl(150, 50%, 50%) hsl(150, 25%, 50%)
38 hsl(150, 100%, 38%) hsl(150, 75%, 38%) hsl(150, 50%, 38%) hsl(150, 25%, 38%)
25 hsl(150, 100%, 25%) hsl(150, 75%, 25%) hsl(150, 50%, 25%) hsl(150, 25%, 25%)
13 hsl(150, 100%, 13%) hsl(150, 75%, 13%) hsl(150, 50%, 13%) hsl(150, 25%, 13%)
180° (Cyan)

100% 75% 50% 25%

hsl(180, 100%, 88%) hsl(180, 50%, 88%) hsl(180, 25%, 88%)
75 hsl(180, 75%, 75%) hsl(180, 25%, 75%)
63 hsl(180, 100%, 63%) hsl(180, 50%, 63%) hsl(180, 25%, 63%)
50 hsl(180, 100%, 50%) hsl(180, 75%, 50%) hsl(180, 25%, 50%)
38 hsl(180, 100%, 38%) hsl(180, 50%, 38%) hsl(180, 25%, 38%)
25 hsl(180, 75%, 25%) hsl(180, 25%, 25%)
13 hsl(180, 100%, 13%) hsl(180, 50%, 13%) hsl(180, 25%, 13%)
210° Cyan-Blue

100% 75% 50% 25%

hsl(210, 100%, 88%) hsl(210, 75%, 88%) hsl(210, 50%, 88%) hsl(210, 25%, 88%)
75 hsl(210, 75%, 75%) hsl(210, 25%, 75%)
63 hsl(210, 100%, 63%) hsl(210, 50%, 63%) hsl(210, 25%, 63%)
50 hsl(210, 100%, 50%) hsl(210, 75%, 50%) hsl(210, 25%, 50%)
38 hsl(210, 100%, 38%) hsl(210, 50%, 38%) hsl(210, 25%, 38%)
25 hsl(210, 75%, 25%) hsl(210, 25%, 25%)
13 hsl(210, 100%, 13%) hsl(210, 50%, 13%) hsl(210, 25%, 13%)
240° (Blue)

100% 75% 50% 25%

hsl(240, 100%, 88%) hsl(240, 25%, 88%)
75 hsl(240, 100%, 75%) hsl(240, 75%, 75%) hsl(240, 50%, 75%) hsl(240, 25%, 75%)
63 hsl(240, 25%, 63%)
50 hsl(240, 100%, 50%) hsl(240, 25%, 50%)
38 hsl(240, 100%, 38%) hsl(240, 75%, 38%) hsl(240, 50%, 38%) hsl(240, 25%, 38%)
25 hsl(240, 25%, 25%)
13 hsl(240, 25%, 13%)
270° Blue-Magenta

100% 75% 50% 25%

hsl(270, 100%, 88%) hsl(270, 75%, 88%) hsl(270, 50%, 88%) hsl(270, 25%, 88%)
75 hsl(270, 25%, 75%)
63 hsl(270, 25%, 63%)
50 hsl(270, 100%, 50%) hsl(270, 25%, 50%)
38 hsl(270, 25%, 38%)
25 hsl(270, 25%, 25%)
13 hsl(270, 100%, 13%) hsl(270, 75%, 13%) hsl(270, 50%, 13%) hsl(270, 25%, 13%)
300° (Magenta)

100% 75% 50% 25%

hsl(300, 100%, 88%) hsl(300, 75%, 88%) hsl(300, 50%, 88%) hsl(300, 25%, 88%)
75 hsl(300, 100%, 75%) hsl(300, 75%, 75%) hsl(300, 50%, 75%) hsl(300, 25%, 75%)
63 hsl(300, 100%, 63%) hsl(300, 75%, 63%) hsl(300, 50%, 63%) hsl(300, 25%, 63%)
50 hsl(300, 100%, 50%) hsl(300, 75%, 50%) hsl(300, 50%, 50%) hsl(300, 25%, 50%)
38 hsl(300, 100%, 38%) hsl(300, 75%, 38%) hsl(300, 50%, 38%) hsl(300, 25%, 38%)
25 hsl(300, 100%, 25%) hsl(300, 75%, 25%) hsl(300, 50%, 25%) hsl(300, 25%, 25%)
13 hsl(300, 100%, 13%) hsl(300, 75%, 13%) hsl(300, 50%, 13%) hsl(300, 25%, 13%)
330° Magenta-Red

100% 75% 50% 25%

hsl(330, 100%, 88%) hsl(330, 25%, 88%)
75 hsl(330, 25%, 75%)
63 hsl(330, 25%, 63%)
50 hsl(330, 100%, 50%) hsl(330, 25%, 50%)
38 hsl(330, 100%, 38%) hsl(330, 75%, 38%) hsl(330, 50%, 38%) hsl(330, 25%, 38%)
25 hsl(330, 100%, 25%) hsl(330, 75%, 25%) hsl(330, 50%, 25%) hsl(330, 25%, 25%)
13 hsl(330, 25%, 13%)

There is a grid with many more colors at if you want to see how more hsl combinations render and have a browser that supports HSL rendering. The grid above is coded with hexadecimal colors, since internet explorer does not understand HSL colors. The grids at require Opera, Safari, Firefox, Chrome or IE9 to view.


Similar to rgb() with rgba(), hsl() also has an alpha transparent call, hsla(). The syntax is hsla, followed by hue in degrees, saturation in percentage, lightness in percentage and alpha value from 0-1, encompassed in parenthesis.

For example: hsla(300, 100%, 50%, 0.5) is magenta at 50% opacity.

Introducting CSS3 Colors

Defining colors in red, green and blue is supported by CSS3 in several ways.

Hexadecimal Values

You can declare the hexadecimal value of your red, green and blue with hexadecimal values ranging from 0 to 255 in the format of 00 to FF, put the three together preceded by a hash (#), and that’s the color. For example, #FFFFFF for complete saturation of red, green and blue comes out white, #000000 for lack of any color comes out black. A mix and match of hexadecimal values from 0-255 using any two characters A-F0-9, case insensitive, for the red green and blue values, combined together in the order of red, green and blue can create millions of colors.

Did I mention case-insensitivity? It doesn’t matter if you use #FFCC00 or #ffcc00 – the value syntax is case insensitive.

The RGB hexadecimal notation also has a shorthand, of #RGB, where the R, G, and B are a single character, A-F0-9, case insensitive, put together, preceded by a hash mark. Identical to the long format, the browser expands the RGB value, such as #369 to #336699.

All browsers support all of the hexadecimal values, both short hand and long hand. There used to be a discussion of web-safe colors. Web face colors has been a non-issue, even for hand held devices. It is safe to use any color combination (may not be pretty or legible, but it will render).

rgb() syntax

Instead of using the hexadecimal values for RGB, you can use the base 10 value for your mix of red, green and blue, or even percentages. Instead of preceding your color with a hash tag, the syntax is the keyterm ‘rgb’ follow by your comma-separated values in parenthesis.

#FFFFFF = #FFF = rgb(255, 255, 255) = rgb(100%, 100%, 100%).

All browsers support all of the RGB color combinations in general. Some browsers allow the mixing of rgb() numbers with percents, but the specifications clearly state that this is not expected behavior, and not all browsers support it, so avoid mixing value types.

What’s new?

New in CSS3 is RGBA. RGBA is similar to RGB, but with an added A for AlphaTransparency. The rgb() specifications were extended in CSS3 to include ‘alpha’ to allow specification of the opacity of a color. The first three values are still red, green, blue. Thee fourth value is the opacity level, 1 being fully opaque, 0 being fully transparent, and any float being everything in-between.

rgb(255, 255, 255) = rgb(100%, 100%, 100%) = rgba(255, 255, 255, 1)

The above are all equal to white, since 1 means fully opaque. But don’t get confused: rgba(0,0,0,0) is transparent, not black, because the level of opacity is none.

Unlike RGB, there is no hexadecimal notation for RGBA. Unlike RGB, the IEs don’t understand RGBA. IE8 correctly ignores properties with rgba() in the value. IE6 and IE7 overwrite values, without understanding them, and generally inherit the default value when confused.

RGBA is going to be extremely useful as drop shadows on boxes and text become better supported. While it is very common to see text-shadow: 3px 3px 3px #CCCCCC; or text-shadow: 3px 3px 3px #000000;— including a gray or black shadow, the effect looks much better if you write text-shadow: 3px 3px 3px rgba(0, 0, 0, 0.4); While the color #CCCCCC and rgba(0,0,0,0.4) look similar when solid over a white background, when included as a shadow, the #CCCCCC starts off as a solid grey, which looks a little off. The RGBA color is always translucent, which looks MUCH better.

Hue, Saturation and Lightness

HSL stands for hue, saturation and lightness. The HSL format simplifies color palette creation as you can pick a hue as the base, then manipulate the lightness/darkness and saturation of the hue selected.

HSL is a new color type added in CSS3, standing for hue, saturation and lightness. The syntax is similar to rgb(), but instead of including the values for red, green and blue, the color value accepts values in degrees from 0 to 359 for hue, and percentages for saturation and lightness, with 50% being the norm for lightness and 100% being the norm for saturation.

Lightness of 0% will be white, 50% will be the actual hue, and 100% will be black. Saturation of 100% will be the hue, and saturation of 0 will give you a shade of gray from white to #808080 to black depending on the lightness.

Up Next

In part 2, we’ll cover hsl and hsla in greater depth.

Making IE recognize HTML5 elements

IE6, IE7 and IE8 don’t recognize the HTML elements. This causes a major problem when you’re using the HTML5 elements, such as ‘aside’, as part of (or your complete) selector in your CSS. Add this snippet either in your HTML or as a condionally included file, and IE will be able to handle your HTML5 elements as selectors in your CSS, and as members of your DOM in javascript. (thanks to John Resig for the inspiration)

<!--[if IE]>
<script type="text/javascript">
var html5elmeents = "address|article|aside|audio|canvas|command|datalist|details|dialog|figure|figcaption|footer|header|hgroup|keygen|mark|meter|menu|nav|progress|ruby|section|time|video".split('|');
for(var i = 0; i < html5elmeents.length; i++){

Printing HTML5 in Internet Explorer: where HTML5 is not supported

The code snipped above does wonders for enabling the various Internet Explorer’s to understand HTML5 elements as element selectors for scressn media, it does nothing to enable print CSS. The above javascript doesn’t cure the ‘print’ issue. Jonathan Neal has come up with a javascript solution to the IE HTML5 print issue.

IE Print Protector is a javascript file that allows you to print HTML5 pages in Internet Explorer, helping IE render HTML5 elements correctly, both on screen and in print.

IE8: The Good: CSS 2.1 Selector Support in Internet Explorer

Internet Explorer 8, IE8, was released on March 19, 2009. Depending on your statistics source, as of July 2009, IE8 already has 17.8% of the browser market share. In the last section we provided an overview of what is new, good, bad and different in IE8. In this article, we take a deeper look at CSS 2.1 support in the IE8 browser, and compare IE8’s CSS support to IE6 and IE7.

CSS 2.1 Support

As mentioned in the overview, IE8 has complete support for CSS2.1. IE8 is the first browser to support all of the W3C CSS2.1 specifications, and currently has the best support of any browser (including Firefox, Safari and Opera) of the CSS 2.1 specifications. One may think (though no one outside of Microsoft does) that this makes IE8 the best browser, but it doesn’t. IE8 may be the first IE to support CSS 2.1, but Firefox, Safari, and Opera have already moved on to supporting features proposed in CSS3.

Internet Explorer 8 supports all CSS 2.1 Selectors

By having complete support for CSS 2.1, IE8 has a lot of improvements over IE7 and IE6 in terms of CSS support. Below are listed all the individual CSS2.1 selectors, with a brief explanation of how IE6, IE7 and IE8 compare. You’ll note that IE8 supports ALL of the selectors listed. While not shown in this grid, Firefox, Opera and Safari all support all the CSS 2.1 selectors, and have been doing so since previous releases.

By having complete support for CSS 2.1, IE8 has a lot of improvements over IE7 and IE6 in terms of CSS support. Let’s look at the differences:

Pattern Meaning IE6 IE7 IE8



Dynamic pseudo-classes are generally thought to be applicable to links and form elements since IE6 and IE7 don’t support them on other elements. IE8 supports pseudo classes correctly on ALL the elements.



The ‘:before’ and ‘:after’ pseudo-elements can be used to insert generated content before or after an element’s content. Completely ignored by IE6 and IE7, it is supported by IE8. See generated content


Universal Selector: any element *{}. While all browsers support this selector, it’s best to use it sparingly if at all.


Type or Element selector: a specific element, such a p, td, ol {}


Class selector: a class or several classes, such as: .myClass {}

IE6 does not support dual class names. For example, .one.two {} will target <p class="one two"> in all modern browsers, except IE6, which ignores it. Except for this exception, class selectors are supported by all browsers.


ID Selector: Matches an element based on it’s ID: #myId {} Supported by all browsers


Descendant selector: Matches any element F that is a child of element E

E > F

Child Combinator: Matches element F that is the first element child of element E

E + F

Adjacent simbling selector: Matches element F that is a the next sibling of element E. label input {} will match any input that follows a label such as <label>a label</label><input type="text">.

Note that there is a sibling selector – E~F – in CSS3 that is supported by IE7 and IE8, but not IE6


Attribute Selector: Matches if the element matched has the attribute: input[type] {}.

The exception to the support is that the browsers won’t match the element that has the attribute if the attribute value is empty


Attribute Selector: Matches if the element matched has the attribute: input[type=checkbox] {}.


Attribute Selector: Matches if the element matched has the value of the attribute value: a[rel~=nofollow] {} should match <a href="..." rel="noindex nofollow">.


Attribute Selector: Matches if the element matched has the attribute with the value has atleast the val as part of the value: div[lang|=en] should match <div lang="en-us">

E :first-child

The CSS selector should match the inner div element, because it is the first child of the outer div element Comments are not elements, so they should not be considered when determining the first child.


Non visited link (non included above with pseudo classes since only links can be links)


Visited link (not included above with pseudo classes since only links can be visited)


Matches element of type E if it is in (human) language c (the document language specifies how language is determined).


First letter pseudo-element: Matches the first letter of the element E.


First-line pseudo-element: Applicable to block-level elements, inline-block, table-caption or a table-cell, targets the contents of the first formatted line of a element.

Note that Opera 9.6, Firefox and Safari all support all of the above CSS selectors.

Full Support
Χ No Support
Δ Some support, but not full support

IE support of :hover pseudoclass

The :hover pseudo-class enables you to alter the presentation of an element when the user mouses over the element. For example, similar to Excel, you can change the color of a table row when the user mouses over a table rows using only CSS. IE6 and IE7, only support the :hover pseudoclass on links (the <a> tag) and some form elements. One very popular use of the hovering is drop down menus. In the past, because of IE6 and IE7, javascript had to be added to make sub-navigation appear on hover in those browsers. IE8, like all other standards compliant browsers, now supports the :hover pseudoclass on all displayed elements.

IE support of :before and :after pseudo-elements

The :before and :after pseudo elements enable you to add content before and/or after specified elements. For example, you can add special characters in front of list items, thereby not limiting yourself to the limited number of default list-style-types. IE6 and IE7 have no support for these pseudo-elements. IE8, however, has fully compliant support for these pseudo-elements. In fact, IE8 has better support for the content property of these pseudo elements than any other browser: better support even than Firefox.

Using differences in CSS selctor support to target browsers

Users of Community MX are encouraged to use conditional comments to target different versions of Internet Explorer. You can also use CSS selectors to target specific browsers. IE6 and IE7 have limited support for CSS 2.1 selectors. IE8 supports all of CSS 2.1 selectors, but very limited support fo CSS 3 selectors. On the other hand, all other non-IE grade-A browsers have support of several CSS 3 selectors. You can use these difference to your advantage to target specific browsers. In the last section, we provided one hack:

p.myclass {
color: green; /* all browsers */
body:first-child p.myclass { /* IE8 and all CSS 2.1 compliant browsers */
color: blue;
} body:last-child p.myclass { /* CSS 3 supportive browsers */
color: red;

This IE8 CSS filter targets all browsers with a regular element.className selector to target all paragraphs with the myClass class. It then targets all CSS2 compliant browsers with the CSS2.1 pseudo-class. It then filters out IE8 but using CSS3 to target all modern, non-IE browsers. It’s best not to use it, but it is important to understand how CSS can be used to filter browsers so you can follow other people’s code.

Up Next

In this section of IE8: the good, the bad, the ugly (and pretty), we’ve covered IE Support for CSS selectors. In the next section wel will look at IE’s support of CSS 2.1 properties and values of interest.

::before and ::after: Generating Content

In this section we learn about the different types of content that we can generated with CSS using the content property and its various value types. You’ve likely only touched upon the CSS content property, adding a simple string before or after an element. The content property can take many more values that just a simple string: you can add text, images, quotes, special characters, even images to your page using the content property to generate content in your :before and :after pseudo-elements. In this section we take a deeper look into the various values of the CSS content property.

Generated content is now supported in IE8 and all other modern browsers, so it makes sense to learn. There is an archaic table of browser support for the various values of the content property below (see listing 8).

Values of the CSS content property

The CSS content property can take as its value

  • none
  • normal
  • <string>
  • url
  • open-quote
  • close-quote
  • no-open-quote
  • no-close-quote
  • attr(attribute)
  • counter(name[, style]).

In this section of the series, we will discuss all of these values. We will only touch upon attr(attribute) and counter(name) in this section, as we will dive deeply into those two value options in the next section of this series..

Definition and purpose of each value of the content property

The CSS content property can take as its value none | normal | <string> | url | open-quote | close-quote | no-open-quote | no-close-quote | attr(attribute) | counter(name[, style]). Values have the following meanings:

  • content: none;

    none: When content: none; is included, the pseudo-element is not generated. This does NOT work in the current version of Safari (or Opera), nor is it expected to be supported in the next release of Safari. The solution to fix this which works in all modern browsers is to define the value as an empty string: content: "";. The two quotes with no content between the quotes is called an empty string. For example, some browsers automatically add opening and closing quotes to the <q> element. To override this default presentation, include q {content: "";} instead of q {content: none;}, so that all browsers override the default <q> presentation.

  • content: normal;

    normal: The ‘normal’ value, according to the W3C specifications, is supposed to “compute to ‘none’ for the :before and :after pseudo-elements.” To me, this specification is unclear. Is it supposed to compute to ‘none’ unless the default browser rendering includes content? The only element where interpretation of this value is relevant is the <q> or ‘quote’ element. In this case, the ‘normal’ value is handled differently in different browsers. Safari and Opera show the default content of quotes encompassing the text in between the opening and closing <q> tags. IE8 and Firefox do not show the quotes: computing to ‘none’. In the grid of support below I put support for Safari and none, and Opera as ‘iffy’, since my take is that Opera misinterpreted the deflation: Opera does compute to ‘none’ for most elements, but leaves quotes around the <q>, which is “normal”, but not the correct value for ‘normal’ according to the W3C.

  • content: "Estelle: ";
    content: "\00a3 "; /* includes '£' */

    string: The values of content can be a string encompassed in quotes. Including a string value will add your string before or after the element (depending on which pseudo-element is used). Strings can either be written with double or single quotes: the opening quote needs to be the same type of quote as the closing quote.

    If your string includes a quotation mark, make sure you escape it with a back slash. Otherwise, you can generally include any keyboard character. If you are putting a string of text, you may want to include a space in your text. You can also generate this spacing using CSS. Remember, as we learned in section 32, you can use CSS to stylize your generated text even though the generated text is NOT added to the pages document tree.

    Advanced topic: If you are going to include any non-ASCII characters or entities, declare the charset in your CSS and XHTML, and/or use the ISO / IEC 8859-1 (a.k.a. Latin-1) code for the character. Check out my blog post on including named entities in CSS and Javascript for examples and instructions.

  • content: url(myBullet.gif);

    url: You can add images as generated content (and even sound as generated content for auditory pages), by linking the content to an online file. To include an external file as generated content, include the URI inside the “url()”. The value of the property in this case it a path and file name that designates an external resource, such as an image, inside the “url()” as demonstrated above. If the browser can’t display the resource, FireFox and Internet Explorer 8 omit the file completely, as if it were not specified. Safari, on the other hand, indicates that the resource cannot be displayed with a missing image icon.

  • content: open-quote;

    open-quote and close-quote: These values are replaced by the appropriate string from the ‘quotes’ property. When including nested quotes, if the outer quotes are double quotes, generally, in literature, the inner quotes should be single quotes. The values of open-quote and close-quote are supposed to handle that scenario, but it doesn’t work cross browser. Firefox and Internet Explorer get these values right. Opera handles this, adding quotes, but does not nest quotes correctly. Safari ignores these values completely. Until Safari handles the open-quote and close-quote, values, I recommend using doing a double declaration. The first declaration should be a string with an escaped quote of your choosing. The second declaration should use the key terms of open-quote or close-quote, so the browsers that understand the declaration can nest correctly.

    p.quote:before {
       content: "\"";
       content: open-quote;

    Listing 1: The first line in understood by all browsers supporting content, since all browsers support the string value. If a browser does not understand the “open-quote” value, the browser ignores the value and inherits the string value from line 1.

  • content: no-open-quote;

    no-open-quote and no-close-quote: Introduces no content, but increments ( or decrements) the level of nesting for quotes. As mentioned in the open-quote/close-quote section above, when quotes are nested in some languages, the type of quotation mark used changes depending on the level of nesting. This is when these values are relevant. Again, safari ignores the declaration. Opera, Internet Explorer 8 and Firefox get it right (though Opera doesn’t nest properly. The trick described in Listing 1 works here too, except serve an empty string, as in listing 2.

    p.quote:before {
       content: "";
       content: no-open-quote;

    Listing 2: The first line in understood by all browsers supporting content, since all browsers support the string value. If a browser does not understand the “no-open-quote” value, the browser ignores the value and inherits the empty string value from line 1.

  • content: attr(title);

    attr(x): This ‘function’ returns as the content value a string with the value of the X attribute of the element on which the content attribute is applied. The attribute value will be elaborated on in the next section.

  • content: counter(subtitles, decimal);
    content: counter(headers) "." counter(subtitles) ": ";

    counter(name) or counter(name, style): The counter takes two parameters: the name, which you can reference to increment or reset, and the style, which, if not declared, defaults to “decimal”. While you can name the counter almost anything except ‘none’, ‘inherit’ or ‘initial’, avoid key terms. Counter will be elaborated on in the next section.

*By “modern browsers” I mean all browsers in listing 3 other than IE6 and IE7.

Browser support for the CSS content property and :before and :after pseudo elements

The CSS content property and possible values
IE6 IE7 IE7 in IE8 IE8 FF3 FF 3.5 Beta Saf 3.2 Saf 4 Beta Opera 9.64
content Since :before and :after is not supported in these browsers, testing is not possible, and moot. It is assumed that IE6 and IE7 does not support the content property, therefore supports none of these values works, except for issues below works, except for issues below works, except for issues below
none n
normal displays quotes on <q> Makes sense, but not the spec.
url() nothing nothing nothing missing image icon missing image icon missing image alt


Does not nest quotes correctly, but does include quotes.



Listing 3: browser support for the various values of the content property.