The power of the Web is in its universality. Access by everyone regardless of disability is an essential aspectLately, there has been a lot of concern expressed, by intelligent, experienced people I have a lot of respect for, about the future of the web, about its very viability.I've engaged folks like Joe Hewitt in strenuous, but I believe healthy and important debate about these issues.As I considered in my recent Web Directions presentation, A Dao of Web Design Revisited (article, slides and audio recording coming soon), I feel that many of these concerns strangely, uncannily, echo those which prompted my original Dao of Web Design article back in 2000.A recent tweet by Aral Balkan (once again, a passionate, intelligent contributor to the web, who has spoken at our events, and hopefully will do again), retweeted by Lea Verou (another generous contributor to the web, and again, one of our past, and I hope future speakers) really captured for me the essence of the issue
#oneversion #manifesto My websites will only support the latest versions of browsers. It's the browser makers' duty to get users to upgrade.Aral Balkan, Twitter, October 20 2011So, what does this tweet, and predictions of world population have to do with one another?I love the shiny stuff of the web - the gradients and animations, the transforms. As someone who has developed for the web for nearly 18 years, the ever increasing sophistication of the DOM, of JavaScript, the increase in the speed of JS engines, of rendering, the arrival of mobile platforms, and micro-mobile platforms for the web excite me as a user and a developer. But, they aren't what gets me up in the morning. They aren't what fires me up like no other platform before (I built my first Mac apps in 1986, and have had commercially available Mac OS apps continuously since 1994, and Windows apps since 1996).What really, at the not so tender age of 45, keeps me as passionate and excited about building stuff as I was when about 16 and got my first TRS80 clone is the potential for the web to transform our world for the better. And overarching all this is the question, the challenge, how do we get the next 2 billion online, and ultimately, the next 6 billion people online?This might not float your boat. And that's fine. You might consider it an ideological position. And that's your prerogative. But I know I'm not alone in believing that the potential, the promise, and in the face of overwhelming planet-wide challenges - anthropogenic climate change, global pandemics to name just two which our generation, and particularly my children's generation will have to increasingly confront - the necessity of bringing our planet together, and enabling all of us to collaborate, share, communicate, without the friction of borders, is something only the web can hope to achieve.Universality is a founding principle of the web. It is the manifesto the web has been built on, and I believe one of the key drivers of the almost unimaginable success of the web over these last two decades. We ignore that at the web's peril.The web alone, not iOS, or Android, or Windows Phone, or any other platform can possibly connect the next 6 billion. Yes, some, many of those 6 billion will be accessing the web via iOS, some via Android devices, some Windows Phone.But, this next six billion is children in rural India, Africa, China where access to power, and networks, may be intermittent. It's someone in Sumatra at a decade old Wintel box. It's people who speak hundreds of different languages, with dozens of different writing systems. It's people who are the first in their family to be able to read and write. It's the 20% of people worldwide who can't read or write. Yet.So, to say "My websites will only support the latest versions of browsers", you are in a sense saying, "I'm going to make the fact that developing for the web is harder than it would be if I concern myself with browsers other than the latest is not my problem, and not even the browser makers problem, it's the problem of the next 6 billion. It's not my problem, it's the problem of the child in rural India, Africa, China."The truth is, the challenge of universality is daunting. It is hard work. But to me at least, paying this forward is the quid pro quo of the enormous privilege I've been granted to work on the web, which has given me fascinating well paid work, connections with thousands of intelligent, passionate, generous people around the world, and the opportunity to participate, in however insignificant a way, in something genuinely extraordinary, something unique. I can pay this forward by including rather than excluding people. By, in my own small way, helping ensure that the next 6 billion will be able to share in the privilege that I, you and the first 2 billion share in.Which is not to say we shouldn't continue to develop the capabilities of web technologies. It is not to say we shouldn't continually explore what these technologies enable us to do.But to me at least, we owe it to the web to do this in a way that is generous to the web in the way the web has been generous to us.To reformulate the now famous question Steve Jobs asked of John Sculley:Do you want to make shiny products for the privileged for the rest of your life, or do you want to come with me and change the world?" ["post_title"]=> string(18) "The Next 6 Billion" ["post_category"]=> string(1) "0" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(18) "the-next-6-billion" ["to_ping"]=> string(0) "" ["pinged"]=> string(122) "http://www.webdirections.org/blog/the-web-is-a-different-problem/ http://www.webdirections.org/blog/css3-radial-gradients/" ["post_modified"]=> string(19) "2011-10-20 14:43:34" ["post_modified_gmt"]=> string(19) "2011-10-20 04:43:34" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=3734" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(2) "39" ["filter"]=> string(3) "raw" } [2]=> object(stdClass)#118 (25) { ["ID"]=> int(3710) ["post_author"]=> string(1) "3" ["post_date"]=> string(19) "2011-10-17 13:16:40" ["post_date_gmt"]=> string(19) "2011-10-17 03:16:40" ["post_content"]=> string(3964) "When you work on something for an extended period of time but which itself lasts itself only a brief moment, such as Maxine and I do with Web Directions, there's an intensity to the event itself, and the strange mixture of relief (and exhaustion) coupled with nostalgia when it has come and gone.Luckily, through photos, tweets, blog and Facebook posts and even the odd video, increasingly an event like Web Directions is captured in more than just our memory.
Web Directions South, held last week, was the sixth annual Web Directions event we've run in Sydney, and though likely we feel this every year, it was in our estimation, and indeed of so many we spoke to, and based on many tweets we've read the best we've done by far.The atmosphere was incredibly positive, (reflected in everything from the twitter stream, to the crowds who refused to go home, staying long into the night at the closing night party).A new generation of partner companies, almost all from Australia and New Zealand, and most of which did not exist when Web Directions started back in 2006 companies shouted great parties, competitions, and most importantly showcased the sophistication and breadth (as well as spirit of fun) of the Australian web industry.Similarly, while many of the speakers, local and international, may have been unknown to our audience, they excelled–educating, inspiring and entertaining. From opening keynote to closing, never have we seen such uniformly positive responses to a program.Every presentation we had the privilege to see, as well as all those we didn't but which we heard amazing things about, was world class.Whether you were there, or missed out, as the podcasts and slides from presentations come online, we'll tweet about them (so if you don't already, you really should follow us on Twitter. Meanwhile, you can catch up on hundreds of past presentations from our conferences around the world from the last several years.And, as a special treat, coming soon is a slickly produced video version of James Bridle's amazing closing keynote, thanks to Hunting with Pixels.In the meantime, Ben Buchanan has already made available his traditional big stonking post™ with detailed live notes, links, and photos from a dozen presentations. So, if you missed it, and can bare to see what you missed out on, it's a great place to start.Thanks!
- A huge thanks to our wonderful sponsors, partners and exhibitors
- To our incredibly generous speakers
- To Cameron Adams for the opening sequence, setting a new standard for creativity with Web Technologies
- To the Design Computing program at the University of Sydney for their incredible exhibition of interactive technology
- To the W3C Australia Office for once again hosting the W3C South Track
- And not least to the fantastic, positive, open minded, engaged audience.
One of the most persistent criticisms of web technologies is that they evolve slowly, indeed, too slowly. Often the argument is raised that the process of standards is antithetical to "innovation" (for innovation read "making cool stuff up").
To contrast with this glacial change, we're typically pointed toward the wonders of platforms like iOS and Android, where change takes place at breakneck speed. Or we're pointed toward any number of open source projects, for example SASS, to demonstrate that we can evolve web standards faster outside the W3C (afterall, CSS hasn't kept place with SASS/LESS... therefor the W3C is clearly useless)
Pretty sure that already happened. SCSS, Coffeescript, etc. The W3C doesn't have influence anymore AFAIK
And occasionally, this erupts in an orgy of revolutionary fervour, where we need to man the barricades, and
dissolve the W3C, and run the web like an open source project. No more specs, just commits. Does Linux need a standards body?
I guess Joe hasn't taken a look at the WHATWG's "HTML"lately. An unversioned. constantly, continuously evolving potage, wherein creeps all kinds of at the every least questionable "innovations", whose trajectory is unburdened by such trifling challenges as the need for intellectual property policies, or getting anyone to actually implement their stuff.
But let's step back a pace. Is there really actually such a problem here? And if so, exactly what is that problem? And, are the proposals, to the extent they do exist, likely to help, or make matters worse?
Firstly, it is fair to say, that for the best part of the first decade of this century, we saw considerable stagnation in the development of web standards. The W3C went down the rabbit hole of XHTML2, and CSS 2 almost entirely stagnated (I'l have more to say on that in a second). During that time, innovation came almost entirely from developers discovering techniques which worked with existing browser capabilities, and through JavaScript libraries.
The last three or four years have however seen an explosion of innovation at the browser level. This has included:
- Huge improvements in the performance of JavaScript engines
- Fantastic new CSS features, that have within a couple of years landed in all modern browsers
- Sophisticated new APIs across a broad range of functionality, again now widespread across most if not all modern browsers (Selectors API, Geolocation, offline, localStorage, 2D and 3D canvas to name just a few)
Before we throw the baby out with the bathwater, we should ask, is there a problem at all? Are we really seeing innovation - from standards proposal to widespread browser adoption in the order of 10 years?
Let's take a look at an actual example. Dave Hyatt announced CSS Gradients in WebKit nightlies April 14th 2008. More or less simultaneously, Apple formally proposed these as part of CSS3. Gradients have been supported in Firefox since 3.6 (released Jan 2010), Opera since 11.1 (final release mid 2011), Internet Explorer 10 (developer releases early 2011). So, from first released and proposed as a standard to very widespread adoption in around 3 years.
We've seen similar timeframes for other CSS features, as well as "HTML5" features like the Selectors API, appcache, geolocation, localStorage.
So, to put it bluntly, I think the problem is overstated. We seem to have arrived at an approach that both enables the exploration and implementation of novel features in browsers, which are also widely adopted across browsers. It's that second part that is most important, and I'll return to it in a moment.
But I also want to quickly address why I think we seem to have thrown off the stagnation of previous years. I'd argue it comes down to stepping back from the monolithic approach of earlier W3C recommendations (CSS 1 and 2, XHTML2, SVG), toward a much more modular approach, as exemplified by CSS3, but as also seen with geolocation and the selectors API. A corollary to this is, I'd argue, that HTML5 is too monolithic and needs to be fragmented (which in some ways is happening).
But back to the real issue. The web is a different problem. It makes little if any sense to compare innovation of the web ecosystem with that of iOS, Android or other platforms. The web faces challenges far far greater (and has goals far more important). A platform such as iOS can abandon legacy applications, content and hardware, (along with their users) with little compunction. It can (and does) make developers and content creators wishing to participate jump through any number of hoops. It has a single dictatorial decision maker, beholden to no one, and nothing other than itself. And it generates extraordinary revenues, which can be reinvested into the ongoing development of the platform.
The web is different. It values interoperablity, backwards compatibility. It's goal is to bring access to the same information to billions across the world, on all manner of devices. Its custodians are, in my opinion, scandalously under-resourced, given just how much wealth the web has created for so many, perhaps above all Google and Apple.
Without the web, Google would not exist, and Apple's core engine of growth, iOS devices would essentially not either.
So, rather than generally criticising the W3C, or going so far as calling for its dissolution, we should focus on how well in many ways it has done an almost impossible task - getting companies which are fierce commercial rivals to sit down, work together and agree on core technologies they will each, and all, implement, even while at the same time, these same competitors are involved in significant legal conflicts with one another.
Can the W3C be improved? Certainly. But before suggesting solutions, let's identify, and demonstrate with evidence, genuine problems. Then, when devising solutions, it pays to ask what evidence there is that those solutions will not only solve the problems identified, but also ensure the ongoing cooperation that has given rise to the web.
" ["post_title"]=> string(30) "The web is a different problem" ["post_category"]=> string(1) "0" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(30) "the-web-is-a-different-problem" ["to_ping"]=> string(0) "" ["pinged"]=> string(0) "" ["post_modified"]=> string(19) "2011-09-21 15:33:11" ["post_modified_gmt"]=> string(19) "2011-09-21 05:33:11" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=3689" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(2) "18" ["filter"]=> string(3) "raw" } [5]=> object(stdClass)#121 (25) { ["ID"]=> int(3664) ["post_author"]=> string(1) "3" ["post_date"]=> string(19) "2011-09-21 10:59:43" ["post_date_gmt"]=> string(19) "2011-09-21 00:59:43" ["post_content"]=> string(37539) "One of the most powerful features of CSS3 are transforms, which allow us to take any element in an HTML document, and while not changing its effect on the page layout, rotate it, translate it (move it left, right, up and down), skew it and scale it. CSS3 provides both 2D and 3D transforms, but while 2D transforms are supported in all modern browsers, including IE9 and up, 3D transforms are currently only supported in Safari, Chrome and IE10.
In this article, we'll take a look at how to use 2D transforms and the various transform functions (such as scale and rotate). We'll also, as always, look at some gotchas when first working with transforms, and once again, there's a tool to help you play with transforms (I developed it some time ago, but I've updated it significantly for this article).
What transforms do
As in many cases, an example is worth a thousand words, so let's take a look at a couple, to illustrate how transforms work, as well as some of their most important aspects.
When you click or tap the button below, this paragraph is rotated by 45 degrees. It's also scaled to 75% of the size it would otherwise be. However note how the rest of the page layout is not affected. That's because transformations don't change the box model of an element, and so leave the page layout unchanged.
This element has been skewed horizontally and vertically. You can still select the text, and otherwise interact with the element, as you would if it weren't transformed.
Transforming elements
The syntax for CSS transforms is in many ways straightforward. There are just two new properties to contend with - transform, and transform-origin. The first specifies the transforms we want applied (scaling, rotating and so on), while the second, which is optional, specifies the origin for this transformation (for example, do we rotate around the middle of the element, its top left hand corner, and so on).
The transform property
The transform property takes as its value one or more transform functions, which each specify a transformation. Let's take a look at each of these different functions in detail. Functions all take the form of a function name, with a value inside round brackets (as indeed do all CSS functions). So for example, we translate horizontally with the function translateX(200px).
OK, enough preliminaries, let's start in with some actual transforming. We'll start with the translate function.
translate
The translate function moves the contents of an element to the left (negative values) or right (positive values), and/or upwards (negative values) and downwards (positive values).
translate takes one or two comma separated values. The first is the horizontal translation value. If there is a second, this is the vertical translation value, while if there is only one value, then the vertical translation is zero (that is, the element will only be translated horizontally).
In addition to the translate function, there are the related translateX and translateY functions, which only translate an element horizontally, or vertically, respectively. Translate functions take length or percentage values, and like CSS properties, require units for values other than zero.
But enough theory, why not have a play with them?

transform: translate(0, 0)
We mentioned a moment ago that transforms don't impact the layout of a page. There's one area where this is not exactly true. If you translate the above element completely to the right, you'll notice a horizontal scrollbar appears (or the page can now be scrolled to the right). While the page layout has not been changed, the overflow property of the transformed elements containing element is affected by transforms (Safari on Mac OS X Lion is an exception to this, and perhaps indicates where this sort of UX is headed, but for now, in desktop/laptop browsers other than this, the addition of a scrollbar will impact page layout).
This element is scaled by 200% when you click the button below. Its containing div has an overflow: auto. So, scrollbars appear when the element is transformed. In many browsers this will cause the page to reflow.
scale
The scale function lets us zoom an element up or down in size (all the while maintaining the dimensions of its box for the purposes of the layout of the page). The function name is scale, and it takes a number value-with a value of .5 meaning "scale to half the current size", and of 2 meaning "scale to twice the current size", and so on. So, if we want to make an element 75% of its current size, we use the property transform: scale(.75). And that's really all there is to it. Why not have a play with it?

