Achieve cross-browser functionality with HTML5 and CSS3

Learn new techniques to use on the latest browsers


The latest incarnations of HTML and CSS offer many new features. For example, HTML5 includes new elements that make web pages more semantic; you can now store data offline, create editable content areas, use drag-and-drop functionality, and much more. With CSS3, you can create round corners without graphics as well as add shadows and gradients. Although many exciting new features are becoming available, not all of the changes work across browsers. This article provides specific HTML5 and CSS3 techniques that you can use right now on all of the latest versions of the major browsers, including Apple Safari, Windows® Internet Explorer®, Mozilla Firefox, and Google Chrome.

In particular, some versions of Internet Explorer need a little help recognizing the new HTML5 elements. Luckily, a publicly available JavaScript file called html5shim—an HTML5 Internet Explorer-enabling script—helps it recognize and style HTML5 elements that are not otherwise rendered properly. To include this JavaScript file, simply include the code shown in Listing 1 in the <head> block of your HTML file above any CSS you are using.

Listing 1. html5shim, an HTML5 Internet Explorer-enabling script
<!--[if lt IE 9]>
<script type="text/javascript" src="//

This code also prevents browsers that do not need it from loading the extra file, limiting the load to Internet Explorer 8 or earlier. You can learn more about the JavaScript library by visiting the project website. (See Related topics for a link.)


In addition to the many new elements being introduced in HTML5, its new functionality is noticeable. This section covers some of the new HTML5 elements and shows how to create editable content areas and post messages between one page and another.

Structuring a page

If you've spent a lot of time structuring HTML websites, you know that many common sections are used repeatedly. These usually include a header for a logo or other identifying information, navigation that lists sections of the website, and a footer with copyright information. In previous versions of HTML, it was common to use the id attribute to identify these elements; for example, a header might be contained by a <div>, with an id set to "header"—that is, <div id="header">.

With HTML5, you can use new tags to define these specific areas without writing additional identifying attributes. For example, use the new header element in place of a <div> with a header id. This is not only a more logical way to code, but it can also be helpful when looking at another developer's web page, since many developers have different coding styles. Of course, the id attribute is still useful in many situations, but it's no longer necessary with these common elements. Listing 2 gives an example of a basic HTML5 page, using the header, nav, section, article, aside, and footer elements.

Listing 2. A basic HTML5 page structure
<!DOCTYPE html>
    <meta charset="utf-8" />
	<title>Cross-browser HTML5 and CSS3</title>
    <!--[if lt IE 9]>
    <script type="text/javascript" src="//

    <section id="intro">
            <h2>Cross-browser HTML5 and CSS3</h2>
        <div>Lorem ipsum</div>
	<section id="content">
        <section id="articles">
                    <h2>Article title</h2>
                    <p>Posted on <time datetime="2009-09-04T16:31:24+02:00">
					September 4th 2009
                <div>Pellentesque habitant morbi tristique senectus et netus et 
				malesuada fames ac turpis egestas.</div>
                <form id="comment-form">
                    <input type="text" name="comment" id="comment" />
                    <input type="submit" value="submit" />
            <h2>About section</h2>
            <p>Donec eu libero sit amet quam egestas semper. Aenean ultricies mi 
			vitae est. Mauris placerat eleifend leo.</p>

	<footer>Copyright notice</footer>



Each element is fairly self-explanatory, but several things should be pointed out:

  • HTML5 only has one doctype: <!doctype html>.
  • The header, nav, and footer are all exactly what you'd anticipate.
  • You can use the section element to help define sections of a web page layout—for example, an article or an intro.
  • You can use the article element to identify an individual blog post, comment, etc.
  • You can use the aside element as a sidebar; its main purpose is to wrap around main page content.

To get the aside element to appear next to the main page content, make sure that the width of each works with the current page width, and position the elements. Floats were once a common way to get two elements to appear side-by-side, but with the section and aside elements, you can now stop using floats by introducing table and table cell display values, as shown in Figure 1.

Figure 1. HTML5 page layout
Example of an HTML5 page layout using header, intro, section,        aside, and footer tags
Example of an HTML5 page layout using header, intro, section, aside, and footer tags