transform: scale(1)
It's also possible to scale horizontally and vertically independently from one another, by using two comma separated numerical values for the scale property. The first value scales an element horizontally, and the second, vertically. Let's take a look.

transform: scale(1, 1)
As with translate there are two related scale functions, scaleX, and scaleY. scaleX scales only horizontally (scaleX(2) is the equivalent of scale(2, 1)), and scaleY, which scales only vertically (scaleY(2) is the equivalent of scale(1, 2)).
rotate
Rotating text and images is a common page design technique, until now difficult to achieve on the web without considerable hackery, if at all. Transforms make rotating an element easy.
The rotate function takes an angle value. If you've worked with CSS linear gradients, in particular the newer syntax, then you'll have seen angle units before. There are several ways you can specify an angle in CSS.
degrees
As you most likely remember from school math, there are 360 degrees in a circle. So, when specifying a rotation of an element, 90 degrees is a quarter turn clockwise, 180 degrees is a half turn, 270 degrees is three quarters turn clockwise, and 360 degrees is a full revolution. Here these are below.
rotate(90deg) rotate(180deg) rotate(270deg) rotate(360deg)
Of course, it is possible to rotate an element by an arbitrary angle, for example 34.6 degrees, like so
rotate(34.6deg)
But, there are other ways we can specify rotations.
- turns
- perhaps the simplest way to specify a rotation is with the
turnvalue. We can rotate an element a quarter turn clockwise with the functionrotate(.25turn), half a turn with .5turn, three quarters of a turn with .75 turn, and a whole turn with the functionrotate(1turn). WebKit and Opera support theturnvalue, while Firefox (version 6) does not.
rotate(.25turn) rotate(.5turn) rotate(.75turn) rotate(1turn)
For completeness, it's worth noting that there are two other possible angle units-radians (rad), and gradians (grad). Briefly, there are 400 gradians in a full rotation (so one grad is slightly larger than one degree), while there are 2π radians in a full rotation (radians are widely used in mathematics).
Now, if you think about rotating an element, then you might wonder what point of the element the rotation takes place around. For example - is it the center? Or one of the corners?
This element rotates around the top left hand corner when you click or tap and hold it. (transform: rotate(360deg))
We can in fact specify where the rotation (and as we'll soon see, any transformation) takes place, using the transform-origin property. transform-origin takes two length or percentage values, which specify the horizontal and vertical "origin" of the transformation. In the above example, we have transform-origin: 0 0. If we want to rotate around the center of the element, we use transform-origin: 50% 50%, while to rotate around the bottom right of the element, we use transform-origin: 100% 100%.
This element rotates around the center of the element (transform-origin: 50% 50%; transform: rotate(360deg)).
This element rotates around the bottom right hand corner of the element (transform-origin: 100% 100%; transform: rotate(360deg)).
(You might be able to guess that we can animate transformation changes, like we can most other CSS property changes using CSS Transitions. For more on this, see my article on CSS transitions and animations.)
So, let's now put rotations and transform origin together so we can play around with them.

transform: rotate(0); transform-origin: 0 0
transform-origin can also be specified with keywords, in place of percentage (or length) values. As with background-position we can use left, center or right for the horizontal origin position and top, center or bottom for vertical. Where only one value is used, this applies to the horizontal origin, and the vertical is 50% (or center). Where no transform-origin is specified, its default value is 50% 50%.
skew
the last of the 2 dimensional transform functions is skew. Skewing is typically explained in mathematical terms, but if you recall a little school geometry, it isn't really that complicated. Horizontal skew (the skewX function) takes the box of an element, and while the top and bottom edges remain horizontal, tilts the left and right edges by the specified number of degrees to create a parallelogram. Similarly, a vertical skew (skewY), leaves the left and right edges vertical, and creates a parallelogram with the top and bottom edges rotated by the specified number of degrees. And when you skew both horizontally and vertically, you combine both of these (where it can get really quite tricky to work out what's going on). Does that help? You can play with the values below to get a sense of how skewing works in practice, including how it can create apparent 3D effects.
The skew function, like most other functions, takes one or two values. As with rotate, they are angle values, and where there are two values, they are comma separated.

transform: skew(0, 0)
Once again, as with a number of the other transform functions we've seen, there are two related functions - skewX and skewY, which each skew only in one dimension, and which take only a single, angle value.
Complex transformations
While you'll likely never need to use it, underneath all these functions is the core of CSS transformations, based on the mathematical concept of a transformation matrix. Each of the functions we've seen can be represented by a matrix value. While it's firmly in the domain of mathematics, we can for example represent the function scale(1.5,1.2) by the matrix
1.5 | 0 | 0 0 | 1.2 | 0 0 | 0 | 1
and directly apply this matrix value using the matrix function, like so
transform: matrix(1.5, 0, 0, 1.2, 0, 0)
this element has been scaled using a matrix function on the transform property.
The transform matrices for various functions are described in the SVG specification.
Multiple transforms
It's possible to apply multiple transform functions at once to an element. For example we can rotate, translate and skew an element with the single transform property:
transform: scale(0.75) rotate(45deg) translate(132px, -149px) skew(32deg, -32deg);
Click the button below to apply several transformation functions simultaneously, with the property transform: scale(0.75) rotate(45deg) translate(132px, -149px) skew(32deg, -32deg);
There is however a complicating factor, which we look at in a moment.
The Transformer Tool
Hand coding transforms, as with much to do with CSS3, is an increasingly complex process. Not only is there a good deal of syntax to remember often for quite straightforward effects, but the outcome of at least some transforms isn't necessarily obvious to most of us simply by looking at the CSS. So, to help you learn, and explore, CSS transforms, I've developed a 2D transform tool (there's a 3D one as well, but we'll cover 3D in a later article).
If you're keen to explore transformations in more detail, and how they can be made to work together, head over and take a look, and as always, let me know what you think via twitter.
Gotchas, tips and tricks
Its fair to say that while now widely supported in modern browsers, 2D CSS transforms are still experimental, and quite quirky. Here are some of the difficulties you might encounter, and some tips and ideas for working with 2D transforms.
vendor specific prefixes
Reflecting the experimental nature of transforms, all browsers require vendor specific prefixes for the transform and transform-origin properties (note that function names are not prefixed). As all modern browsers including IE9 and up support 2D CSS transforms, using these transformation properties can get more than a little unwieldy. For example, the CSS for a simple rotation around the center of an element, if we include all vendor specific properties, would be something like:
img{
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-o-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg); //always include a standard for last
-webkit-transform-origin: 50% 50%;
-moz-transform-origin: 50% 50%;
-o-transform-origin: 50% 50%;
-ms-transform-origin: 50% 50%;
transform-origin: 50% 50%;
}
You might find the use of a CSS preprocessor like LESS or SASS worth exploring, as they can make stylesheets far more manageable when you use a lot of vendor prefixing.
Transforming inline elements in webkit
According to the current version of the specification, CSS Transforms should be applied to inline, as well as block elements, but while Opera and Firefox both correctly apply transforms to inline elements, WebKit browsers (Safari 5.1, Chrome 15) currently don't.
A workaround for this is to give inline elements which are to be transformed display: inline-block, which won't affect how they are laid out in the page, but will enable these browsers to transform them.
Translating rotated content
One subtle aspect of multiple transformations is that functions are performed in sequence - from first to last in the list. The order that you specify functions can make a difference. Take a look at the following paragraphs. Both have the same scale, rotate and translate functions applied. But, in the first, the element is translated to the right, while in the second, it is translated to the left. What's going on?
Clicking the button below applies several transformation functions simultaneously, with the property transform: scale(0.75) rotate(180deg) translate(-100px,0)
Clicking the button below applies several transformation functions simultaneously, with the property transform: scale(0.75) translate(-100px, 0) rotate(180deg)
Transformations don't take place in an absolute coordinate space. Rather, "up", "down", "left" and "right" are relative to the current rotation (but not skew) of the element. So, if an element is rotated half a turn, and so is "upside down" then translate(0, -100px) moves it down the page 100px. If it's rotated a quarter turn to the right, it's moved to the left. Similarly, translating "horizontally" is always relative to the element. So, if it's rotated by 180 degrees, then translate(100px, 0) moves the element to the left. In short, the X and Y axes of a transformation are relative not to the page, but the element's current rotation.
Interacting with transformed content
While the box of an element isn't changed by a transformation, elements that are transformed display various quirks when it comes to mouse events in various browsers, most likely due to the still experimental nature of transformations. Take the element below. It rotates a quarter turn clockwise when the mouse is over it, and then back to its original rotation when the mouse is out of it.

Now, if the box of the element isn't changed, then when rotated, hovering over any of the image which is outside that original box should not trigger a mouseover event, and so the element should rotate back to its original position. However, as makes intuitive sense, hovering over those parts of the rotated element that are outside the original box does cause mouseover events to be fired. But in addition, mouseover events are also fired when you hover over that part of the element's original box which no longer has content because it has been rotated away. And if you move your mouse around the element, you'll find in all browsers various locations where the rotation abruptly, though unintuitively, changes. Similar behavior can be observed for translation and other transformations.
In light of this, I'd suggest being extremely wary of transforming elements which users will interact with given the current state of browser support for transformations.
Overflowing and transformations
We mentioned earlier that while transformations don't effect the box model of an element, and so leave the layout of a page untouched, they do effect the overflow, and if we have overflow: auto, they can in fact impact the page flow.
In the element below, we have an image inside a div. The div has an overflow:auto. When we hover over the element (apologies to touch device users), the contained image scales up in size.

Now, in most browsers on most platforms (Safari on Mac OS X 10.7 is an exception) the browser adds a horizontal scrollbar to the div when you hover over the image, which adds to the height of the element, reflowing the page below it. Just something to be aware of.
CSS Positioning and Transforms
While I was writing this article, CSS legend Eric Meyer posted a detailed critique of one interesting aspect of transforms.
It has to do with the positioning of elements. When we absolutely or fixed position an element, and give it say a top and left, these positions are offset from their containing box - which is not necessarily their parent element. Rather, the containing box is the first ancestor which itself has either relative, absolute or fixed position. However, adding a transform to an element also makes it a containing block for its descendent elements! As Eric observes, this can particularly cause difficulties with fixed positioning. Rather than rehash Eric's detailed thoughts, I'll let you head over and read them first hand.
General Rendering Problems
On different browsers you'll find various rendering problems with transformed content. For example, with Opera, rotated text appears to be rendered in a lighter font than the same text when it isn't rotated. I've also seen redrawing problems when rotating text in WebKit browsers. In Safari on iOS 4, rotated text doesn't necessarily align smoothly along its baseline. None of these are necessarily deal breakers, but it's worth keeping in mind. Transforms are still experimental, so don't necessarily expect them to be perfectly supported in all circumstances just yet.
Hardware Acceleration
There's a widely held belief that at least some browsers hardware accelerate the rendering of CSS transformations (hardware acceleration involves the CPU handing off execution of certain types of calculation to the GPU, which can increase rendering performance significantly, particularly on mobile devices).
At present the current state of hardware acceleration for CSS transforms across all browsers and devices is difficult to pin down. A webkit engineer I tracked down confirmed that current versions of Safari (5.1 on the desktop, iOS 4), but not necessarily other WebKit browsers:
- animated 2D transforms in Safari are always hardware accelerated
- using 3D for static 2D transforms may improve performance, but may also increase memory use - a real issue for memory limited mobile devices in particular
Now, haven't we just spent however much effort covering 2D transforms? How could this possibly help? Well, as we'll see in an upcoming article on 3D transforms, we can use 3D transforms to do 2D transforms (for example, there's rotate3D). If squeezing maximum performance for iOS devices is a need, then it may be that using a 3D version of a transform will help.
It's also worth noting that issues around what aspects of CSS transforms are hardware accelerated and how that acceleration works are implementation details in specific browsers, and not specified as part of CSS Transforms. As such, across browsers there's likely to be little uniformity of approach to hardware acceleration, and even from one version of a browser to the next, approaches may change.
Backwards Compatibility
One of the strongest aspects of CSS3 features like gradients, border-radius, shadows and the like is that they have been typically designed so as to be easily used in a way that is backwards compatible almost automatically, or provided we keep a small number of potential challenges in mind. For example, with gradients we need to ensure we have a fallback background color or image for when gradients aren't supported. For text-shadow, we need to ensure that the contrast between the text and the element background is sufficient when the shadow is not drawn.
Of all new CSS3 properties, transform is the one where backwards compatibility is the most difficult to ensure. Ironically, it's precisely because transforms don't affect the page layout that they cause such difficulty. For example, in order to accommodate say a heading rotated 90 degree to run horizontally along the left hand side of the text which follows it, we need to create whitespace to ensure the heading does not overlap the text. We might do that with margin, or padding. We're also likely to want to remove the whitespace where the heading has been rotated away from, by, for example, using negative margin on the paragraph following the heading. But, what happens if transforms aren't supported? The heading text will be overlapped by the paragraph below it.
In order to use transforms for more sophisticated page layout along these lines, a solution like Modernizr, which enables different CSS to be applied based on the support, or absence of support for various CSS3 features like transforms is indispensable.
Transformations are typically most easily used in a way that is backwards compatible where animated transforms create a transition between states in an application. We're all most likely used to sliding or flipping transitions between states in iOS and other mobile apps. CSS transforms can be used for these transitions, in conjunction with CSS Transitions, and where transforms aren't supported (in which case it's unlikely transitions will be as well), your users simply see an abrupt change in state.
However you plan to use transforms, as with every other aspect of web development, keep in mind those browsers which don't support them, and ensure your user's experience isn't diminished to the point where information or functionality is denied them because their browser doesn't support it.
Browser Support
As we mentioned, despite the still rather experimental nature of support for CSS 2D Transforms, they are now widely supported in modern browsers including:
- Internet Explorer 9 and up
- Firefox 3.5 up
- Safari 3.2 up
- Chrome 10 and up
- Opera 10.6 and up
- iOS 3.2 and up
- Opera Mobile 11 and higher
- Android 2.1 and up
So, support is widespread, and constantly improving. While there are definitely challenges associated with using 2D Transforms, they're a powerful, and worthwhile addition to the repertoire of developers, and will only gain in value. What are you going to do with them?
More Reading
- The 2D Transforms Specification
- MSDN on Transforms - great to see the IE love for them!
- Opera's developer center on, you guessed it, Transforms
- On Transformations in Internet Explorer (before and after IE9)
- Bezier curves
- Accessing the gyroscope and accelerometer in mobile browsers (watch a live web based take battle built specially for the night!)
- WCAG ARIA
- Mobile HTML emails (our Sydney winner!)
- CSS3 Media Queries (our Melbourne winner, and great fun)
- Parallax effects in CSS
Principle 2.2. Degrade Gracefully
So, what happens if we use this feature in current browsers? Well, firstly none of these support the feature whatsoever. But here's an example I tried in a number of current browsers<section>
<style scoped>
p { color: red; }
</style>
<h2>How does it work?</h2>
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p>
</section>
<p>other stuff</p>
And here's what happened.Safari 5.1, Opera 11, Chrome, Firefox 6, and IE7 up all recognise the style element, and then style both p elements red - so scoping is not honoured - let's call this not graceful degradation.Principle 2.3. Do not Reinvent the Wheel
We currently can scope style in an HTML document. We use these new fangled things call CSS selectors. Even without touching the HTML above we could style the paragraphs in the given section like sosection:first-of-type>p{
color: red
}
Or we could add class or id as appropriate to our section. I'd need to see a pretty compelling use case here, that demonstrates a need that can't otherwise be solved using existing CSS/HTML practices and technologies, before beginning to even think there's a problem to be solved, let alone that this might be a good solution to that problem.Principle 3.1. Solve Real Problems
In over 15 years of web development, I've not seen a problem this is a solution to. If you are going to violate widely held long standing best practice, you need to do a bit better than invent a rare problem, then solve it in a way that opens the floodgates to terrible practice.Truthfully, and I have paid a fair bit of attention for close to 15 years in the CSS space, I have never ever once heard anyone articulate this need. Sure, it's probably happened, but it's far from a pressing concern.Principle 3.2. Priority of Constituencies
In case of conflict, consider users over authors over implementors over specifiers over theoretical puritySo, users get broken pages in older browsers with style scope. Authors who want to use it would need to hack around the fact that this not only doesn't work in older browsers, it causes rendering challenges. Seems we are focussing at the level of theoretical "purity", or maybe, the whims of specifiers here.Is this what versionless HTML development is about? Design principles violated left right and center, and an unwanted, unneeded and harmful addition to HTML, seemingly at the whim of one of the authors of HTML5?And the first place we hear about it is in a draft of the future HTML specification. I wonder what other hidden gems await discovery in that document?You know, it's not like there aren't some pressing real world problems to there for HTML to address.If you feel remotely strongly as I do, you can submit a comment on the draft HTML specification at the WHATWG here." ["post_title"]=> string(72) "On the (abominable) proposed HTML5 "scoped" attribute for style elements" ["post_category"]=> string(1) "0" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(68) "on-the-abominable-proposed-html5-scoped-attribute-for-style-elements" ["to_ping"]=> string(0) "" ["pinged"]=> string(93) " http://www.whatwg.org/specs/web-apps/current-work/multipage/semantics.html#attr-style-scoped" ["post_modified"]=> string(19) "2011-09-15 13:13:10" ["post_modified_gmt"]=> string(19) "2011-09-15 03:13:10" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=3646" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(1) "5" ["filter"]=> string(3) "raw" } [8]=> object(stdClass)#124 (25) { ["ID"]=> int(3642) ["post_author"]=> string(1) "3" ["post_date"]=> string(19) "2011-09-06 09:55:59" ["post_date_gmt"]=> string(19) "2011-09-05 23:55:59" ["post_content"]=> string(687) "There's not necessarily a lot of whimsy in the world of web standards. A great deal of value, a lot of hard work by really smart people, but not whimsy.Well, recently there's been a little bit of whimsy in the otherwise dry, but very useful CSS3 Text module, with the "bikeshedding" property. But sadly, no more. bikeshedding is now more prosaically named "white-space-collapsing", and I for one think this is wrong. So wrong, that I'm campaigning for the reinstatement of the bike shedding name.If like me, you want to bring a little bit of whimsy back to web standards, then join the campaign by commenting below, and bring back bikeshedding!" ["post_title"]=> string(42) "Bring back the CSS bike shedding property!" ["post_category"]=> string(1) "0" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(41) "bring-back-the-css-bike-shedding-property" ["to_ping"]=> string(0) "" ["pinged"]=> string(0) "" ["post_modified"]=> string(19) "2011-09-06 09:55:59" ["post_modified_gmt"]=> string(19) "2011-09-05 23:55:59" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=3642" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(1) "5" ["filter"]=> string(3) "raw" } [9]=> object(stdClass)#125 (25) { ["ID"]=> int(3638) ["post_author"]=> string(1) "3" ["post_date"]=> string(19) "2011-09-02 11:11:32" ["post_date_gmt"]=> string(19) "2011-09-02 01:11:32" ["post_content"]=> string(13129) "
In the infancy of JavaScript, there was little if any concept of an HTML document object model (DOM). Even though JavaScript was invented to enable web developers to manipulate parts of a web page, and in the original implementation, in Netscape 2.0, developers could only access the form elements, links, and images in a page. Useful for form validation, and first widely used for image rollover techniques (think :hover, before CSS), but far from the general purpose tool to create modern web applications we now know (and love/hate).
Newer iterations of the DOM provided developers with access to far more than just that original limited range of elements, as well as the ability to insert, modify and delete elements in an HTML document. But, cross-browser implementations very often differed, and full support for the W3C's DOM standards have arguably been treated as far more optional than CSS or HTML support.
One of the many reasons for the success of JavaScript libraries like jQuery and Prototype, on top of their easing the pain of cross-browser development was how they made working with the DOM far less painful than it had previously been, and indeed how it was with the standard DOM. Being able to use arbitrary CSS selector notation to get matching elements from a document made the standard DOM methods seem antiquated, or at the every least, far too much like hard work.
Luckily, the standards and browser developers took notice. The W3C developed the Selectors API, a way of easily accessing elements in the DOM using standard CSS selector concepts, and browser developers have baked these into all modern browsers, way back to IE8.
In this short (by my standards) article, we'll look at the Selectors API, how you use it, browser support, and some little things you might like to keep in mind while using it. Rest assured, it's now widely supported, so in many cases, you can safely use it, potentially with a fallback for older browsers (IE7 and older specifically) via libraries like jQuery (or more lightweight selector engines like Sizzle, which provides this functionality for jQuery, and other libraries).
The Selectors API
The Selectors API, which many would consider to be part of HTML5, is in fact a separate, small specification from the W3C. It provides only two new methods, querySelector, and querySelectorAll, for the Document, Element, and DocumentFragment objects (typically, you'll use these methods on the document or element objects.) But do these methods make life easier for developers?
Before the Selectors API, to access an object in the DOM we could use these methods:
getElementById(from DOM Level 2 Core) - available for thedocumentelementgetElementsByClassName, standardized in HTML5, after long non standard browser support, which is supported ondocuments andelementsgetElementsByTagName, from DOM Level 2 Core, available on thedocumentandelementobjects
And there are some legacy ways of accessing elements on a page, which date from the earliest days of JavaScript:
linksis a property of the document object which contains all anchor (a) andareaelements with anhrefattributeanchorsis a property of the document object which contains allaelementsformsis a property of the document object which contains all form elements
We can also "traverse" the DOM, using:
childNodes, a property of thedocumentandnodeobjectsnextSibling, a property of anode, which contains the element directly following it in the same parent elementparentElement, a property of a node, which contains its parent element.
and related DOM traversal properties and methods.
But, what developers really often want to be able to do (as the success of jQuery and other libraries has shown) is simply say "give me all the elements which match this selector", or "give me the first element which matches this selector". And that's precisely what the simple, powerful Selectors API does. It doesn't completely do away with the need for DOM traversal, and legacy methods and properties, but it goes a long, long way.
querySelector
querySelector is a method of the document or any element, which returns the first descendent element which would be selected by its one argument, a CSS selector string. We can use this in place of the document.getElementById('content') like so: document.querySelector('#content') (like me, you'll probably find yourself forgetting to add the # from time to time in querySelector, something which doesn't throw an error, so can be frustrating to track down).
And we can do things like find the first header element in an HTML5 document, with querySelector('header'). So far so good. But where querySelector really shines is we can use any selector (attribute, structural, dynamic, UI, and even selector groups) with it. In most cases, this makes traversing the DOM, and locating a specific element far simpler, and most likely far quicker, as we won't be looping in JavaScript and accessing all kinds of DOM properties, rather, the query is taking place inside the browser's far faster native DOM engine.
querySelectorAll
Often, when working with the DOM, we want to manipulate several elements at once, For example, we might want to unobtrusively attach an event listener to all the links with a given class value. Here, querySelectorAll is your friend. Just like querySelector, it takes a single string as an argument, which is a CSS selector. Instead of returning a single element, it returns a NodeList (a kind of JavaScript array) of matching elements. We can then iterate through this array, and manipulate these objects.
For example, we could use it to replace document.links like so:
document.querySelectorAll('area[href], a[href]')This finds all area elements with the href attribute set, as well as all a elements with this attribute set as well (notice how we've used a selector group, which is quite acceptable with the Selectors API).
Matching elements are returned in the order they appear in the DOM parse tree.
Document or Element?
I mentioned that both the document, and element objects implement these two methods - what's the difference? Well, as you might have guessed, these methods find elements that are descendants of the object you query on. So, if you use the method on a paragraph element, it will only find the descendant elements of that paragraph which match the selector. Other elements in the document which might match it won't be returned. But, if you use the methods on the document, then any matching element in the document can be found.
Gotchas
If you've really got your hands dirty with the DOM, you'll know that when DOM methods return a NodeList, it is live—that is, the members of the list change, depending on the state of the document.
Let's say we get all the elements with a class of "nav" using document.getElementsByClassName('nav'), and it returns 5 elements, which we keep in a variable.
Now, if we add a new element with class nav, or remove one of the existing elements with a class of nav, the NodeList in our variable will be updated to reflect these changes (that's why it is called a live NodeList).
But querySelector and querySelectorAll are different. While they return a NodeList, it is static. So, if we similarly get all elements with a class of nav using document.querySelectorAll('.nav'), then regardless of what we subsequently do to the DOM, the length and contents of the NodeList won't change. Which means, it's always best to query the DOM just before you need the elements, rather than holding on to elements if your DOM is going to change.
There's also a performance consideration. Tests of various browsers indicate that querySelectorAll is slower than getElementByTagName (though not it would appear in Opera). But, it's also possible that once available, manipulating the static NodeList may be higher performance than manipulating a dynamic NodeList. And this issue will likely only have an impact in extreme cases. I'd certainly not recommend prematurely optimising by using getElementsByTagName, getElementsByClass, getElementById and so on in place of querySelectorAll, but it is worth noting you might be able to squeeze a little more performance out by doing so if you really need to.
And it is worth noting too that querySelector and querySelectorAll don't work with every kind of selector. While pseudo-class selectors (like :visited) work with these methods, pseudo-element selectors, like :first-letter, :first-line, :before and :after although permissible as arguments, will return null in the case of querySelector, and an array of length zero for querySelectorAll.
A little gotcha this aging developer has found I'm so used to getElementById and getElementsByClassName that I find myself forgetting the # or . required in the selector string in querySeletor and querySelectorAll. As I mentioned a moment ago, it can be frustrating, as this won't throw an error, but simply return null or an empty NodeList.
Support
All modern browsers, including IE8 and up support both querySelector and querySelectorAll. It is however worth noting that the results returned are dependent on what selectors the browser supports. IE8 supports CSS2.1 selectors, though not CSS3 selectors. IE9 supports many CSS3 selectors, but not a number of the UI related pseudo-classes, such as :required and :invalid. IE CSS support for versions 5 through 9 is extensively covered here by Microsoft.
So, keep in mind, even where these methods are supported, what they return is only as good as the CSS selector support in that browser.
The Wrap-up
If you're more of a web designer who's always been a little intimidated by the thought of wading through the DOM in search of elements (trust me, even seasoned developers often wince at the thought), then querySelector and querySelectorAll are a boon for you. Or, if you're a developer who finds yourself going straight for jQuery or another library as soon as the DOM is involved, the Selectors API might just save you a few KBs, additional files and fussing around. And, if you're one of those seasoned DOM experts, I'm sure there's plenty of times you'll breathe a sigh of relief that rather than wading through an entire document with childNodes, nextElementSibling and the like, a single call to querySelectorAll will return all the elements you want. I reckon these two are my favourite, and now most used DOM methods, and I'm only surprised they aren't more widely covered, as they really are like a Swiss Army Knife for the DOM. Perhaps we need a "top 2 Selectors API methods" article. Then again...
Reading
Here's a few articles and other resources which delve into the Selectors API.
- The Selectors API specification from the W3C
- Selectors API at Opera Developers Center, by Lachlan Hunt, one of the authors of the spec.
- Selectors API at Mozilla Hacks
- Thoughts on performance from JS performance guru Nicholas Zakas (the comments are well worth reading)

- it must be a site developed by an Australian individual or team
- it must have launched or been significantly upgraded between September 22nd 2010 and September 23 2011 (you have another month to finish your site or upgrade!)
A brief history on Animation of the Web
If you've been developing for, or even just using the web for more than about 15 years, you'll likely remember a time when animated effects were the bomb. Animated GIFs adorned just about every page, spinning globes, little men with jack hammers, self-folding winged envelopes. And if you're very unlucky, you'll remember the explosion of blinking content on the web around 1995, as the blink element in the then dominant Netscape browser took hold of the imagination of designers everywhere (for killing off the non-standard blink element alone, the web standards movement deserves at the very least a Noble Peace Prize). And perhaps the single widest JavaScript use in its earliest days was for creating image rollovers, until CSS got into the act with the hover state. In short, animation has had a long, if checkered career on the web.
Then, for years, animation fell out of favour, but with the rise of JavaScript libraries, we've seen the re-emergence of animated interfaces.
CSS3 animation
In the last 2 or 3 years, CSS3 has got into the act, providing a reasonably straightforward declarative way of creating even quite sophisticated animations, where complex JavaScript had previously been required.
In this article we'll take a look at two related ways CSS3 provides for creating animations and animated effects, CSS Transitions and CSS Animations. We'll look at how to create them, browser support, some interesting gotchas, and yet again, I'll introduce a tool, AnimatR, I've created to help you more easily, and quickly, create cross-browser CSS animations. But please use animations wisely, tastefully and sparingly - we've take nearly 15 years to recover from the "blink tag". Let's not wait until 2026 for our next opportunity to get animations on the web right.
The JavaScript controversy
First up, let's address a now fading controversy. When CSS animations were first proposed and experimentally introduced in Webkit, (coming up on 4 years ago now), many prominent, thoughtful developers felt strongly that animations were rightfully the domain of JavaScript, not CSS. Among the strongest, and most articulate, of those critics was Jonathan Snook, who subsequently revisited his concerns, and changed his position. In short, the concern is that animation is a kind of behavior, considered the domain of JavaScript, not presentation, the domain of CSS. But the simplest way of understanding an animation is that it is the change of presentational aspects of an element (height, width, color, etc.) over time. In short, animations are presentation, even if prior to CSS3 Transitions and Animations, they could only be achieved via JavaScript.
We also increasingly have the benefit that CSS based animation is being hardware accelerated in browsers, making for smoother animations and transitions even on relatively low powered mobile devices.
Let's begin with the simpler CSS Transitions, then continue with CSS Animations. Animations reuse many of the concepts, and even syntax of transitions, so what we learn about transitions we can apply with animations as well.
Transitions
In CSS3, there are two kinds of animated effects - transitions and animations, which work in very similar ways. You might even think of transitions as simple kinds of animations. Transitions are the animation from one set of an element's CSS property values of to another set. At their simplest, that might be a smooth animation from a background-color of red to a background-color of green.
Animations enable multiple changes to the presentational properties of an element over time - for example a 2 second animation from background-color of red to green, then a 1 second transition back to red again, repeated indefinitely (we'll see less boring, and more useful animation examples shortly).
First introduced in Webkit and now supported across all modern browsers, including IE10 developer previews, transitions allow us to animate the change in presentation between two states, that is two sets of CSS properties. At its simplest, a transition might be just a smooth change from one value of a property to another value, over a specified period of time - for example, the smooth change of height over 2 seconds. To create simple transitions, we use the transition-property property, with a space separated list of CSS properties to be animated, and the transition-duration property, to specify how long the animation should take.
Here's a really simple example: let's cross fade a background-color from red to blue in 2 seconds.
p {
transition-property: background-color;
transition-duration: 2s;
background-color: red;
}Which leaves one simple question to answer - how do we trigger the change, and so the animated transition? Well, here's the deceptive simplicity of transitions - they take place any time the specified property (in this case background-color) changes. So, if the background-color changes because we have a different background-color specified for the hover or other state, or if we use JavaScript to change the background-color, then those changes in color will be animated! Let's try it out. If we specify a different background-color when the paragraph is in a hover state, like so:
p:hover {
background-color: blue;
}
Then any time you hover over a p element, the color will fade. Let's see that in action below
A little pro tip as we go along - make sure you put the transition properties (transition-property, transition-delay etc.) on the element in its normal, not hover state.
But what's with the s unit for the transition-duration property? CSS has in fact had units of time since CSS2. Originally part of Aural Style Sheets, we can specify time in either seconds (s) or milliseconds (ms) - 1,000 milliseconds in a second. CSS3 Transitions and Animations reuse these units, which are also part of CSS3 of course.
So, hopefully the basic idea is clear - with transitions we tell a browser that when a certain property or set of properties change, the change should not be abrupt, but be animated over a certain time period. Now, you might have noticed in the transition above the text color changes too - but does so without an animation. That's because we've only specified that the background-color have an animated transition, via transition-property. We can as mentioned specify multiple properties, by listing each in a comma separated list of property names like so:
transition-property: background-color, color;
If we want all of the transitions to take the same amount of time, we can specify a single transition-duration property value. But, if we want different properties to transition over different time periods, we do so by listing the time values in a comma separated list - with the time periods and properties in the same position in their respective lists. Here for instance, the color will transition over 1s, while the background-color will do so over 2s:
p {
transition-property: background-color, color;
transition-duration: 2s, 1s;
background-color: red;
}And here this is in action:
If we want to animate the changes for any properties which change, we can use the keyword all as the value for transition-property. This will ensure that regardless of which property changes, that change will be animated (not all properties can in fact be animated - we'll cover which ones can be shortly). Be careful with the all keyword - should future properties support animation, these will be animated, and it may not be clear at this stage just what these animations will look like.
There's also the shorthand transition property which takes a space separated property name and time values like so:
p {
transition: background-color 2s;
}Note how there are no commas between the property and time value.
Or, if we have multiple property and time pairs, we separate each pair with a commas, like so
p {
transition: background-color 2s, color 1s;
}And in a nutshell, that's the core of CSS3 transitions. We'll touch on some gotchas (most of which are shared with animations) a little later. And we'll take a look at browser support in detail in just a moment. But there are some optional features of transitions you might find useful, including specifying the nature of the transition, and a delay before a transition starts.
Transition Timing Functions
When a transition occurs, there are various ways the intermediate steps can take place. Let's take the example of an element moving from left to right across the screen, over 2 seconds:
Notice how it begins quickly, then slows down as the transition draws to an end. Now, take a look at the same transition below, with a very slight change.
The difference between the two is they have different transition-timing-function properties. This property "describes how the intermediate values used during a transition will be calculated". There are 5 timing function keywords (as well as some more complicated ways of describing timing functions mathematically using Bezier curves which we won't go into here), ease, linear, ease-in, ease-out, ease-in-out.
Each of these is defined in mathematical terms in the specification, but it makes much more sense to let you see them all in action.
We specify an optional timing function (as noted above, the default is ease) using the property transition-timing-function, with one of the keywords above as its value. As mentioned, we can specify a timing function as a cubic Bezier curve, but if you need to get this technical with your transitions, the best place to understand the details is the specification.
Which timing function you choose is a matter of taste, and for most purposes, the default value of ease should be fine.
Delay
There may be occasions on which we want a transition to delay for a certain amount of time before commencing, and we can do this quite straightforwardly with the transition-delay property. As with transition-duration we do this using a time value in seconds or milliseconds.
transition-duration: 150ms;
We can also specify different delays for different transitions, like this (click the element below to see the effect):
transition-property: top, left; transition-duration: 2s, 1.5s; transition-delay: .5s, 0s;
Browser Support and Backwards Compatibility
So, having introduced such a mouthwatering prospect for designers, just how useable is it today? In fact, surprisingly so. All modern browsers support transitions, including IE10 developer previews. Firefox has done so since version 4, Safari since 3.2, Chrome since at least version 9, Opera since 10.6, iOS since 3.2 and Android since 2.1.
It does need to be noted that not all browsers animate all property changes - we'll look at this in a little more detail in the animations section, since the list of properties applies to both animations and transitions.
However, as yet, all browsers require vendor prefixes in front of all the properties for transitions - which can make for some unwieldy CSS.
Since transitions only animate changes in style that are triggered either by a change in state (like hover or focus) or via JavaScript, they are effectively backwards compatible to just about any browsers likely to be used today. Users of those browsers simply don't see the intermediate steps between one state and the other, merely the abrupt transition they'd always have seen. We just need to ensure that in the absence an animated transition, no information is lost.
From a usability and accessibility perspective, we should also be mindful that flashing content can trigger seizures in some users, and that sudden movements of content (for example a block of content from one place to another) in the absence of an animated transition may be disorienting, particularly for users with cognitive disabilities.
Transitions are straightforward to use, widely supported, backwards compatible, and can add a little more to your site or application. However just make sure you don't overdo them. Remember the <blink>.
Animations
Similar in many ways to transitions, CSS Animations allow us to create multi-step animated content using only CSS and HTML (though we will often want to use just a little JavaScript to trigger the animation).
I've mentioned that animations and transitions have a good deal in common - here's a quick look at their similarities and differences.
Similarities between CSS Transitions and Animations
- Both animate the change in CSS property values over a period of time
- Both have a duration
- Both have an optional delay
- Both have an optional timing function, defined in the same way
Differences between CSS Transitions and Animations
- Animations can repeat any number of times
- Animations can be specified to go in a forward and reverse direction
- Animations can have any number of defined intermediate steps, called "keyframes", but transitions only have a defined start and end "keyframes".
- With transitions we can specify an animation for any property which changes, using the
allkeyword. With animations, we need to specify every property we want animated.
How CSS Animations are defined
Creating a CSS3 animation is a little more work than creating a transition, involving two interlinked steps.
We need to create a regular CSS rule, which selects the element or elements we want to be animated, and we give this rule a set of CSS properties related to animations (we'll look at these properties in a moment).
We also create an @keyframes rule, similar to an @media rule, which defines the two or more keyframes in our animation. If we have simply two keyframes, for the beginning and end of our animation, a transition is most likely the better choice. Each keyframe specifies the state of the animated properties at that particular time during the animation.
While it might sound a little complicated, each step is quite straightforward. Let's take a look at each in turn.
The animation properties
Just as with transitions, we specify various aspects like the duration and timing function of the animation using CSS properties. But first we need to declare which @keyframes rule will be used to specify the keyframes of our animation, which we do using the animation-name property. Animation names follow the same rules as HTML4 id values - alphanumeric characters, dashes and underscores, and begin with a letter. Here we're specifying that the header element should be animated using an @keyframes rule with the name opening-sequence (we'll see very shortly how we give @keyframes rules names).
header {
animation-name: opening-sequence;
}Notice how the animation-name value is not quoted.
We'll return to familiar territory by specifying a duration and timing function for the animation, using the properties animation-duration and animation-timing-function. As with transitions, the duration is specified in seconds or milliseconds, while the timing function takes one of the keywords we saw earlier (or again a more complex formula we'll not go into here).
header {
animation-name: opening-sequence;
animation-duration: 5s;
animation-timing-function: ease-in;
}As with transitions, we can also delay the beginning of an animation, here using the animation-delay property, with a value once again in s or ms.
header {
animation-delay: 500ms;
animation-name: opening-sequence;
animation-duration: 5s;
animation-timing-function: ease-in;
}So far, all should be very familiar from transitions. Now we meet two new properties. The first is for specifying how often the animation runs (once, a certain number of times, or indefinitely). The other is for specifying what happens when a repeating animation completes - should it begin again from its initial state, or play the animation in reverse? Let's take a look at each.
Specifying that an animation should run more than once is very straightforward. We use the animation-iteration-count property, and give it either a numerical value, or the keyword infinite. The animation then runs the specified number of times, or indefinitely. The delay in commencing the animation only applies to the very beginning of the animation, and there will be no delay between iterations.
When an animation does run more than once, for example if an element moves from left to right on the page, what should happen when the next loop of the animation begins? There's two possibilities. The animation could begin where it did the first time - for example on the left, as in this example
animation-direction: normal;
Or, the animation could reverse direction, returning to the starting values, as the animation below does:
animation-direction: alternate;
We define this behavior using the animation-direction property, which takes one of two possible keyword values: alternate or normal. To achieve the first of the effects above, we use the animation-direction property with a value of normal. The second of the two has a value of alternate for the animation-direction property.
Now we've set up part one of our animation, it's time to create the animation itself. As we've mentioned, this is done using an @keyframes rule. The form of this rule is:
@keyframes opening-sequence {
0% {
/*properties to animate*/
}
20% {
/*properties to animate*/
}
100% {
/*properties to animate*/
}
}That is, we start with the keyword @keyframes. This is followed by the animation name. Next, inside curly braces (}"{" and "}") we have two or more keyframes. A keyframe has the form of a percentage value, and then a group of CSS properties inside their own curly braces.
The first keyframe must be 0%, and unlike elsewhere in CSS, the % is required. The last keyframe must be 100%. OK, so we can use the keyword from in place of 0% and to in place of 100%, but both the first and last keyframes must appear.
To create the animations above, we'd have this @keyframes rule:
@keyframes opening-sequence {
0% {
left: 0%;
}
100% {
left: 80%;
}
}Note how our keyframes rule doesn't have anything to say about the direction, duration, and so on. These are properties we specify for particular elements using the animation properties we've just seen. Both of the animations just above use the same @keyframes rule - they just have different animation-direction properties. Here are the complete rules for each of those animated elements
#normal-animation {
background: red;
position: relative;
width: 20%;
animation-name: opening-sequence;
animation-duration: 5s;
animation-iteration-count: infinite;
animation-timing-function: ease;
animation-direction: normal;
}
#alternate-animation {
background: red;
position: relative;
width: 20%;
animation-name: opening-sequence;
animation-duration: 5s;
animation-iteration-count: infinite;
animation-timing-function: ease;
animation-direction: alternate;
}
The only difference between the two is the value of the animation-direction property.
Let's take a closer look at the @keyframes rule. Each keyframe is more or less like a regular CSS rule. In place of a selector like p.classname, it has a percentage value. The percentage value specifies where in the animation this keyframe belongs. For example a keyframe percentage of 40% in a 10 second animation occurs after 4 seconds.
It also has a declaration group of properties, separated by semicolons, as we'd find in a regular CSS rule. These define what the appearance of the selected element or elements should be at this point in the animation. The browser then animates the transitions between these keyframes.
Rather than go on in ever greater detail, perhaps the best way for you to get a better understanding of animations is to create some. And you don't need to fire up a text editor, just head over to AnimatR, the tool I've developed to help you create animations. I'll go into a bit more detail about how it works shortly, but it should make sense if you've read this far (and hopefully make more sense of what you have read).
Before and After Animation
Suppose we have this CSS
header {
width: 90%;
animation-name: opening-sequence;
animation-delay: 2s;
...
}And this animation
@keyframes opening-sequence {
0% {
width: 40%;
}
100% {
width: 60%;
}
}What width is the element during the 2 second delay before the animation begins? What about after the animation completes? In both cases, it's 90% (which may not be what you want). But we can specify that instead of the applied properties, the opening and closing keyframe properties should apply during the animation delay, and after the animation completes using the animation-fill-mode property.
animation-fill-mode can take the following keyword values:
- none
- the default state, as described above
- forwards
- the properties from the 100% keyframe will continue to apply after the animation completes
- backwards
- the properties from the 0% keyframe apply during the delay period of the animation
- both
- both the forwards and backwards cases hold
Triggering animations
We saw that transitions occur when we change the associated CSS properties, either using CSS, or JavaScript. But when do animations occur? An animation will begin as soon as a page is loaded, which may not be what we want to occur. There's various ways we can stop the animation auto-playing. We could not give an animation-name property to the elements we want to animate, and then apply this property using JavaScript when we want the animation to commence. But simpler in a way is to use the animation-play-state property. This takes one of two keywords, running or paused. We can change this using JavaScript:
element.style-animation-play-state="running";
Or even trigger an animation to run only when the user is hovering over an element (far from recommended):
header {
animation-play-state: paused;
}
header:hover {
animation-play-state: running;
}Browser Support
We were in luck with transitions, as we saw they have widespread support in modern browsers, including IE10. We're not quite so lucky with animations, but support is definitely on the increase. At present, Safari since version 4, Chrome since at least 9, Firefox since version 5, iOS since 3.2 and Android since 2.1 have support for animations. While support in Opera and Internet Explorer 10 has not been announced, as both these browsers support transitions, arguable the hardest part of CSS animations to implement, support for animation in these browsers may not be too far off.
As with transitions, all animation properties must currently have vendor prefixes: -webkit-, -moz- (and so on for future browser support). This is also true for @keyframes rules, but these have a slightly unusual format. Typically we prefix the property name, but for @keyframes the prefix comes after the @ and before the keyframes keyword, like so:
@-webkit-keyframes{
}
@-moz-keyframes {
}As with transitions, animations will typically be backwards compatible, particularly if they are used to add a layer of enhanced user experience, rather than content in their own right. One area where animations are beginning to see some use is in browser-based games. As many browsers and devices hardware accelerate animations and transitions, for applications where performance is a significant issue, as it often is with games, animations will become an increasingly attractive solution. But here backwards compatibility is a significant issue - with games, animations aren't simply decoration, they are central to the user experience. So, for some time to come, choosing to use CSS animation to develop games will necessarily mean excluding some users from playing those games.
Animations also pose a potentially significant challenge to creating accessible content. Where sophisticated animations are in essence an important part of the content, there is as yet no consensus as to how to make rich animations developed using CSS3 accessible.
Animation (and Transition) Gotchas
As a technology still in its infancy, animations do have a number of gotchas it is worth knowing about, to save hours of hair pulling and head-on-table banging. I'm sure there are many more than this, but here are some that I've come across.
Supported properties
Not all properties are animated. A list of properties that can be animated is outlined in the specification. Noteworthy is that background images can't be animated (though properties like background-position are), with the theoretical exception of gradients (in practice gradients aren't animated by any browser as yet).
It's also important to note that transitions and animations only animate property transitions which would otherwise occur. For example
@keyframes widen {
0% {
width: 5em;
}
100% {
width: 10em;
}
}won't animate the width changes of an inline element like an <a>, because we can't set an explicit width on an inline element. Similarly, for a paragraph which is statically positioned,
@keyframes move {
0% {
left: 5em;
}
100% {
left: 10em;
}
}won't animate the element, as we can't set the position of elements with a position: static. So, if your animation or transition isn't working, make sure the properties make sense. In the case of our link above, we could give it a display: inline-block, while in the case of the paragraph, a position: relative, and then the animations would take effect.
Animations in the Wild
So, just how sophisticated can CSS based animation be? Earlier this year, Naomi Atkinson and Mircea Piturca created an opening title sequence for our European conference, @media. Here's a video of it appearing on the big screen, in front of hundreds of people in London's famous Queen Elizabeth Hall:
Opening credits at Web Directions @media 2011 from Naomi Atkinson on Vimeo.
Renowned designer and developer Cameron Adams created these stunning opening titles for our conference, Web Directions South 2010. Displayed on two enormous screens in a theatre with a capacity of 1,000, it was an amazing sight to see. Note, this was expressly designed for 1024x768 resolution, and uses the font Gotham, so if possible, make sure you have the font, and set your screen to that size.
Perhaps the pre-eminent CSS Animator to date is Anthony Calzadilla, whose experiments and commercial work have really opened up people to what's possible with CSS transitions and animations. Well known examples include Madmanimation, and an animated cover for the Wired Magazine iPad edition.
You'll also find various collections of animation demonstrations like this one.
Introducing AnimatR
As CSS becomes ever more powerful and sophisticated, understanding, learning and remembering all the associated concepts, property names, syntax and so on becomes an ever more onerous job. So, as I am lazy, I've developed yet another tool, this time to help me (and hopefully you) understand and use CSS animations - AnimatR. AnimatR is not a WYSIWYG animation tool like Sencha's slick Animator, the eagerly awaited Animatable, or the just announced Adobe Edge. Rather, it's kind of like training wheels, to help you get up to speed with the concepts and syntax of animations (or for me a kind of Zimmer frame to help me totter along with all these new fangled CSS innovations).
It helps you easily set up the animation properties (except animation-play-state), as well as the keyframes for your animation. You can also add further style for the animated element, for example, giving it a position: absolute for animating an element's location (an ever popular pastime).
To use the code you create with AnimatR, just change the #demo selector to select the element or elements you want to animate in your pages, and paste the contents of the code field into your style sheet. AnimatR will even generate the vendor prefixed versions for -moz- and -webkit- browsers (since Opera and IE have yet to announce support, I've not added support for these browsers yet).
Use wisely
Right now, there's very little "hotter" in web development than animation, shown by the takeoff of Apple's iAD, and other mobile advertising technologies along with tools like Adobe Edge and Sencha Animator. I hope you'll agree they really aren't all that complex to use, but also that they need to be used intelligently. The novelty of stuff on the web which flashes and moves has worn off (I hope). It's time for web based animation that is smart and engaging. You have the tools - now get to it!
" ["post_title"]=> string(54) "Let the Web move you - CSS3 Animations and Transitions" ["post_category"]=> string(1) "0" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(52) "let-the-web-move-you-css3-animations-and-transitions" ["to_ping"]=> string(0) "" ["pinged"]=> string(0) "" ["post_modified"]=> string(19) "2011-08-07 14:36:34" ["post_modified_gmt"]=> string(19) "2011-08-07 04:36:34" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=3580" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(1) "9" ["filter"]=> string(3) "raw" } [12]=> object(stdClass)#128 (25) { ["ID"]=> int(3536) ["post_author"]=> string(1) "3" ["post_date"]=> string(19) "2011-07-26 14:54:32" ["post_date_gmt"]=> string(19) "2011-07-26 04:54:32" ["post_content"]=> string(30961) "Hard perhaps to believe, but the world wide web began without an image element. That's right, there was no way to include images as part of the content of a web page before Mosaic implemented them (here's Marc Andreesen proposing the img element at the beginning of 1993). The img element ushered in the age of included content so the web browsers could now display gif, jpeg, and more recently PNG format images in a standard way, but that's where matters stayed for more than a decade. While the non-standard embed element (ironically, now standardized in HTML5, and later standardized object element enabled developers to include audio, video, and interactive content, browsers did not implement native handling of these kinds of media - the actual rendering was left to plugins, like Flash (while the number of different commonly used plugins today is quite low, in the late 1990s there was an explosion of different plug in technologies.)
While HTML5 for the first time specifies a way of incorporating audio and video content via the mundanely named audio and video elements, the revolution in web content these bring is that browsers now no longer require plugins to play the content, rather they do so "natively". Which has the advantage that users don't need to download and install plugins, or keep them up to date. But there's more to it than that. With plugin content, browsers effectively hand over a part of the browser window and say to the plugin - "ok, this is all yours, do your worst". Which makes applying style to a video player (rounded corners, or adding a drop shadow, for instance) challenging, and effects like layering HTML based content over the top of plugin content a bit of a lottery.
HTML5 audio and video has been, in browser years, quickly adopted by all major browsers (we'll cover off browser support in just a moment). But let's first take a look at how we incorporate audio and video content into HTML5 documents, how to provide fallbacks for browsers which don't support them, and the inevitable gotchas. And once again, I'll introduce a couple of tools we've developed to make life easier for you when using native multimedia content in your web sites and applications.
There are a lot of great resources out there, which go into much more detail on some aspects we only really touch on here, particularly on the complex issue of formats and codecs, as well as the challenges of making your content accessible. There's a list of further reading at the end of the article.
We'll begin by looking at audio, and then follow up with video, which we use in almost exactly the same way as audio.
HTML5 Audio
HTML5 introduces the audio element, for embedding audio files in a page. Browsers which support HTML5 audio provide a simple audio player for playing, scrubbing forward and back through content, as well as setting the volume. It's also possible to hide these controls, and either autoplay files, or build your own player interface using HTML and the audio element's JavaScript API (which is beyond the scope of this article, but not really that difficult at all if you are competent in JavaScript).
Setting up the element
The first thing we need to do to include audio in a page is to add an audio element to the HTML. Unlike img, audio is a non empty element - that is it can contain other HTML, so has an opening and closing tag.
<audio></audio>
Of course, this isn't going to play anything, just as an img element with no src attribute won't display an image. So, you're probably guessing we add the audio file reference using a src attribute. And you're more or less right. We can do that, but there is another, better way to add a reference to the sound files we want to play. This is because the audio element can have only one src attribute, but because different browsers support different audio formats, at least for now, and for the foreseeable future, we'll need to provide browsers with multiple sound files, so that we cover all browser bases. We'll turn to how we do this in a moment, but let's first look at several other attributes the audio element can take.
controls- The
controlsattribute, when present, tells a browser to display the default controls for its audio player. If the attribute is not present, then no controls will be displayed. loop- another boolean attribute, if this is present, the audio file will begin again after it has played indefinitely
autoplay- if this attribute is present, then once the sound file can begin playing, it will.
autoplayshould be used carefully and sparingly! autobuffer- this is now replaced with the
preloadattribute which we'll look at in a moment, but as older browsers, for example Safari 4 supportautobufferinstead ofpreload, you may wish to add this attribute as well if you want audio to be buffered by the browser as soon as a page is loaded. Browsers may choose to ignore this, or not support it at all (Opera for example doesn't support preloading of audio)
Before we continue, these attributes are boolean attributes, which you might not necessarily be as familiar with as you are regular attributes. Boolean attributes (another exampled is checked) are either true, or false, depending on whether they are present or absent on an element. So, they look like this
<audio controls loop></audio>
That is, they don't take values. If this offends your XHTML sensibilities, they can also be written like so
<audio controls="controls" loop="loop"></audio>
That is, with their name as their value as well. Why they aren't written as controls="true" is beyond me, but there you have it.
In addition to these boolean attributes, and the src attribute (which we've recommended ignoring) audio can also take the preload attribute, which has one of three values. The preload attribute doesn't force the browser to preload an audio file, but rather, suggests to the browser how it can provide the best user experience to the user (balancing the impact of downloading a potentially large file, with the benefit of faster response to their choosing to play a file). In the words of the specification, these values are
none- Hints to the user agent that either the author does not expect the user to need the media resource, or that the server wants to minimise unnecessary traffic.
metadata- Hints to the user agent that the author does not expect the user to need the media resource, but that fetching the resource metadata (dimensions, first frame, track list, duration, etc) is reasonable.
auto- Hints to the user agent that the user agent can put the user's needs first without risk to the server, up to and including optimistically downloading the entire resource.
Getting Sourcey
Having suggested we don't use the src attribute to link to the audio file to be played, how then can we do this? Well, we saw audio elements can contain other HTML elements, and in this case, we're going to use the source element (also new in HTML5), to provide links to one or more audio files in various formats. The browser can then download the format it supports, ignoring others to save bandwidth.
Like img, the source element uses the src attribute to link to a file. So, if we want to link to an mp3 file, we do so like this
<source src="http://westciv.com/podcasts/youmayknowmypoetry.mp3">
and, if we put that all together, that's all we need to play this file in browsers which support mp3 (at present, IE9, Safari, Chrome, Android and iOS).
<audio controls="controls" loop="loop"> <source src="http://westciv.com/podcasts/youmayknowmypoetry.mp3"> </audio>
While several browsers will be able to play this content, neither Firefox nor Opera support the mp3 format natively. They both however, support the Ogg Vorbis format, so in addition, we'll link to an ogg version of this same audio file, for the benefit of users of these browsers.
<audio controls="controls" loop="loop"> <source src="http://westciv.com/podcasts/youmayknowmypoetry.mp3"> <source src="http://westciv.com/podcasts/youmayknowmypoetry.ogg"> </audio>
Where a browser happens to support both ogg and mp3, it will use the first source it finds which it supports, and so in this case, play the mp3 version.
So now we have an audio element, with two sources, which provide audio that can be played in all modern browsers. But what about older browsers? Can we also include support for them? Let's find out.
As an aside, beneath the seemingly simple issue of audio and video formats, there's more than a little complexity. We'll look at this whole issue separately in the gotchas section, but I'll just note here, that we can give the browser further information about the file, including it's MIME type, and a specific codec to be used to decode it using the type attribute. This can further help a browser in deciding whether to download a file - audio and video files are typically large, so browsers really should only download files they can very likely play. For now, just note we have the type attribute, which may be useful, for example, to distinguish between audio files of the same format encoded at different bitrates.
Providing fallbacks
Because we've long been able to embed audio and video in a web page using Flash (or Silverlight, and other audio playing plugin technologies), we can use this to provide a fallback player for audio content. There's two approaches to this (for simplicity, we'll only consider the case of Flash, but a similar approach can be used with Silverlight).
- We use the object element to link to a .swf version of our audio file, which Flash can play
- We use object to embed a Flash audio player which can play mp3 files
The first approach is simplest, but Flash won't display controls for the sound file - the user will have to context menu click to play, rewind, etc.
The second approach potentially involves hosting an audio player at your site, or using a free hosted player such as the Google Reader Audio Player, but has the advantage of reducing the number of audio files we need to encode, and of providing a better user experience.
In both cases, we use the object element, as the only browser we really need to worry about is Internet Explorer versions 8 and older, which support object. Unless you're looking to also cover an old version of a browser that doesn't support object (which to be honest is unlikely), there's no need to also include a nested embed element inside the object.
Here's how we go about using the object element to add the Google Reader player, and our sound file.
<object type="application/x-shockwave-flash" data="http://www.google.com/reader/ui/3523697345-audio-player.swf" width="400" height="27" >
<param name="flashvars" value="audioUrl=http://westciv.com/podcasts/youmayknowmypoetry.mp3">
<param name="src" value="http://www.google.com/reader/ui/3523697345-audio-player.swf"/>
<param name="quality" value="best"/>
</object>There's no great need to go into detail here, because all you really need to know is the value of the flashvars parameter includes the URL of the sound file. Simply replace the URL there, leaving the audioURL= part as is, and you'll be fine.
Note that this fallback won't work if the browser supports audio, but none of the audio formats you've linked to, or if the files go missing. The browser in these instances will show the native audio player controls (if you've used the controls attribute), but no sound will be played.
Lastly, what if we have a browser that supports neither audio, nor the object element? We can include fallback text (and HTML) within the object element (or if we choose not to include a flash based fallback, inside the audio element, after any source elements). We could for example link to a downloadable version of the file. Here's what this would look like if we haven't included a Flash based fallback
<audio controls="controls" loop="loop"> <source src="http://westciv.com/podcasts/youmayknowmypoetry.mp3"> <source src="http://westciv.com/podcasts/youmayknowmypoetry.ogg"> <p>Sadly your browser can't play this audio file</p> <p>The good news is you can still <a href="http://westciv.com/podcasts/youmayknowmypoetry.mp">download an MP3 version</a></p> </audio>
Gotchas
We've covered most of the things that can trip you up with audio (with the exception of the whole issue of formats and codecs which we'll cover shortly) but keep in mind these as well:
- fallbacks only come into play if the audio element is not supported, not if the file formats aren't or if the files are missing.
- ogg files must be served as audio/ogg or application/ogg. If the server is set up to serve these as another MIME type, Firefox will ignore them.
- Fallback text is not for the purposes of accessibility, but as a last resort when audio is not supported (we'll look at accessibility in a moment).
But, on the whole, HTML5 audio is not particularly complicated, and in my opinion far less of a headache than using plugin based audio with the object and embed elements. As I mentioned earlier, I've built a web based tool that helps you create audio elements, including fallbacks, and hopefully helps you understand exactly what's going on. Let me know what you think
HTML5 Video
Let's now turn to incorporating video in HTML5 documents, and the good news is, it's more or less identical to audio. Where audio and video are the same, we won't repeat what we've covered earlier.
Adding the element
In place of the audio element, for video we have, not surprisingly, the video element. As with audio, we recommend you don't use the src attribute to link to the video file, but again the source element, so we can link to different formats (as with audio, different browsers support different formats, so to cover all modern browsers we need at least two different video files).
video elements can take all the attributes of the audio element - controls, loop, autoplay and preload. But in addition, it can also take the poster attribute. The value of the poster is a url that specifies a file to be used as a placeholder image when video is not playing. Here's a video element, with controls, and a poster
<video controls="controls" poster="http://westciv.com/podcasts/lesson6.jpg"> </video>
and while this won't play any video, it will look impressive, something like this

Adding sources
Now we need to specify the video files to be played. As with audio, we use the source element, with the src attribute pointing to the video file to be played. To cover modern browsers, we need at least two formats, to simplify considerably, h.264 and either ogg/theora or webM/VP8.
<video controls="controls" poster="http://westciv.com/podcasts/lesson6.jpg"> <source src="http://westciv.com/podcasts/lesson6.mp4"> <source src="http://westciv.com/podcasts/lesson6.ogv"> </video>
Which now gives us video which will play in almost any modern browser, including IE9. again, we're going to add fallbacks much as we did for audio, to round out our coverage.
Providing fallbacks
The simplest way to add Flash based fallback video content is to create a .swf version of the file, and then embed this in your HTML document using the object element. If Flash is installed this will play in the user's browser, and while no controls will be shown, if you add a menu parameter with the value of true, then the user can context menu click and play, rewind and otherwise control the video.
<object type="application/x-shockwave-flash" data="http://westciv.com/podcasts/lesson6.swf" width="320" height="400">
<param name="movie" value="http://westciv.com/podcasts/lesson6.swf">
<param name="menu" value="true">
</object>All we need to concern ourselves with here is that we put the url of our video file as the value of the parameter with the name "movie", as well as the data attribute of the object element.
There are also various Flash based video players we might include, similarly to the way we included the Google Reader MP3 player. This will likely require serving the Flash application, in addition to the video files.
Again we've used only the object element, as we're really only looking to ensure IE 8 and older is served the video, and as these support object there's no need to also include the embed element.
Lastly, as with audio, we can provide fallback text or HTML to display when video is not supported. Here, we'll provide a download link when neither video nor Flash are supported.
<video controls="controls" poster="http://westciv.com/podcasts/lesson6.jpg">
<source src="http://westciv.com/podcasts/lesson6.mp4">
<source src="http://westciv.com/podcasts/lesson6.ogv">
<object type="application/x-shockwave-flash" data="http://westciv.com/podcasts/lesson6.swf" width="320" height="400">
<param name="movie" value="http://westciv.com/podcasts/lesson6.swf">
<param name="menu" value="true">
<p>Sadly your browser can't play this video file</p>
<p>The good news is you can still <a href="http://westciv.com/podcasts/lesson6.mp4">download an MP4 version</a></p>
</object>
</video>Gotchas
HTML5 video gotchas are similar to those with audio. Fallbacks are only for when video is not supported at all. Ensure video files are served with the right MIME type. But on the whole, both audio and video are quite usable today.
As I've mentioned, the single biggest challenge is ensuring we serve the right video files, to ensure all browsers can play the video. Which means delving a little into the more complex issue of formats and encodings.
Video and Audio formats
Probably I should skip this part, and just point you in the direction of Mark Pilgrim's fantastic coverage at Dive Into HTML5. But, I feel I should at least cover this issue briefly, so here goes.
When we think of video formats, like h.264, there are in fact 2 and usually 3 separate pieces of technology involved.
- There's the container file - for example MPEG4, WebM or Ogg
- There's the video data, encoded with one of many possible codecs (decoding/encoding formats) such as H.264, VP8 or Theora
- There's audio data encoded with one of many possible audio codecs such as mp3, AAC or Vorbis
So, when we talk about the video format a browser supports, it's important to understand what this actually means. It means the combination of container, video and audio encoding.
With this in mind, The current state of browser support for audio and video formats is
Video
- Firefox 3.6+, Chrome, Android 2.1+ and Opera support Ogg/Theora (.ogv).
- IE9, Safari 4+, Chrome, Android and iOS support MPEG4/h.264 (.mp4), although Chrome 14 will drop support for the format.
- Firefox 4+, Chrome, Opera, and Android (2.3+) support WebM/VP8 (.webm), as does IE9 if the required codecs are installed on the system (they can be downloaded from here)
So, to cover all modern browsers, we need at a minimum, MPEG4/h.264 and either Ogg/Theora or WebM/VP8
Audio
- Firefox, Chrome, Android and Opera support Ogg/Vorbis (.ogg).
- IE9, Safari, Chrome, Android and iOS support MP3 (.mp3).
- Safari, Chrome, IE and iOS support AAC (.aac).
To cover all modern browsers, we need Ogg/Vorbis and either MP3 or AAC.
The type attribute
We mentioned earlier that the source element can take a type attribute in addition to the src attribute. While not required, this can help a browser decide whether it can actually play the content located at the end of the src URL. You might think that the file extension would be enough, but not necessarily so. For example, iPhone with iOS 4 supports H.264 video up to 720p (the so called H.264 "Main Profile"), so can't play a 1020p H.264 encoded video (that is, a "High Profile" H.264 video). If we wanted to provide various H.264 profiles, for various devices, all these files will have the extension mp4. But we can provide codec information in the type attribute to differentiate between the various versions.
The type attribute's value provides two pieces of information, separated by a semicolon. First is the MIME type of the file, then (optionally) the codecs used (separated by a comma). So, for example we could provide various H.264 profiles of our video like so:
<source src='video.mp4' type='video/mp4; codecs="avc1.58A01E, mp4a.40.2"'> <!-baseline profile--> <source src='video.mp4' type='video/mp4; codecs="avc1.4D401E, mp4a.40.2"'> <!-main profile--> <source src='video.mp4' type='video/mp4; codecs="avc1.64001E, mp4a.40.2"'> <!-high profile-->
(Which to tell the truth is taken directly from the HTML5 specification, and is beyond my level of understanding of the ins and outs of codecs.), but depending on your circumstances, you may find it useful to include MIME type and codecs information using the type attribute. If you do, I'm sure you'll know the codecs information to use, and now where to put it.
Accessibility
The web is about inclusivity and access to as wide an audience as possible, which includes those with hearing and visual disabilities. Creating accessible audio and video content is far beyond the scope of this article, but I do have some links for further reading below. But, it is important to note that, as spelt out in the HTML5 specification
In particular, [fallback] content is not intended to address accessibility concerns. To make video content accessible to the blind, deaf, and those with other physical or cognitive disabilities, authors are expected to provide alternative media streams and/or to embed accessibility aids (such as caption or subtitle tracks, audio description tracks, or sign-language overlays) into their media streams.
The tools
I'm not sure whether it's stupidity, or laziness, but many aspects of web development, if I've not used a particular technology for a while, I quickly find myself reaching for a reference. And sadder still, it's often the book I wrote myself! But in all seriousness, as aspects of CSS and HTML (not to mention JavaScript and the DOM) become increasingly complex, our chances of remembering every aspect of our craft, along with the subtleties of browser support, grow ever smaller (even Einstein was reputed to have said that he didn't remember the speed of light as he could always look it up). Well, mine certainly do. So, I write little web based tools to replace my dwindling brain cells.
I've recently developed two new tools, one each for audio and video, that help you easily do pretty much all we've covered here - create the elements, add controls, a poster, and other attributes, sources, and fallback audio, video and HTML. It will even tell you which browsers can play a particular file (well, it will make a guess based on the files' extensions).
You can find the audio tool here, and the video tool here.
There's also a similar excellent tool for creating HTML5 video which I wasn't aware of when creating mine, the Video for Everybody Generator. It's highly recommended.
Further reading
Here's a few of the many articles and other resources on HTML5 video and audio I've come across in my travels. They cover video and audio encoding, accessibility, some Flash players you might consider for your fallback content, browser support, and more.
The very best place to start is the video chapter in Mark Pilgrim's Dive into HTML5. Video for Everybody, the originator of the Flash fallback technique for HTML5 Video
Opera Developer Connection has a series of articles on HTML5 media, including an Introduction to HTML5 Video, and Everything you need to know about HTML5 audio and video.
The HTML5 Doctor has a detailed overview of HTML5 Audio, and video.
HTML5 Rocks has several various articles on native HTML5 media including a quick guide to audio, the basics of HTML5 video
Encoding your audio and video
Here are some great places to get tips and techniques on encoding video and audio for HTML5, and services which you can use to create the right formats of your media files
- Encoding.com has free and paid encoding services for many audio and video formats
- Here's a detailed list of various encoding services
- ZenCoder is another hosted encoding service, with free service for testing, and various pricing options
- Vid.ly is a service for encoding and hosting video
Flash players for video and audio fallback
There are some open source Flash video players you can host yourself to play your video files.
- FlowPlayer
- JW Player
- Media.js supports both audio and video with fallbacks to Flash
- VideoJS is a highly regarded JavaScript HTML5 player, with fallback support as well. You can skin it with CSS.
- JPlayer open source jQuery HTML5 Audio / Video Library (as used in Pandora)
In addition to the commonly used Google Reader Flash MP3 Player, other Flash MP3 players you might consider include
- The innovatively named MP3 Player
- And equally so Free Flash MP3 Player
Accessibility
- Captioning HTML5 Video using JavaScript from the Opera Developer Center
- Creating Accessible HTML5 YouTube Video
Browser support
As always When Can I Use? is the place to keep up to date with browser support.
Addressing challenges playing audio and video in the Android browser.
A look at the challenges associated with video on the iPad.
A further look at HTML5 media challenges in iOS.
" ["post_title"]=> string(46) "Getting Sourcey - native HTML5 Audio and video" ["post_category"]=> string(1) "0" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(44) "getting-sourcey-native-html5-audio-and-video" ["to_ping"]=> string(0) "" ["pinged"]=> string(342) "http://www.broken-links.com/2010/07/08/making-html5-video-work-on-android-phones http://blog.millermedeiros.com/2011/03/html5-video-issues-on-the-ipad-and-how-to-solve-them/ http://blog.millermedeiros.com/2011/04/unsolved-html5-video-issues-on-ios/ http://html5doctor.com/the-video-element/ http://html5doctor.com/native-audio-in-the-browser/" ["post_modified"]=> string(19) "2011-08-07 14:35:41" ["post_modified_gmt"]=> string(19) "2011-08-07 04:35:41" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=3536" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(1) "9" ["filter"]=> string(3) "raw" } [13]=> object(stdClass)#129 (25) { ["ID"]=> int(3506) ["post_author"]=> string(1) "3" ["post_date"]=> string(19) "2011-07-19 07:46:28" ["post_date_gmt"]=> string(19) "2011-07-18 21:46:28" ["post_content"]=> string(25649) "Getting your head around CSS3 radial gradients
We recently took a detailed look at linear gradients in CSS3. If you've not read that, you might like to spend a few minutes doing so, as the concepts are very similar, and I don't spend quite as much time in this article on the fundamentals of gradients which I've already covered there.
This time we'll look in detail at radial gradients. If you've got a good sense of how linear gradients work, radial gradients should present no great difficulty. And, I'll again introduce an updated tool for creating radial gradients, which supports the current syntax, and works across all modern browsers which support radial gradients (more on which they are shortly).
A brief history
Like linear gradients, radial gradients were first introduced in Webkit in 2008. Like linear gradients, they are still in a draft CSS3 specification, and indeed are still in something of a state of flux, so it is more than possible the final specified version will be different from that described here. As with linear gradients, radial gradients as originally proposed by Apple's Webkit team had a different syntax, and quite significantly different conceptual basis from how they are currently specified, and from how they are supported in current browsers. With Safari 5.1, all modern browsers have harmonized on the same syntax, and conceptual basis for radial gradients, which is what we cover here. Safari 4, and Chrome 10 and up support a very different syntax, and model for radial gradients, which is effectively obsolete, and which we won't cover here.
What exactly is a radial gradient?
I've thought long and hard about whether to try and explain what is really going on with a radial gradient (and for most folks, simply playing around with them is likely the best way to really come to grips with them). But, as I've yet to see a very good description of exactly how radial gradients work, here's my attempt.
You'll hopefully remember that linear gradients have a straight gradient line, from one edge of the element's background box. It could be vertically from top to bottom, or bottom to top. It could be horizontally from left to right, or right to left. Or it could be at an angle, from left to right, right to left, upwards or downwards.

Some common linear gradient lines
We then specify two (or more) colors to create the gradient along this line. The gradient "smoothly fades" from one color to the next along the gradient line. So, what exactly does "smoothly fades" mean? To get all technical on you, the Image Values and Replaced Content module of CSS3 says "between two color-stops, the line's color is linearly interpolated between the colors of the two color-stops, with the interpolation taking place in premultiplied RGBA space". Glad you asked? And if you really want to get down and dirty with linear interpolation, the spec has a whole section on it.
Radial gradients also specify a gradient line, but this time, the line goes from the center of an ellipse, outwards in each direction to the edge of the ellipse. Along this line color also "fades smoothly" from one color stop to the next.
We also know from linear gradients, that the gradient can have intermediate stops between the starting and final color. Not surprisingly, radial gradients can have color stops, specified as being a certain percentage, or length value, along the gradient, between the start and final colors.
But where radial gradients differ significantly from linear ones, is the shape and size of the gradient, as well as a gradient's location.
In essence, to specify a radial gradient, we give the gradient
- a location
- a shape
- a size
- one or more color stops
Let's look at each of these, though slightly out of order, because to understand how they all work, we need to understand a little bit about what an ellipse is (this won't hurt a bit I promise).
Ellipses

An Ellipse, showing the major and minor radii.
An ellipse is what we more colloquially call an oval. It differs from a circle in that its width and height are different from one another (strictly speaking, a circle is a kind of ellipse where the width and height are equal).

As you can see here, a circle is a special kind of ellipse where these two lines are the same length.
If you drop a vertical line through an ellipse at its tallest point, and a horizontal line through it at its widest, where these two intersect is the center of the ellipse. The longer of these two lines is called the major semi-axis or major radius, and the shorter the minor semi-axis or minor radius.
From all this, the key concepts to take away are
- What the center of an ellipse is
- What the radii of an ellipse are
Radial gradient location
We give a radial gradient a location by specifying where its center will be in relation to the element it is a background image for (we'll leave aside the case where the gradient is used elsewhere for now).
We can specify the location of the ellipse's center essentially the same way we specify the location of a background image with the background-position CSS property. We specify the horizontal position of the background, and optionally the vertical position using either keywords (left, center right, or top, center, bottom), length values, percentage values, or some combination of these. For example we might have
- left bottom
- left 100%
- 0% bottom
- 0% 100%
Which all specify that the center of the gradient ellipse should be in the left bottom corner of the element background.
Where the second value is omitted, it is treated as center (similarly, if we omit the first value as well, the center of the gradient ellipse is in the center of the element's background.)
So, let's start putting together a radial gradient. As we saw with linear gradients, a gradient is not a CSS property. Rather it is a value, that can in theory be used anywhere an image would be used, but in practice, typically only as a background image on an element. Here we'll start a radial gradient as the background image of an element, and give it a location. We'll place the gradient in the center of the element's background.
background-image: radial-gradient(50% 50%,
Notice how the horizontal and vertical center values are simply separated by a space, and then pair is then followed by a comma. Note too that this is not yet a gradient, just the start of one. We still need to specify the shape and size, plus its color values.
Radial Gradient shapes and sizes
Now we've specified the location of the center of the gradient, we need to specify the shape and size of the ellipse. These can be specified in one of two ways, implicitly, or explicitly.
Explicit shapes and sizes
We explicitly specify the shape and size of the ellipse for our radial gradient by specifying the lengths of the major and minor radius, using a length or percentage value. (as of July 2011, this aspect of radial gradients was not supported by any browser, so we'll only cover this briefly).
For example, we might specify a width of the gradient ellipse as being 50% of the width of the background element and 30% of the height of the element with the values25% 15% (note that these values specify the radius, which is half the width or height). If we specify identical values for width and height, then the two radii are the same length, and so we get a circular gradient. Here's what our gradient would look like with this explicitly declared width and height
background-image: radial-gradient(50% 50%, 25% 15%,
Notice again, the width and height values are separated only by a space, and then we follow these by a comma.
Implicit shapes and sizes
Alternatively, instead of specifying an explicit width and height to give us the size and shape of our gradient, we can specify the size and shape implicitly with keywords. In practice, this is the only one of the two forms that is supported in contemporary browsers, and so is the one you should use.
Shape
This part is very straightforward, we just use one of two keywords ellipse or circle, to specify the shape of the gradient. So, we create an elliptical shape for our gradient like so
background-image: radial-gradient(50% 50%, ellipse
Now it's time to give the gradient a size.
Size
If we are declaring the size of the gradient implicitly, we specify the size of the gradient shape using one of several keywords. Each of these keywords specifies an algorithm for giving the gradient a size. These algorithms are sometimes slightly different for ellipses and circles. While they may initially seem quite complicated, they make sense once you understand the key principle of each. Here's my way of understanding what is going on with each keyword.
| Keyword | For Circular gradients | For Elliptical Gradients |
|---|---|---|
| closest-side |
with |
with |
| closest-corner |
with |
with |
| farthest-side |
with |
with |
| farthest-corner |
with |
with |
There are two additional keywords, contain and cover. The keyword contain is the same as closest-side, while the keyword cover is the same as farthest-corner.
Here we'll give our gradient a size of closest-corner.
background-image: radial-gradient(50% 50%, ellipse closest-corner,
As with the location of the center of the gradient, the two keyword values are separated by space, then followed by a commas
Color Stops
Now we've established the size, shape and location of the gradient, all that remains is for us to specify two or more color stops. As with linear gradients, we specify a color stop with a color, and an optional stop position, which is a length or percentage value. The simplest case is color values alone.
When color stops are specified with color values only, the stops divide the size of the gradient evenly. So, if there are 3 color stops, each color covers a third of the gradient shape, and fades into its adjacent color stop(s).
Let's take a look at an example. Here's a simple circular gradient. It's implicitly sized to touch the closest size to its center, and has three color stops, red, green and blue
background-image: radial-gradient(center center, circle closest-side, #ff0000, #00ff00, #0000ff )
Notice how each stop is separated by a comma.
And here's what it this will look like in a browser which supports radial gradients.
If we add more stops, these are simply evenly spaced in the same size, as here, where we have 6 color stops, evenly spaced across the size of the gradient.
background-image: radial-gradient(center center, circle closest-side, #ff0000 ,#ff9f40 ,#fff81f ,#050a99 ,#0b990f ,#911c99 ,#d24fe0 )

Color stops can, as we mentioned, optionally also specify a length or percentage value. So, we can make color stops a specific distance apart from one another, like so:

background-image: radial-gradient(center center, circle closest-side, #ff0000 25%, #19ff30 90%, #2f3ced 100%)
Notice again, the color and position of each stop is separated by a space, and again each stop is separated by a comma.
It's also possible to use length values, like px and em in place of percentages, and to mix all three forms of color stop (color alone, percentage and lengths). Keep in mind that percentage gradients will adapt to the size of the element, so that when it grows or shrinks in size the gradient remains in proportion to the element's size, and so in many cases, percentage gradient stops (or simple color stops specified only by color) are likely to be the most adaptable choice.
Coloring inside and outside the gradient
You might have noticed that in our examples, outside the gradient shape is a solid color background, the color being that of the last color stop specified. Once the gradient completes, whatever the finishing color is will then fill the remainder of the element's background.
In this last example, you might also have noticed the same thing happens inside the gradient shape. Our first color stop is at 25%, so from the center of the gradient to 25% of its width, we have a solid red color. The red only fades smoothly into the next color stop, green, from 25% out from the gradient shape's center.
Stop positions can in fact be greater than 100% of the size of the gradient, so we can fill the entire element with a gradient by specifying a final stop position large enough that the entire element is covered by the gradient.
Repeating gradients
As with linear gradients, radial gradients can repeat. This we specify with a slightly different value name - repeating-radial-gradient. If we take our previous gradient, and repeat it, here's what we get

background-image: repeating-radial-gradient(center center, circle closest-side, #ff0000 25%, #19ff30 90%, #2f3ced 100%)
Where we would have solid color outside the gradient shape, we now have the gradient repeating. If we reduce the size of the gradient, the effect becomes more pronounced. In this example, we reduce the size of the gradient shape, to get the following non-repeating gradient.

background-image: radial-gradient(center center, circle closest-side, #ff0000 0%,#19ff30 29%)
Now if we repeat the gradient, the effect is far more noticeable.

background-image: repeating-radial-gradient(center center, circle closest-side, #ff0000 0%,#19ff30 29%)
Doing the heavy lifting for you
Shapes, sizes, centers, radii, stops... If it all sounds like a lot to learn and remember, then again we're here to help. As we've done for linear gradients, we've built a radial gradient tool, which helps you build gradients, without having to remember all the heavy lifting.
As with our linear gradient tool, in addition to just helping you create radial gradient, it has some other features.
- You can tweet a link to a gradient you’ve created by simply clicking a button
- You can copy the url of your gradient, and send it to someone via email, put it in a link (like I’ve done for many of these examples) or otherwise share it
- Via the magic of HTML5 localStorage, it remembers your most recent gradient, and other settings next time you visit
- It adds vendor prefixes for all modern browsers (as an option)
- It adds the start color as a background color for older browsers
- There’s a related tool for creating old-style Webkit gradients
- It provides up to the minute browser compatibility information (provided I remember to update that as browsers change)
- It looks really pretty, all thanks to CSS gradients of course
So give it a try, and let us know what you think.
Browser Compatibility
Despite being relatively new, and as yet not completely specified, radial gradients are safe to use in a way that is backwards compatible, and are in fact quite widely supported (we'll take a look at which browsers support them in a moment).
To ensure compatibility and accessibility when using radial gradients, as with linear gradients, it's important to
- include vendor specific prefixes (-o-, -ms-, -moz, -webkit-), as well as the standard form of gradient values
- include a background color for browsers which don't support gradients. Make sure the text of an element with a gradient background has sufficient contrast with the element's background color
Browser support
A quick summary of current browser support for CSS Radial Gradients (based on the information at the fantastic When Can I Use).
- Safari 4 introduced radial gradients, though as noted with a different syntax from that detailed here. The vendor prefix -webkit- is required for gradients in Safari 4.1 and newer.
- Safari 5.1 introduces the syntax detailed here, as well as continuing to support the older style syntax. Again, the -webkit- vendor prefix is required.
- Firefox 3.6 was the first browser to support the current gradient syntax. The -moz- prefix is required, and it's currently only supported on backgrounds.
- Chrome 10 and up (and probably earlier versions) supported the syntax for gradients detailed here. The -webkit- prefix is required.
- Opera 11.1 introduced linear gradient support, but at present does not support radial gradients of any kind
- Internet Explorer 10 also features CSS radial gradients, using the prefix -ms-, and also only on backgrounds.
Gradients can be computationally intensive, and may cause browsers running on older hardware difficulty. At present they are not able to be animated with CSS transitions in any browser which supports transitions.
Links, galleries, articles and more
Here are some places to go to learn more.
- Lea Verou has some great presentations on Gradients, including one at our recent @media conference, which you can watch the slides of and listen to
- Lea has also put together a CSS pattern gallery, showcasing some amazing designs using CSS gradients
- Estelle Weyl also has a great gallery of gradient patterns
- Detailed support information for CSS gradients, and many other modern HTML5, CSS3 and DOM features is available at When Can I Use?
The wrap
I hope this article has been helpful in understanding a little more deeply what is really going on with radial gradients, and hope the radial gradient tool makes working with them enjoyable. Let me know if you've found them helpful on twitter!
" ["post_title"]=> string(21) "CSS3 Radial Gradients" ["post_category"]=> string(1) "0" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(21) "css3-radial-gradients" ["to_ping"]=> string(0) "" ["pinged"]=> string(131) "http://www.webdirections.org/blog/css3-linear-gradients/ http://www.webdirections.org/resources/lea-verou-mastering-css3-gradients/" ["post_modified"]=> string(19) "2011-08-07 14:35:48" ["post_modified_gmt"]=> string(19) "2011-08-07 04:35:48" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=3506" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(2) "27" ["filter"]=> string(3) "raw" } [14]=> object(stdClass)#130 (25) { ["ID"]=> int(3475) ["post_author"]=> string(1) "3" ["post_date"]=> string(19) "2011-07-11 21:05:05" ["post_date_gmt"]=> string(19) "2011-07-11 11:05:05" ["post_content"]=> string(23748) "Taking your web sites and apps offline with the HTML5 appcache
There's a general (and understandable) belief by even many developers that web sites and web applications can only be used when the browser has a web connection. Indeed, this is routinely cited as one of the real advantages of "native" apps over web apps. But as unintuitive as it sounds, in almost every modern browser and device (except even for now IE10 developer previews, but here's hoping that changes), that's not the case, provided the developer does a little extra work to make their app or site persist when a browser is offline. (Of course the user must have visited your site while their browser did have a connection)
In this article, I hope to clear this whole areas up once and for all, show you how to do it, and point to some great resources out there for learning more about creating offline versions of your web sites and apps. Perhaps most importantly, introduce a simple new tool I've built to do the heavy lifting for you, ManifestR.
Even if you develop web sites, rather than applications, you can benefit from the techniques outlined here, because caching resources can seriously decrease the load time for your site, particularly on a visitors subsequent site visits.
Making a cache
As I'm sure you know, browsers cache HTML, CSS, JavaScript files, images and other resources of the sites you visit, to speed up the subsequent loading of pages. However, you never know when the browser might discard cached files, and so this is not a reliable way for sites to work offline. But what if we could tell the browser what to cache? Well, with HTML5 application caches (also known as applications caches or "appcaches") we can do just that. Let's look at how.
Making it manifest
The heart of the technique is to create an appcache manifest, a simple text file, which tells the browser what to cache (and also what not to). The resources are then cached in an "application cache", or "appcache", which is distinct from the cache a browser uses for its own purposes. The anatomy of an appcache manifest is straightforward, but there are a few subtleties.
An appcache manifest
- begins with the string "CACHE MANIFEST" (this is required)
- has a section, introduced by the string "CACHE:" which specifies the URLs of resources (either absolute, or relative to the location where the manifest file will be located on the server) to be cached.
- We can also optionally specify which resources should not be cached, in a section of the manifest file introduced by the string "NETWORK:". These resources aren't just not cached, but further, won't be used when the user is offline, even if the browser has cached them in its own caches.
- We can also optionally specify fallback resources to be used when the user is not connected, in a section of the file called "FALLBACK:"
- You can add comments to the file with, simply by beginning a line with "#"
It's recommended that the extension for a manifest file is .appcache (previously, .manifest was the recommended extension).
Here is a very straightforward example
CACHE MANIFEST CACHE: #images /images/image1.png /images/image2.png #pages /pages/page1.html /pages/page2.html #CSS /style/style.css #scripts /js/script.js FALLBACK: / /offline.html NETWORK: signup.html
The CACHE section
In the CACHE section we list the resources we want cached. We can use either a URL relative to the .appcache file, or an absolute URL. We can cache resources both in the same domain as the cache, as well as (in most cases) other domains (we'll cover this in more detail in a moment)
Often, the only section of an appcache manifest is this section, in which case, the CACHE: header may be omitted.
Be careful with what you cache. Once a resource, for example an HTML document is cached, the browser will continue to use this cached version, effectively forever, even if you change the file on the server. To ensure the browser updates the cache, you need to change the .appcache file. This can play havoc while you are developing a site, and we'll cover some techniques for managing this in a moment.
One suggestion is to add a version, and or a date stamp to the manifest as a comment. This way, you can quickly change the date or version number, and then browsers will refresh the appcache. Browsers do this intelligently, checking to see which resources might have changed since they were last cached, and only re-caching those which have.
The Network Section
Probably the most subtle aspect of app caching is the NETWORK section. Because a great many web sites, and particularly applications, have dynamically generated content, pulled in from APIs, CGIs and so on, we may want to ensure certain resources aren't cached, and are always directly loaded when the browser is online.
That's where the NETWORK section of the cache comes in. Here, we list the resources we never want to be cached, which is referred to as an "online whitelist". So, in our example above, we are specifying that the page signup.html (located at the root of our site - remember the entries in our manifest are either absolute or relative URLs) is never cached. When online, any request for this page will always cause the page to be loaded from the server (even if the browser might have previously cached it itself). When the user is offline, any request for this resource resuls in an error (again, even if the browser might have cached the resource in its own caches).
We can also specify a group of resources located within a site in the NETWORK section using a partial URL (technically a "prefix match pattern") (note that we can't use this technique in the CACHE section, where all resources must be explicitly listed to be cached in the appcache, with one exception we'll get to shortly). Any resources which have URLs beginning with this pattern are included in the online whitelist, and never cached. As developers we then need to handle the cases where these resources aren't available because the user is offline.
There's also a special wildcard, *. The asterisk specifies that any resources that aren't explicitly cached in the appcache manifest should not be cached.
Fallbacks
App caching also allow us to specify fallback resources. The form of an entry in the FALLBACK section is two resource identification patterns. The first (in the case above simply "/", which matches any resource in the site), specifies resources to be replaced with a fallback when the user is offline. The second specifies the resource to replace any resources matching the patter. So, in this case, when any resource in the site has not been cached, and the user is offline, the page offline.html will be used instead. We can also specify resources to be replaced more specifically. For example, we could specify an offline image for any images that haven't been loaded like so
/images/ /images/missing.png
Here we're specifying that any resources located in the directory images at the top level of our site that have not been cached, be replaced with the image called missing.png found in that same directory, when we are offline.
Using the appcache manifest
So now we've created our appcache manifest, we need to associate it with our HTML documents. We do this by adding the manifest attribute to the html element of a document, where the value of this attribute is the URL of the appcache file.
The current recommendation is the appcache file have the extension .appcache. So, if our manifest is located at the root of our site, we'd link to it like so
<html manifest='manifest.appcache'>
There are also suggestions that using the HTML5 doctype may be required for some browsers to use app cache, so, make sure you use the doctype
<!DOCTYPE html>
And we're all set. Well, almost. In order for the browser to recognize the appcache file, it needs to be served with the mimetype text/cache-manifest. How you set this up depends on your site's server. At the time of writing, it's likely that this is a step you'll need to take, so if caching isn't working, that's very likely why. One of the most common servers is Apache. There are two ways in which you can set up Apache to serve .appchace files as type text/cache-manifest. At the root directory of your site, add a file with the name .htaccess, with the entry AddType text/cache-manifest .appcache (if there's already a .htaccess file, just add this line to it).
Gotchas
App caching can be very powerful, allowing apps to work while the user is offline, and can increase site performance, but there are some definite gotchas it pays to be aware of. Here's a few well worth knowing about.
Resources in style sheets
You'd be forgiven for thinking that any images in a style sheet that has been cached will be included in the appcache, but that's not so. Images your style sheet refers to must be explicitly referenced in the CACHE section of the manifest as well.
Similarly, style sheets that are imported using @import, and resources included via JavaScript must also be explicitly cached.
To help build an appcache manifest, I've developed manifestR, which we'll look at in detail in a moment. It will generate an appcache manifest for you, which includes all the scripts, style sheets, including those @imported, images, linked pages at the same site, and any images linked to in stylesheets.
There's one exception to the rule that only explicitly listed resources are cached, and it is important to understand. Any HTML document that has a manifest attribute will be cached, even if it is not listed in the manifest. This can cause all kinds of headaches while developing, which we cover shortly.
Caching Cross Domain Resources
While there is some confusion on the issue, you can in general cache content from across different domains in an app cache. In fact, without this ability, the real world value of app caching would be limited, as content distributed via a CDN (content distribution networks like Akamai) could not be cached (even content served from a differently named server within the same domain couldn't be cached). The exception to this is that when content is served over secure http (https), then the specification says all resources must come from the same origin. In an exception to this exception, Chrome in fact does not adhere to this part of the specification, and it has been argued that the single origin policy for https is too restrictive in the real world for app caching to be of genuine value.
Refreshing the cache
In effect, unlike most caching of web resources, appcaches do not expire. So, once the browser has cached a particular resource, it will continue to use that cached version, even if you change the resource on the server (for example by editing the contents of an HTML document). The exception to this is when a manifest file is edited. When the manifest is changed, the browser will recache all the resources listed in the manifest.
Caching can cause real headaches while developing a site or application, so it is recommended that during development, you avoid appcaching. One way of achieving this is to serve .appcache files with the wrong mimetype. This way, you can include the manifest attribute in your HTML elements, and serve the appcache file, just as you wold in production, but not have the effects of appcaching. Moving from development to production is as simple then as associating .appcache files with the right mimetype.
Resource hogging and lazy loading
To improve the performance of a site, you might be tempted to preload the entire site, by adding all the pages, images etc in it to the appcache manifest. And, in certain circumstances this might be desirable. It will however place considerable demands on your server, and use more bandwidth, as the first time a person visits your site, they will download more resources than they otherwise might have. Luckily, appcaches have an additional feature that can help here.
You might recall earlier that even when an HTML document with a link to an appcache manifest isn't included in the manifest file, it will still be cached. The benefit of this is that rather than explicitly listing all the pages at your site in a manifest for them to be cached, each time someone visits a page that links to a manifest, it will then be cached.
If the primary motivation for using an appcache is to ensure your site or more likely app works offline, you'll likely want to explicitly list the pages of the site, so that they'll be available offline even if the user hasn't visited them. If your primary motivation is increased performance, then let pages lazily cache when the user visits them, but cache scripts, CSS, and perhaps commonly used images.
Cache failure
An important, but subtle gotcha with appcaching is that if even one of the resources you include in your cache manifest is not available, then no resources will be cached. So, it is really important to ensure that any resource listed in your appcache manifest is available online. There's a tool we discuss in a moment, the Cache Manifest Validator, to help ensure all those resources are online.
Size limits
While there specification places no limits on the size an appcache can be, different browsers, and different devices have different limits. Grinning Gecko reports that:
- Safari desktop browser (Mac and Windows) have no limit
- Mobile Safari has a 10MB limit
- Chrome has a 5MB limit
- Android browser has no limit to appcache size
- Firefox desktop has unlimited appcache size
- Opera's appcache limit can be managed by the user, but has a default size of 50MB
User Permission
In Firefox, when the user first visits an appcached site, the browser asks the user's permission (as it and other browsers do for location with the geo-location API). However, unlike with geo, other browsers don't ask the user's permission. Just something to be aware of, as there'll be no guarantee with Firefox that appcaching is being used, even when supported.
Flakiness and browser support
It must also be noted that the general consensus is that appcaching is currently far from perfect across all browsers which support it. The specification is still in draft, but it should also be noted that most browsers have supported at least some appcaching for quite some time.
According to an amalgam of When can I use, Dive into HTML5 and other online resources:
- Safari has supported offline web apps since version 4
- Chrome has supported the feature since version 5
- Mobile Safari has supported offline apps since iOS 2.1
- Firefox has supported it since version 3.5
- Opera has supported appcache since version 11
- Internet Explorer as yet does not support offline web apps, including in IE10 developer previews
- Android has support appcache since version 2.1
Introducing ManifestR
We've already mentioned that a particular challenge in creating an appcache is identifying all the resources you need to add to the manifest. To help you with this, I've developed ManifestR, an online tool to help you create an appcache manifest for any page. I don't recommend you use it without at least a little additional fine tuning, as what it attempts to do is locate any resources referenced from a given page. As discussed above, depending on the purpose of your appcache, this is likely to be overkill.
Drag me to your bookmarks bar.
When you use ManifestR on a page, here's what it looks for
- images both in the same and other domains referenced in the
srcattribute of anyimgelement in the page. - links to pages in the same domain. This can improve the performance of your site for visitors viewing other pages, and is vital if you want the entire site/app to work offline, but means potentially considerable additional load on your server the first time someone visits the site. Whether you choose to keep this list, or remove some or all of the links is an important decision to make.
- style sheets, linked, or included via @import statements, located both in your domain, or other domains
- images linked to in any style sheet, both those in the same domain, or other domains
- JavaScript files, both those in the same domain, and served from other domains. Here too, you'll need to consider carefully which to include and which you want to add to the online whitelist via the NETWORK section of the manifest.
it then puts them all together in a manifest, ready for you to cut and paste, tweak, save and upload.
I hope you find it useful in building appcache manifests (and make sure you let me know via twitter what you think, and how we can improve it).
More reading
There's quite a bit available online about app caching, though keep in mind the specification, and implementations are still somewhat in a state of flux. Here's some articles and other online resources I have found very helpful -
Overviews and specifications
- Not the the faint-hearted, here's the latest draft specification on offline browsing, and specifically appcache manifests. These specifications are written for browser developers, and you should hopefully not need to delve into them.
- Apcache facts features facts and details of the workings of the cache, with details on gotchas, and best practices
- The Offline section of the fantastic HTML5 Rocks site has details on appcaching.
- Safari, and the webkit browser engine have supported offline appcaching for some time, and Apple has details here.
- The detailed online book on all thing HTML5, Dive into HTML5, has an indepth chapter on offline apps, and appcaching.
- Mozilla has supported offline apps since version 3 of Firefox, with fuller support since 3.5. The Mozilla Developer Network has details here.
- A detailed look at caching, including appcaching from Platformability
Tutorials and how-tos
- The ever excellent HTML5 Doctors' tutorial
- A from the basics tutorial on appcache from HTML5 Rocks
- Another excellent introductory tutorial from SitePoint
- Standardists Estelle Weyl's take on offline web apps
- More fromthe folks at Mozilla on building offline web apps
- Opera Developers Network on building offline web apps.
Critiques and gotchas
as we know, all is not yet perfect in the world of the offline web just yet. Here are a couple of critiques of the current, and collections of gotchas discovered by offline pioneers.
- http guru Mark Nottingham on what's right, and wrong with "one confused puppy"
- Tips and gotchas from app developer Bunny Hero
- A few things to know, love and hate about applicationCache
- How offline web apps should work from Mike Kelly
- Mark Christian, one of the authors of AppCache Facts outlines some things he sees could be improved with HTML5 AppCaching
- The limits do various browsers and devices have on appcache size, from grinning gecko.
Tools
We've already mentioned ManifestR, but you should find the The Cache Manifest Validator another really useful tool. Remember, for appcaching to work, every resource you list in your manifest must be available, or nothing will be cached. The Cache Manifest Validator can make sure all your resources are available.
Compatibility
Probably the best place to keep up to date with the ever changing field of HTML, CSS3 and other new web technology support in all modern browsers is When Can I Use?. You can find a snapshot of current browser support above.
" ["post_title"]=> string(13) "Get off(line)" ["post_category"]=> string(1) "0" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(11) "get-offline" ["to_ping"]=> string(0) "" ["pinged"]=> string(146) "http://www.standardista.com/html5/offline-applications-application-cache-manifest-files http://hacks.mozilla.org/2010/01/offline-web-applications/" ["post_modified"]=> string(19) "2011-08-07 14:35:54" ["post_modified_gmt"]=> string(19) "2011-08-07 04:35:54" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=3475" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(2) "30" ["filter"]=> string(3) "raw" } } ["post"]=> object(stdClass)#116 (25) { ["ID"]=> int(3906) ["post_author"]=> string(1) "3" ["post_date"]=> string(19) "2011-11-10 07:22:28" ["post_date_gmt"]=> string(19) "2011-11-09 21:22:28" ["post_content"]=> string(3663) "It's often argued (well, asserted might be a better way of putting it) that standards are an anathema to innovation, or at the very least a significant impediment to it.At its most extreme, this is used as an argument for disbanding the W3C, and even for core web technologies to become "a single source repository [with] a good owner to drive it."Occasionally history throws up curiously timely experiments. Right now we are seeing a very interesting one (and one with far reaching consequences) play out.Since the middle to late 18th Century, with the enclosure of the commons, and the rise of industrial capitalism, the belief that ownership and property rights is what has largely driven advancements in our civilisation has become almost all pervasive. It lies at the heart of the, until relatively recently alien, concept of intellectual property (increasingly seen as a bane not boon for innovation).So, what does this have to do with the clear demise of Flash on mobile? Flash has an owner. One that had, and continues to have large revenues, teams of very smart people, deep pockets.Despite all this, Flash failed to adapt to changing technological circumstances, and withered on the vine.In parallel, core web technologies have slowly, inexorably grown more sophisticated, organically, iteratively, cooperatively adding capabilities that, for the most part developers clearly want and need.Let's take an example I used in a recent presentation. The DOM, while powerful, has long been a pain for developers to really get to grips with. Recognizing this, various libraries, and most famously jQuery, came up with more developer friendly ways of accessing it. jQuery's use of CSS selector concepts proved immediately popular, and in short order, the W3C began work on the Selectors API, while browsers also within a relatively short time frame began implementing this API.An ownership model is different. The owner of a platform or technology makes strategic decisions, and long term bets on what will be successful. Those bets may of course pay off tremendously (as in the case of iOS). But they may not, and very often do not, as in the case of Flash.Standards bodies are not imune to the ownership model of development. XHTML2 is a decade long demonstration of that.Technologies with the ownership model seem less capable of adapting to change, and are very dependent on initial conditions. The cooperative, collaborative standards based approach (characterised best by the IETF's founding principle of "rough consensus and working code") often seems to build technologies that weather the storms of technological, social and political change far better.It's ironic, that the apparently "capitalist" "ownership" model is really much more like the central planned economic model of former socialist countries, while the W3 model more closely approximates how the societies of economically liberal countries work.Neither model is going away soon. Each will have its successes and its failures. But I think it is time to put to bed the far too pervasive meme that standards are in some way an impediment to innovation. After all, take a look at the web. Built on standards (TCP/IP, http, HTML, CSS, EMCMAScript, the DOM), it's doing ok. Better than OK I'd suggest." ["post_title"]=> string(53) "Standards, innovation, Flash, ownership and all that " ["post_category"]=> string(1) "0" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(4) "open" ["ping_status"]=> string(4) "open" ["post_password"]=> string(0) "" ["post_name"]=> string(49) "standards-innovation-flash-ownership-and-all-that" ["to_ping"]=> string(0) "" ["pinged"]=> string(85) " http://www.webdirections.org/resources/john-allsopp-the-dao-of-web-design-revisited/" ["post_modified"]=> string(19) "2011-11-10 07:47:09" ["post_modified_gmt"]=> string(19) "2011-11-09 21:47:09" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "http://www.webdirections.org/?p=3906" ["menu_order"]=> int(0) ["post_type"]=> string(4) "post" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(1) "4" ["filter"]=> string(3) "raw" } ["queried_object"]=> object(stdClass)#113 (16) { ["term_id"]=> &string(1) "1" ["name"]=> &string(4) "Blog" ["slug"]=> &string(4) "blog" ["term_group"]=> string(1) "0" ["term_order"]=> string(1) "0" ["term_taxonomy_id"]=> string(1) "1" ["taxonomy"]=> string(8) "category" ["description"]=> &string(0) "" ["parent"]=> &string(1) "0" ["count"]=> &string(3) "538" ["cat_ID"]=> &string(1) "1" ["category_count"]=> &string(3) "538" ["category_description"]=> &string(0) "" ["cat_name"]=> &string(4) "Blog" ["category_nicename"]=> &string(4) "blog" ["category_parent"]=> &string(1) "0" } ["queried_object_id"]=> int(1) }Blog
Morning coffee for web workers News Feed Podcast Follow Us
Standards, innovation, Flash, ownership and all that
- In: Blog
- By: John
- November 10, 2011
- 4 Comments
It’s often argued (well, asserted might be a better way of putting it) that standards are an anathema to innovation, or at the very least a significant impediment to it.
At its most extreme, this is used as an argument for disbanding the W3C, and even for core web technologies … Read more »
The Next 6 Billion
- In: Blog
- By: John
- October 20, 2011
- 39 Comments
Some time this month, for the first time, there will be 7 Billion people alive on earth. In around 14 years, the United Nations predicts our population will reach 8 Billion. These are numbers the human mind has not evolved to intuitively understand.
According to most estimates just over 2 … Read more »
Web Directions South 2011
- In: Blog
- By: John
- October 17, 2011
- 4 Comments
When you work on something for an extended period of time but which itself lasts itself only a brief moment, such as Maxine and I do with Web Directions, there’s an intensity to the event itself, and the strange mixture of relief (and exhaustion) coupled with nostalgia when it … Read more »
The challenge of WYSIWYG development for the web
- In: Blog
- By: John
- September 27, 2011
- 7 Comments
This is the first in what I hope will be a number of articles I’m writing to clarify my thinking in the lead up to my Dao of Web Design Revisited presentation at this years Web Directions South.
In the middle 1990s, by an accident of fate and coincidence … Read more »
The web is a different problem
- In: Blog
- By: John
- September 21, 2011
- 18 Comments
One of the most persistent criticisms of web technologies is that they evolve slowly, indeed, too slowly. Often the argument is raised that the process of standards is antithetical to “innovation” (for innovation read “making cool stuff up”).
To contrast with this glacial change, we’re typically pointed toward the wonders of … Read more »
2D Transforms in CSS3
- In: Blog, developer
- By: John
- September 21, 2011
- 4 Comments
One of the most powerful features of CSS3 are transforms, which allow us to take any element in an HTML document, and while not changing its effect on the page layout, rotate it, translate it (move it left, right, up and down), skew it and scale it. CSS3 provides … Read more »
What do you know? Video now available
What do you know? That’s the question we posed 20 Australian designers, developers, UX folks and others for our first ever “What do you know” events in Sydney and Melbroune.
The format was simple — each of the speakers had 5 minutes to tell the audience something they know — … Read more »
On the (abominable) proposed HTML5 “scoped” attribute for style elements
- In: Blog, developer
- By: John
- September 15, 2011
- 5 Comments
Over the last couple of years, I’ve had my fair share to say about the direction HTML5 has been taking, in particular being quite critical of the entire approach taken to adding richer semantics to HTML, as well as specific language choices.
It must be said though, that nothing has … Read more »
Bring back the CSS bike shedding property!
- In: Blog
- By: John
- September 6, 2011
- 5 Comments
There’s not necessarily a lot of whimsy in the world of web standards. A great deal of value, a lot of hard work by really smart people, but not whimsy.
Well, recently there’s been a little bit of whimsy in the otherwise dry, but very useful CSS3 Text module, with the … Read more »
HTML5 selectors API — It’s like a Swiss Army Knife for the DOM
- In: Blog, developer
- By: John
- September 2, 2011
- 4 Comments
In the infancy of JavaScript, there was little if any concept of an HTML document object model (DOM). Even though JavaScript was invented to enable web developers to manipulate parts of a web page, and in the original implementation, in Netscape 2.0, developers could only access the form elements, links, … Read more »
The 2011 McFarlane Prize for Excellence in Australian Web Design

In 2006, Maxine and I started a prize for excellence in Australian Web design in honour of Nigel McFarlane, Australian web and open source pioneer.
Unlike many awards, it’s not about popularity, it’s about excellence — as assessed by … Read more »
Let the Web move you — CSS3 Animations and Transitions
- In: Blog, developer
- By: John
- August 5, 2011
- 9 Comments
A brief history on Animation of the Web
If you’ve been developing for, or even just using the web for more than about 15 years, you’ll likely remember a time when animated effects were the bomb. Animated GIFs adorned just about every page, spinning globes, little men with jack hammers, self-folding … Read more »
Getting Sourcey — native HTML5 Audio and video
- In: Blog, developer
- By: John
- July 26, 2011
- 9 Comments
Hard perhaps to believe, but the world wide web began without an image element. That’s right, there was no way to include images as part of the content of a web page before Mosaic implemented them (here’s Marc Andreesen proposing the img element at the beginning of 1993). The … Read more »
CSS3 Radial Gradients
- In: Blog, developer
- By: John
- July 19, 2011
- 27 Comments
Getting your head around CSS3 radial gradients
We recently took a detailed look at linear gradients in CSS3. If you’ve not read that, you might like to spend a few minutes doing so, as the concepts are very similar, and I don’t spend quite as much time in this article … Read more »
Get off(line)
- In: Blog, developer
- By: John
- July 11, 2011
- 30 Comments
Taking your web sites and apps offline with the HTML5 appcache
There’s a general (and understandable) belief by even many developers that web sites and web applications can only be used when the browser has a web connection. Indeed, this is routinely cited as one of the real advantages of “native” … Read more »
Stay in touch
- Our awesome weekly newsletter:
- Twitter: @webdirections
- Keep up with the latest in HTML5, app development, platforms, devices and more at our blog, the web, unplugged
What do you know?
Live dev and design screencasts
State of Web Development Reports
Flip through our detailed reports focussing on the technologies and techniques used by web professionals around the world.
- State of Mobile Web Development (2011)
- State of Web Development (2010)
- State of Web Development (2008)
Slides and podcasts from previous events
- accessibility
- coding
- css
- data
- design
- development
- html
- innovation
- interaction design
- javascript
- mobile
- strategy
- usability
- user experience
- visual design
- wdn08
- wds07
- wds08
- wds09
- web standards
Jobs from jobs.webdirections.org
Post contract, part-time or full-time job offerings for web professionals of all types for free, or find properly qualified job openings as a web professional.