Listing 2 shows how to set the content section to display as a table and the articles section and <aside> tag to display as a table cell. This way, the entire structure acts as a table without all the extraneous table code and the table cells sitting next to each other like columns. Listing 3 gives an example of how to write the CSS to display these elements side-by-side.

Listing 3. Using table values for display
#content {
	display: table;
#articles {
	display: table-cell;
	width: 620px;
	padding-right: 20px;
aside {
	display: table-cell;
	width: 300px;

Creating editable content areas

Another interesting HTML5 feature is ContentEditable. As Listing 4 shows, any element that uses the ContentEditable attribute becomes editable. This means that you can edit any text within the element without having to use a finicky form element. Figure 2 gives an example of the ContentEditable attribute in action.

Figure 2. Editable content areas
Example of an editable content area using the ContentEditable attribute
Example of an editable content area using the ContentEditable attribute

With Ajax, you can easily save any updates to a database, and with HTML5's local storage functionality working across browsers, you can take this powerful functionality offline.

Listing 4. Creating an editable HTML element
<div id="editable" contenteditable="true">
Pellentesque habitant morbi tristique senectus et 
netus et malesuada fames ac turpis egestas.

Posting messages

Message posting is a new addition that brings a lot of possibilities. Listing 5 and Listing 6 give examples of how to post messages from a main web page to an iframe within that page.

Listing 5. Posting messages
<form id="comment-form">
    <input type="text" name="comment" id="comment" />
    <input type="submit" value="submit" />
    <iframe id="comment-iframe" src="post-message.html"></iframe>
<script type="text/javascript" src="assets/js/event.js"></script>
<script type="text/javascript">
    var win = document.getElementById("comment-iframe").contentWindow;
    addEvent(document.getElementsByTagName('form')[0], 'submit', function (e) {
        if (e.preventDefault) e.preventDefault();
        // otherwise set the returnValue property of the original event to false (IE)
        e.returnValue = false;
        return false;

A JavaScript function named postMessage handles the actual message posting; you use a new event named message in the iframe to retrieve the event and the associated properties.

Listing 6. Retrieving posted messages
<p id="post-comment"></p>
<script type="text/javascript" src="assets/js/event.js"></script>
<script type="text/javascript">
addEvent(window, "message", function(e){
    if(e.origin !== "") {
        document.getElementById("post-comment").innerHTML = 'Message from ' + e.origin;
        document.getElementById("post-comment").innerHTML = e.origin + " : " +;

This example uses a custom JavaScript event function that is included as an external file named event.js. Listing 7 shows this script.

Listing 7. A custom event function
var addEvent = (function () {
  if (document.addEventListener) {
	return function (el, type, fn) {
	  if (el && el.nodeName || el === window) {
		el.addEventListener(type, fn, false);
	  } else if (el && el.length) {
		for (var i = 0; i &lt; el.length; i++) {
		  addEvent(el[i], type, fn);
  } else {
	return function (el, type, fn) {
	  if (el && el.nodeName || el === window) {
		el.attachEvent('on' + type, function () {
				return, window.event);
	  } else if (el && el.length) {
		for (var i = 0; i &lt; el.length; i++) {
		  addEvent(el[i], type, fn);


CSS3 is adding an entirely new realm of possibilities for web designers. You can now add shadows, gradients, rotation, and certain fonts—all without having to use images that weigh down a web page. This section introduces some new, exciting features that you can use immediately without any cross-browser issues. Web designers can now spend more time creating eye-catching websites instead of trying to identify how to make something look right.

Working with shadows

Shadows add dimension to a web page; this was previously possible only with images. With CSS3, you can control many details, including the direction, offset, color, and blur of the shadow (shown in Figure 3). Listing 8, Listing 9, and Listing 10 give examples of the various ways you can use CSS to create a shadow.

Figure 3. Rendering a shadow with CSS3
Example of CSS3 shadows applied to an HTML element

In Firefox, use the -moz-box-shadow to apply a shadow to an element. You can assign four values to this property.

Listing 8. Creating a shadow in Firefox
-moz-box-shadow: 1px 1px 4px #666;

In Safari and Chrome, use -webkit-box-shadow to apply a shadow to an element. You can assign four values to this property as well.

Listing 9. Creating a shadow in Safari and Chrome
-webkit-box-shadow: 1px 1px 4px #666;

Four properties are available for Safari, Chrome, and Firefox shadows:

  • Horizontal offset of the shadow. The offset number can be positive or negative; if it's negative, the offset casts the shadow to the left of the element, while a positive value casts the shadow to the right.
  • Vertical offset. This offset can also be set to a negative or positive number. A negative value casts the shadow above the element, while a positive value casts it below.
  • Blur radius. Higher numbers increase the amount of blur you see, while lower numbers sharpen the shadow.
  • Hex color. You can set the hex color of the shadow.

The CSS is different when working with Internet Explorer. Listing 10 shows how to create a shadow in Internet Explorer using filters. The first filter is for versions 6 and 7, while the second filter is for versions 8 and later.

Listing 10. Internet Explorer CSS filters for creating shadows
filter:  progid:DXImageTransform.Microsoft.dropshadow(OffX=0px, OffY=2px, 
-ms-filter: "progid:DXImageTransform.Microsoft.dropshadow(OffX=0px, OffY=2px, 

Creating gradients

Many ways to create gradients have been popularized over the years; my favorite is the 1px repeating gradient image. Figure 4 shows that with CSS3, this technique is longer necessary, since each browser type now has its own way of handling gradients (shown in Listing 11, Listing 12, and Listing 13).

Figure 4. Rendering a gradient with CSS3
Example of a CSS3 gradient applied to an HTML element
Example of a CSS3 gradient applied to an HTML element

You can handle the display of a gradient in several ways. Listing 11 gives a simple Firefox example that starts from the top and fades from the first to the second color.

Listing 11. Creating a gradient in Firefox
background: -moz-linear-gradient(top, #eaeaea, #999999);

The Safari and Chrome example in Listing 12 results in the same look as the Firefox example, but is written differently:

  • The first property is the type, which allows you to set the gradient to linear or radial.
  • The second and third properties are the start and the end points of the gradient, respectively.
  • The fourth and fifth properties are the start and end colors of the gradient, respectively.
Listing 12. Creating a gradient in Safari and Chrome
background: -webkit-gradient(linear,left top,left bottom,color-stop(0, #eaeaea),
color-stop(1, #999999));

Internet Explorer requires a filter to create a gradient. The filter has a number of associated properties:

  • Enabled indicates whether the filter is enabled. (The default is True.)
  • EndColor determines the final opaque color of the gradient.
  • EndColorStr determines the final color of the gradient.
  • GradientType determines the orientation of the gradient.
  • StartColor determines the initial opaque color of the gradient.
  • StartColorStr determines the initial color of the gradient.

Listing 13 uses the simplest form of the gradient filter, defining a start and end color.

Listing 13. Creating a gradient in Internet Explorer
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eaeaea', 

Rotating elements

Sometimes, the normal horizontal display of an element is not enough. With the introduction of transform, you can now rotate an element in CSS3 (as shown in Figure 5). Whether you need an element to be completely flipped on its side or a little angle to fit your design, it's possible across browsers with the code shown in Listing 14, Listing 15, and Listing 16.

Figure 5. Rotating an HTML element with CSS3
Example of a rotated HTML5 element with CSS3

The code to rotate an element is straightforward: simply use a number and deg to indicate the degree. In Firefox, use -moz-transform to rotate an element, as the code in Listing 14 shows.

Listing 14. Rotating an element in Firefox

In Safari and Chrome, use -webkit-transform to rotate an element.

Listing 15. Rotating an element in Safari and Chrome

You have several options when rotating an element in Internet Explorer. If the first transform method doesn't work, you can always fall back to filters. The filter to rotate an element in Internet Explorer is Matrix. While it might be a little complicated to use, it does do the job when necessary.

The Matrix filter has a number of associated properties:

  • Dx gives the X component for linear transformations.
  • Dy gives the Y component for linear transformations.
  • Enabled is used to enable the filter.
  • FilterType is used to set the pixels of the transformed content.
  • M11 determines the first row/first column entry for linear transformations.
  • M12 determines the first row/second column entry for linear transformations.
  • M21 determines the second row/first column entry for linear transformations.
  • M22 determines the second row/second column entry for linear transformations.
  • SizingMethod is used to determine whether the container is resized to fit the result.
Listing 16. Rotating an element in Internet Explorer
-ms-transform: rotate(-2deg); 
filter:  progid:DXImageTransform.Microsoft.Matrix(sizingMethod='auto expand', 
M11=0.9914448613738104, M12=-0.13052619222005157, M21=0.13052619222005157, 
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.9914448613738104, 
M12=-0.13052619222005157, M21=0.13052619222005157, M22=0.9914448613738104,
sizingMethod='auto expand')";

Box sizing

All browsers use the W3C box model, and with CSS3, you can use box-sizing to set the way the browser renders an element's width and height. The border-box element tells the browser to use the actual width and height without taking into account the padding and border. Listing 17 shows box sizing in Safari and Chrome.

Listing 17. Box sizing in Safari and Chrome
-webkit-box-sizing: content-box;

In Listing 18, notice that the only difference between Safari/Chrome and Firefox box sizing is that Firefox uses the -moz-box-sizing property.

Listing 18. Box sizing in Firefox
-moz-box-sizing: content-box;

Internet Explorer uses the -ms-box-sizing property, as shown in Listing 19.

Listing 19. Box sizing in Internet Explorer
-ms-box-sizing: content-box;

The default for some browsers prompts them to take the padding and border into account when setting the width of an element, which results in the equation (width or height) + padding + border.

Outlining elements

Borders are a common way to define an area of a web page. The new outline element allows the same possibilities as a border but with the addition of an offset. In Listing 20, notice that the offset lets you create an outline and offset it from the actual bounds of the element. In the past, this was only achievable by adding a border and padding to an element, which didn't always produce the expected results.

Listing 20. Outlining and offsetting the outline on an element
outline: 1px dotted #cccccc;
outline-offset: 10px;

Working with pseudo-classes

Many pseudo-classes are already in use; most are commonly associated with anchor tags for hyperlinks. Pseudo-classes let you add different states to an element and change properties based on the current state. Listing 21 shows common usage for pseudo-classes.

Listing 21. Common usage of pseudo-classes
a:link { }
a:visited { }
a:hover { }
a:active { }

The pseudo selector shown in Listing 22 creates a hover state for the editable HTML5 content area and applies the previously covered outline code.

Listing 22. Working with pseudo selectors
#editable:hover {
	outline: 1px dotted #cccccc;
	outline-offset: 10px;

Embedding fonts

Fonts on the web have been an issue since the very beginning. Very few options are available on each user's computer, and of the options that are available, few are attractive. We are on the verge of experiencing a great change, and font embedding (shown in Figure 6) will let us create brilliant layouts without using heavy images on our pages. Several methods can accomplish this.

Figure 6. Embedding fonts with CSS3
Example of an embedded font with CSS3
Example of an embedded font with CSS3

For Internet Explorer, you need access to the .eot file format for the font you want to use. Listing 23 shows how to embed the font once you have the correct font file.

Listing 23. Embedding fonts in Internet Explorer
font-family: yanone;
src: url('../fonts/yanone.eot');

For Firefox, Safari, and Chrome, you can embed .ttf or .otf fonts. Listing 24 shows the code to embed these fonts for later use in a web page.

Listing 24. Embedding fonts in Firefox, Safari, and Chrome
font-family: yanone;
src: local('Yanone'), url(../fonts/yanone.ttf) format("truetype");

Once you have the font embedded, apply it to an actual HTML element by creating a class by the name of the font family you used in the @font-face declaration. Listing 25 shows how to use this font in a class and then later apply it to an HTML element.

Listing 25. Embedding fonts for all browsers and adding a class to assign the font to an element
@font-face {
    font-family: yanone;
    src: url('../fonts/yanone.eot');    
    src: local('Yanone'), url(../fonts/yanone.ttf) format("truetype");
.yanone {
  font-family: yanone, Verdana, Arial, Helvetica, sans-serif;


HTML5 and CSS3 are bringing great change to the web, but you should exercise caution when using many of their techniques, since a great deal of functionality does not work across browsers. As time progresses, we will see more of this new code being used and supported by the major browsers; this will let us surpass any limitations that require creating workarounds to design web pages and focus more energy on the look and feel of a site.

Downloadable resources

Related topics

Zone=Web development
ArticleTitle=Achieve cross-browser functionality with HTML5 and CSS3