CSS Gradients are about to Graduate!

Finally all browser vendors are on the same page when it comes to gradients

The Webkit team introduced CSS gradients on April 14th, 2008. Shortly afterwards they presented it to the W3C for consideration as a recommendation. Sometime later, Mozilla decided to implement CSS gradients using the same notation the Webkit gradients, but with the -moz prefix. After some time, however, they decided to replace that notation with a simpler one. Ever since, to do CSS gradients on the Web you had to write gradients the Webkit way for Safari and Chrome, and the Mozilla way for Firefox. Well, now all browser vendors have agreed to implement the same spec. At this time you can write a single notation that is identical for Safari, Chrome, Firefox, Opera and IE10.

Since version 5.1, Safari has supported the newer notation. Opera beta running Presto 2.10.299 fully supports the linear and radial notation, although the developer site only mentions support for the linear notation. Firefox, of course, already supports this notation. And the latest beta of IE10 does as well. This means that at some point all browsers will support this notation. Well, sort of.

Recently somebody at the W3C has been thinking a little too much. As of January 2012 the document CSS Image Values and Replaced Content Module Level 3 now has a slightly different notation. Since this just showed up, there is no support for it in any browser. And, since it is a working draft, it could change at any time. So, at this time, I’m going to ignore what the document says and just cover what the latest browsers have agreed to support.

Because CSS gradients are still a draft proposal, all browser vendors use their respective prefixes with the notation. This is a good thing since the spec is in flux. They shouldn’t change their present implementation until the spec reaches recommendation status, in which case they can implement the final version of CSS gradients without their vendor prefixes.

  • Webkit: -webkit-
  • Mozilla: -moz-
  • Opera: -o-
  • Microsoft: -ms-

CSS gradients are rendered as a background image. That means that all of the properties of the CSS background module apply to CSS gradients. In other words, you can have multiple gradients on the same element and control their size and position as well, or use them as image masks. Also, whereas in the past you might have used a background color in conjunction with a background image, you can now use a background gradients as the backdrop for a background image, or you could have a transparent gradient layered over a background image. The ability to stack up gradients while controlling their size, position and repetition means you can create complex repeating patterns that would normally require a background image. The ability to define multiple background images results in a layered affect not unlike Adobe Photoshop’s layers. The new CSS filters module will increase the comparison with Photoshop further my providing many color filters, such as reverse, multiply, dodge, burn, darken, lighten, grayscale, etc. With JavaScript you could also manipulate the properties of your CSS gradients to produce a background pattern that morphs in real time.

Linear Gradients

The notation for linear gradients is quite simple and straightforward. First thing, you’ll be defining it as a background image on an element. CSS uses functions that create the gradient according to the arguments you provide. For linear gradients, the values you’ll need are as follows:

[<point (one value, two values or degrees)>]?, <color [stop]?>, <color [stop]?>

From the above definition we can see that all values are optional, except the start and end colors.

The first value (point) is optional. If no value is provided, it will default to drawing the gradient from top to bottom. You can use keywords for the position. These can be a single keyword or a combination of two. You can also use any valid degree values. The purpose of these point definitions is to define which direction the gradient flow towards. You also need to provide at least two colors. The first color will be where the gradient starts from, and the last color will be where the point indicates. So a gradient with yellow and blue and a point value of top will start at the bottom with yellow and end at the top with blue. Here re possible point values:

- top
- right
- bottom
- left
- top left
- top right
- bottom left
- bottom right
- 0deg
- 11deg
- 67deg
- 182deg
- -45deg
- -90deg

Colors can have optional stop values. If no stops are provided, the colors will blend equally from the first to the last.You can provide as many colors as you want to create the gradient, and you can vary their widths by providing stops. The value of the stops can use any valid CSS length identifier (px, pt, em, %, etc.). The position value is placed after the color. You can use any valid CSS colors, such as keywords (red, yellow, blue), or hex, hsl, rgb or rgba values. Regardless of what the stop position is for the last color, that color will continue filling the element the rest of the way.

background-image: linear-gradient(top, yellow 10px, red 80px);
background-image: linear-gradient(top right, orange, green 30%, yellow 70%);
background-image: linear-gradient(60deg, red, white, blue 50%);

Repeating Linear Gradients

Repeat linear gradients are easy to do. Actually, the same effect can be achieved with background size and background repeat properties, but it is nice to have it I suppose. It works the same way as regular linear gradients, except that you use repeating-linear-gradient as the function:

background-image: repeating-linear-gradient(top, yellow 10px, red 80px);
background-image: repeating-linear-gradient(top right, orange, green 30%, yellow 70%);
background-image: repeating-linear-gradient(60deg, red, white, blue 50%);

Radial Gradients

The notation for radial gradients is similar to linear gradients, except that you can specific a shape argument to control how the radial is produced. Here’s the possible values:

[<position (two separate values)>]?[[<shape (literal value or length value)>] || [<size length value>]>]? <color [stop]?> <color [stop]?> 

From the above definition we can see that all values are optional, except the start and end colors, just like linear gradients.

If no value for position is supplied, the radial gradient will be centered in the element. Position is based on the center of the radial gradient. It accepts the same values as background position. Those values include percentages, lengths and keywords. Just like background positioning, you can use negative values to move the center of the radial gradient off the screen. Percentages and lengths require two values, the first defining the x axis and the second defining the y axis.

percentage: 0% 0%, 20% 60%, 50% 50%
length: 0px 0px, 24px 45px, 3em 5em

The keywords are: top, right, bottom, left and center. You could combine these in various ways:

top left, bottom right, center center, center right, top center

Shape can be either circle or ellipse. If no shape is supplied, if the length value is single, it defaults to a circle with a radius defined by that length. Otherwise, if no shape is supplied and two lengths are passed, it uses those to draw an ellipse. The first value determines the width, the second the height:

// A vertical ellipse:
background-image: radial-gradient(center, 100px 400px, red, white);
// An horizontal ellipse:
background-image: radial-gradient(center, 400px 100px, red, white); 

If you use one of the shape keywords, you can also use size keywords to control how the radial gradient is draw in relation to its container. The size keywords are:

- closest-side
- farthest-side
- closest-corner
- farthest-corner

First of all, these keywords only work when you use a shape keyword. Defining the shape of the radial gradient with lengths and then trying to use these size keywords will not work. So, this is how these size keywords work. If the container is narrower than it is tall, the size of circle or ellipse will be restrained by the left and right of the container. With farthest-side, it would be restrained by the top and bottom of the container, probably resulting in the left and right extending beyond those sides. Be aware that these work in relation to the position of the radial gradient. That means that if it is positioned near the top left, it will be rendered differently than if it were centered. Closest-corner and farthest-corner work just like closes-side and farthest-side. The best way to get the hang of these keywords is to play around with a radial gradient to see how they affect it. Although these keywords are nice conveniences, you’ll see that they are far from exact. If you need precise placement and size, you’re better off using lengths to define the size of your radial gradient.

Color and stops work similar to linear gradients. The first color defined the color drawn from the center of the radial gradient. The last color will define the outermost color of the gradient. Stops allow you to define more precise positioning of those colors in the radial gradient.

Repeating Radial Gradients

Like repeating linear gradients, it is possible to create the same effect as a repeating radial gradient. You’d just need to define it tediously repeating the colors and providing appropriate stops. In contrast, using the repeating-radial-gradient function makes this easy.

Practical Examples

Enough with theory. Let’s look at what we can do with linear and radial gradients. By layering them and controlling their size and positioning, we can create complex patterns that we can use as Web assets. Please note that in all of the following examples I’m presenting the gradients without vendor prefixes. To have them render in a browser that currently supports CSS gradients, you would need to provide the appropriate vendor prefix for that browser. When the current spec reaches recommendation status, browser vendors will drop their prefix.

In most of these examples I’ve used a transparent gray. This was so I could just add an background color to show through the transparency. Having the color controlled by the background color makes it easy to change the feel of the pattern.

Here’s a vertical stripe with the transparent gray stripe is separated by a 1 pixel transparent stripe:

background-image: 
   linear-gradient(0deg, 
      rgba(0,0,0,0.1) 75%, 
      transparent 75%);
background-size: 5px 100%;

vertical stripes gradient

Here’s the same stripe horizontal:

background-image: 
   linear-gradient(90deg, 
      rgba(0,0,0,0.1) 75%, 
      transparent 75%);
background-size: 100% 5px;

horizontal stripes gradient

And here it is slanted to the left:

background-image: 
   linear-gradient(45deg, 
      transparent 15%,  
      rgba(0,0,0,0.1) 15%, 
      rgba(0,0,0,0.1) 50%, 
      transparent 50%, 
      transparent 65%,
      rgba(0,0,0,0.1) 69%);
background-size: 6px 6px;

gradient of stripes slanting left

And then to the right:

background-image: 
   linear-gradient(-45deg, 
      transparent 15%,  
      rgba(0,0,0,0.1) 15%, 
      rgba(0,0,0,0.1) 50%, 
      transparent 50%, 
      transparent 65%,
      rgba(0,0,0,0.1) 65%);
background-size: 6px 6px;

gradient of stripes slanting right

Now lets have some fun with repeating linear gradients. Here’s vertical repeating stripes:

background-image: 
   repeating-linear-gradient(0deg, 
      rgba(0,0,0,0.1) 0px, 
      rgba(0,0,0,0.1) 5px, 
      transparent 5px, 
      transparent 10px);

repeating vertical stripes gradient

Horizontal repeating stripes:

background-image: 
   repeating-linear-gradient(90deg, 
      rgba(0,0,0,0.1) 0px, 
      rgba(0,0,0,0.1) 5px, 
      transparent 5px, 
      transparent 10px);

repeating horizontal stripes gradient

Left slanted repeating stripes:

background-image: 
   repeating-linear-gradient(45deg,
      rgba(0,0,0,0.1) 0px, 
      rgba(0,0,0,0.1) 5px, 
      transparent 5px, 
      transparent 10px);

repeating gradient of left leaning stripes

Right slanted repeating stripes:

background-image: 
   repeating-linear-gradient(-45deg,
      transparent, 
      transparent 5px, 
      rgba(0, 0, 0, 0.1) 5px, 
      rgba(0, 0, 0, 0.1) 10px);

repeating gradient of right leaning stripes

Now lets cross them:

background-image: 
   repeating-linear-gradient(0deg, 
      transparent 0,
      transparent 5px, 
      rgba(0, 0, 0, .1) 5px, 
      rgba(0, 0, 0, .1) 10px),
   repeating-linear-gradient(90deg, 
      transparent 0,
      transparent 5px, 
      rgba(0, 0, 0, .1) 5px, 
      rgba(0, 0, 0, .1) 10px);

checkered

And now criss-cross them:

background-image: 
   repeating-linear-gradient(-45deg,
      transparent, 
      transparent 5px, 
      rgba(0, 0, 0, 0.1) 5px, 
      rgba(0, 0, 0, 0.1) 10px),
   repeating-linear-gradient(45deg,
      transparent, 
      transparent 5px, 
      rgba(0, 0, 0, 0.1) 5px, 
      rgba(0, 0, 0, 0.1) 10px);

intersect

Enough with stripes, let’s get square:

background-image: 
   linear-gradient(180deg, 
      rgba(0,0,0,0.05) 75%, 
      transparent 75%),
   linear-gradient(90deg,  
      rgba(0,0,0,0.05) 75%, 
      transparent 75%);
background-size: 5px 100%, 100% 5px;

cubes

And a nice checkerboard pattern:

background-image: 
   linear-gradient(45deg, 
      rgba(0,0,0,0.1) 4.5px, 
      transparent 5px, 
      transparent 16px, 
      rgba(0,0,0,0.1) 16px, 
      rgba(0,0,0,0.1)), 
   linear-gradient(45deg, 
      rgba(0,0,0,0.1) 4.5px, 
      transparent 5px, 
      transparent 16px, 
      rgba(0,0,0,0.1) 16px, 
      rgba(0,0,0,0.1));
background-position: 0 0, 8px 8px;

squares

And let’s make those diagonal:

background-image: 
   linear-gradient(45deg, 
      rgba(0,0,0,0.1) 25%, 
      transparent 25%),
   linear-gradient(-45deg, 
      rgba(0,0,0,0.1) 25%, 
      transparent 25%),
   linear-gradient(45deg, 
      transparent 75%, 
      rgba(0,0,0,0.1) 75%),
   linear-gradient(-45deg, 
      transparent 75%, 
      rgba(0,0,0,0.1) 75%);
background-size: 10px 10px;

chess

Now that we have them diagonal, lets spice them up and turn them into an argyle pattern:

background-image: 
   linear-gradient(right top, 
      rgba(0,0,0,0.1), 
      rgba(0,0,0,0.1) 50%, 
      transparent 50%, 
      transparent),
   linear-gradient(left top, 
      rgba(0,0,0,0.1), 
      rgba(0,0,0,0.1) 50%, 
      transparent 50%, 
      transparent);
background-size: 12px 12px;

argyle

OK, now lets take another look at stripes. But this time we want to shake things up about. We want to get out to the monotony of strictly repeating patterns, but still have a pattern. What I’m talking about is sometimes called the Cicada principle. It produces a pattern that doesn’t repeat itself exactly. It does this my layering different repeating patterns, except that these are different proportions, similar to the progression of prime numbers. Using this principle, I’ve created a series of overlapping lines that creates a textile like pattern that retains it’s randomness. Here’s the CSS:

background-image: 
   linear-gradient(left, 
      rgba(0,0,0,0.1), 
      rgba(0,0,0,0.1) 25%, 
      transparent 25%, 
      transparent),
   linear-gradient(left, 
      rgba(0,0,0,0.1), 
      rgba(0,0,0,0.1) 15%, 
      transparent 15%, 
      transparent),
   linear-gradient(left, 
      rgba(0,0,0,0.1), 
      rgba(0,0,0,0.1) 15%, 
      transparent 15%, 
      transparent),
   linear-gradient(top, 
      rgba(0,0,0,0.1), 
      rgba(0,0,0,0.1) 17%, 
      transparent 17%, 
      transparent),
   linear-gradient(top,
      rgba(0,0,0,0.1), 
      rgba(0,0,0,0.1) 15%, 
      transparent 15%, 
      transparent),
   linear-gradient(top,
      rgba(0,0,0,0.1), 
      rgba(0,0,0,0.1) 13%, 
      transparent 13%, 
      transparent);
background-size: 10px 100%, 17px 100%, 21px 100%, 100% 10px, 100% 17px, 100% 21px;
backgroud-position: 0 0, 6px 0, 14px 0, 0 0, 0 6px, 0 16px;

linen

Now lets play with radial gradients. We’ll start with basic patterns and build up to more complex combinations.

background-image:
   radial-gradient( 
      rgba(0,0,0,0.1),
      rgba(0,0,0,0.1) 45%,
      rgba(0,0,0,0) 50%,
      rgba(0,0,0,0) 95%);
background-size: 8px 8px;

speckeled

Now we’ll take the above pattern and turn the dots inside out so that the pattern looks like someone cut holes in the color.

background-image:
   radial-gradient( 
      rgba(0,0,0,0),
      rgba(0,0,0,0) 50%,
      rgba(0,0,0,0.1) 55%,
      rgba(0,0,0,0.1) 95%);
background-size: 10px 10px;

spotted

Now we’ll just play with the size of circles a bit.

background-image:
   radial-gradient( 
      rgba(0,0,0,0.1),
      rgba(0,0,0,0.1) 9px,
      rgba(0,0,0,0) 9px,
      rgba(0,0,0,0) 17px);
background-size: 18px 18px;

circles

OK, I now the above patterns are not revolutionary or anthing. Now we’re going to get creative. For the next ones we’re going to user colors, yeah! The next pattern has a gold background with orange and greenish polka dots:

background-image:
   radial-gradient( 
      rgba(255,0,0,0.2),
      rgba(255,0,0,0.2) 4px,
      rgba(255,255,255,.10) 5px,
      rgba(255,255,255,.10) 7px),
   radial-gradient( 
      rgba(0,0,0,0.2),
      rgba(0,0,0,0.2) 4px,
      rgba(255,255,255,.25) 5px,
      rgba(255,255,255,.25) 7px);
background-size: 18px 18px;
background-color: #ffd239;
background-position: 10px 10px, 0% 0%;

gold-polka-dots

The next one I call puff balls because of their look:

background-image:
   radial-gradient(
      rgba(255,255,255,0) 90%,
      rgba(255,255,255,.5) 90%,
      rgba(255,255,255,.5)
   ),
   radial-gradient( 
      rgba(255,255,255,0.01),
      rgba(255,255,255,0.01) 10%,
      rgba(255,255,255,255.1) 70%,
      rgba(0,0,0,0) 79%,
      rgba(0,0,0,0) 96%);
background-size: 20px 20px;
background-color: #ff77a1;

puff-balls

Here’s another gold pattern with four-pointed stars:

background-image:
   radial-gradient( 
      rgba(255,0,0,0.2),
      rgba(255,0,0,0.2) 8.5px,
      rgba(255,255,255,.5) 9.5px,
      rgba(255,255,255,.5) 17.5px),
   radial-gradient( 
      rgba(0,0,0,0.2),
      rgba(0,0,0,0.2) 8.5px,
      rgba(255,255,255,.15) 9.5px,
      rgba(255,255,255,.15) 17.5px);
background-size: 18px 18px;
background-color: gold;
background-position: 9px 9px, 0% 0%;

gold stars

And here we change the background to green:

background-image:
   radial-gradient( 
      rgba(255,210,57,0.42),
      rgba(255,210,57,0.42) 9px,
      rgba(0,0,0,0) 11px,
      rgba(0,0,0,0) 15px),
   radial-gradient( 
      rgba(0,0,0,0),
      rgba(0,0,0,0) 9px,
      rgba(255,210,57,1) 10px,
      rgba(255,210,57,1) 15px);
background-size: 17px 17px;
background-color: #1e8e04;
background-position: 8.5px 8.5px, 0% 0%;

green stars

And finally, we do some interesting overlap with the radial gradients:

background-image:
   radial-gradient( 
      rgba(255,255,255,0),
      rgba(255,255,255,0.5) 14px,
      rgba(255,255,255,0) 14px,
      rgba(255,255,255,0) 26px),
   radial-gradient( 
      rgba(0,0,255,0.31),
      rgba(0,0,255,0.31) 14px,
      rgba(255,255,255,0) 16px);
background-size: 28px 28px, 28px 28px;
background-position: 14px 18px, 0% 18px, 0% 0%;
background-color: rgba(200,250,190,0.5);

petals

You can see these gradients in action here. You can same the page to your desktop, since it is a self-contained document.

Proposed Changes to Spec

So, as I mentioned, since January 2012 the draft for CSS gradients at the W3C has some notation changes. Really their minor, but in my opinion, not necessary. Actually, I’m irritated by them. The two owners of the document: Elika J. Etemad and Tab Atkins Jr., from Mozilla and Google respectively, have decided to make the notation more English-like by requiring prepositions for the position keywords for linear and radial gradients. So if you had a yellow to red linear gradient that ended in the bottom right, you’d need to write the following:

linear-gradient(to bottom right, yellow, red);

For a radial gradient, it would be

radial-gradient(circle at closest-side, yellow, red);

OK, so if the point is to make it more English-like, shouldn’t it be:

linear-gradient(to the bottom right, yellow, red)

Or better yet:

linear-gradient(directed toward the bottom right, yellow, red);

Or:

radial-gradient(a circle positioned at closest-side, yellow, red);

And, last time I check, a big chuck of the world doesn’t know what the English word “to” means and so it adds no clarity to what the keywords are doing. I’m totally against requiring unnecessary English grammatical constructs in to CSS. We don’t do that with HTML or JavaScript. What strikes me as really odd, one of the authors is from Mozilla. They were the guys that complained that the original Webkit notation used “to” and “from” to designate the start and end colors. Now they want to make the simpler notation more complicated. Adding prepositions to keywords for gradients will not add any new functionality nor prevent any rendering errors. They just make the notation more wordy. Fail! Making CSS more English-like is a rabbit hole down which you do not want to go.

March 23, 2012

Since writing this post there has been some ongoing discussion at CSS Working Group about the reasoning behind the use of prefixes in the new syntax. The gist of it is that prepositions actually remove the ambiguity of direction when dealing with gradients. Here’s a quote from the discussions:

The “to” keyword was added to linear gradients because there was
significant confusion about whether “top” meant “start from the top
(put the 0% color on the top)” or “point toward the top (put the 100%
color on the top)”.

Radial gradients gained keywords in an attempt to make the syntax more
flexible and more readable – previously, for example, you could have a
declaration like “radial-gradient(20% 20%, 30% 30%, black, white)”.
It’s very unclear what that means – even if you know that one of them
is a position and the other is a size, how can you tell which is
which? Due to this ambiguity, the syntax also disallowed specifying
just a size without a position.

The new syntax, while not ideal in some ways, solves this problem -
you’d write the previous example as “radial-gradient(30% 30% at 20%
20%, black, white)” which gives you some clues as to which is the size
and which is the position. As well, it’s now possible to specify
either a size or a position alone, and have it parsed unambiguously -
“radial-gradient(30% 30%, black, white)” has an explicit size and
default position, while “radial-gradient(at 20% 20%, black, white)”
has an explicit position and default size.

In light of the above I’ve been won over to support prepositions in the gradient syntax. It solves the problems described above and will make creating gradients easier for everyone.

About these ads

CSS Gradients for IE9

This works with Desktop IE9, Desktop Firefox, Desktop Chrome, Desktop Safari, Desktop Opera, iOS, and Android.

Attention! IE9 will not destroy the world, kill babies, or take away your home or job.

Simply put, IE9 is the best browser Microsoft has ever released. Has it caught up to Chrome, Firefox and Safari? No. But that doesn’t matter. It’s still light years ahead of any other version of IE. All of us should be praying every day for IE users to upgrade to it as soon as possible.

Shortly after the initial launch of the beta of IE9, I began testing to see what kind of support it had for all the rich and exciting features CSS3 offers for Web layout and interaction. The earlier beta’s didn’t have much, but with each release it has gotten better. If you’re already using advanced CSS3 for Web development and never bothered supporting IE before, you’ll want to know what it supports and what it doesn’t. Here’s what it supports at present right from the horse’s mouth. In particular, it supports real CSS opacity, multiple background images, box shadows, border radius, background-clip, background-size, background-position, WOFF for Web fonts, RGBA and HSLA color, box sizing, as well as the full suite of CSS3 selectors. The above post also talks about support for CSS3 2d transforms, however, even with the -ms- vender prefix I am unable to get it to work with the present beta (7).
Update: Transforms are working in Platform Preview 6, which is different from the present public beta. Microsoft is taking a two track approach to releasing this: the public beta for general users to test and a platform preview where features are introduced but not necessary finalized.

So what didn’t make it into IE9? First up, the flexible box model. Once you’ve used the flexible box model for layout, it’s as painful as eating glass to go back to using floats and positioning for layout. No text shadow, which is a strange omission considering they have box shadow. No border images. No CSS transitions. The single-threaded nature of JavaScript makes it inefficient for complex animations. Offloading style animations to the browser’s CSS rendering engine frees up JavaScript and allows the browser to use threads and hardware acceleration for better optimization. In my opinion, CSS3 transitions are more important than CSS3 transforms. Since Firefox, Opera and Webkit all support CSS3 transitions to some degree, it’s a odd omission for IE9. No 2d or 3d transforms. As I mentioned before, transforms do not appear to be implemented in the current beta. (Someone correct me if I’m wrong on this.) The thing I love about CSS3 transitions and transforms is that they allow you to create user interactions that make a Web application feel like a native one, blurring the difference between desktop and Web. No CSS3 keyframe animation. If you thought CSS3 transitions were awesome, you be blown away by CSS keyframe animations.

When I look at IE9′s support for CSS3, it appears they decided to pick the low hanging fruit: border radius, drop shadow, multiple backgrounds, etc. But the flexible box model, gradients, transitions, transforms and keyframe animation are the things in CSS3 that really turn your head.

I have no experience working with Adobe Flash. I do have extensive experience working with Microsoft’s Silverlight platform. I love how it enables you to create rich, interactive user interfaces where you can customize every aspect of a control’s look and feel. Chrome, Firefox and Safari’s support for CSS3 enables a similar high level of possibilities for the creation of Web user interfaces. IE9 is attempting to achieve feature parity with the other browsers and is making good progress. But if you want to use the CSS3 features that IE9 doesn’t support, you’ll need to find workarounds.

Presently my main area of focus is the mobile Web on Android, Blackberry 6, iOS and WebOS. That’s a world ruled by Webkit. But I usually make efforts to ensure that my solutions can also work with modern desktop browsers: Chrome, Firefox and Safari. That involves a lot of vender prefixes: -moz, -webkit. And then you need to future proof it by supplying the same property without the vendor prefix. This technique allows browsers that understand the properties, like IE9, to also render them without any extra effort.

I’m going to take one example of an HTML/CSS3 implementation of iOS’s popup dialog box which I originally created for use on iOS devices and show how I got it to render equally in Chrome, Firefox, IE9, Opera and Safari. At the end of this post you’ll find links to try it out online or download it. One thing, I’m not using any image pieces, just CSS3 properties. Here’s the initial state of the page with the popup in Safari and Firefox:

popup Initial state

Here’s the page with the popup in view in Safari and Firefox:

Here’s the same markup in IE9. Notice how it understands border radius, box shadow and RGBA background color, but cannot render the flexible box model layout nor the CSS3 gradients.

ie9 initial state no styleie9 final state no style

IE9′s lack of support for the flexible box model can be resolved by using old-school layout techniques (floats/positioning). But there is no way to fake CSS3 gradients with pngs. When you stretch them they exhibit banding. Since I make extensive use of CSS3 gradients all the time, I felt pressed to find a solution for IE9. After spending some time experimenting with SVG in IE9, I hit on an idea. Using an IE9 specific stylesheet, I would try setting SVG gradients as background images on the element’s that use CSS3 gradients. The technique works quite well. Here’s IE9 with its custom CSS:

ie9 initial state fixedie9 final state fixed

First, here’s a CSS3 gradient used by Chrome, Firefox and Safari:

header {
	width: 100%;
	display: -webkit-box;
	display: -moz-box;
	display: box;
	-webkit-box-orient: horizontal;
	-webkit-box-pack:justify;
	-webkit-box-align: center;
	-webkit-box-sizing: border-box;
	-moz-box-orient: horizontal;
	-moz-box-align: center;
	-moz-box-pack:justify;
	-moz-box-sizing: border-box;
	box-orient: horizontal;
	box-align: center;
	box-pack:justify;
	box-sizing: border-box;
	height: 45px;
	margin: 0;
	padding: 0 10px;
	background-image: 
		-webkit-gradient(linear, left top, left bottom, 
			from(#b2bbca), 
			color-stop(0.25, #a7b0c3),
			color-stop(0.5, #909cb3), 
			color-stop(0.5, #8593ac), 
			color-stop(0.75, #7c8ba5),
			to(#73839f)); 
	background-image: 
		-moz-linear-gradient(top,
			#b2bbca, 
			#a7b0c3 25%,
			#909cb3 50%, 
			#8593ac 50%, 
			#7c8ba5 75%,
			#73839f); 
	border-top: 1px solid #cdd5df;
	border-bottom: 1px solid #2d3642; 
}

As you can see in the above code, we’re defining background images as gradients with a number of color stops. That all a CSS3 background gradient is. As a matter of fact, it’s rendered by the browser as a canvas background image. Since IE9 supports SVG, including as background images, I’ve come up with a way to use SVG gradient images as background gradients. Because SVG is vector-based, the gradients scale without banding. SVG is an XML markup language for describing vector graphics. The HTML5 parsing engine allows SVG to be directly embedded in HTML. But I want background images. By defining the height of the SVG document as 100%, I have an image that will scale to whatever the element is, just like the CSS3 gradient. Here’s the markup that I used to create the gradient for the header. Notice that the SVG gradient has color-stops and offsets like the CSS gradients. They aren’t that different.

<?xml version="1.0" ?>
<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" version="1.0" width="100%" 
   height="100%" 
     xmlns:xlink="http://www.w3.org/1999/xlink">

  <defs>
    <linearGradient id="myLinearGradient1"
                    x1="0%" y1="0%"
                    x2="0%" y2="100%"
                    spreadMethod="pad">
      <stop offset="0%"   stop-color="#b2bbca" stop-opacity="1"/>
      <stop offset="50%"   stop-color="#909cb3" stop-opacity="1"/>
      <stop offset="50%"   stop-color="#8593ac" stop-opacity="1"/>
      <stop offset="100%" stop-color="#73839f" stop-opacity="1"/>
    </linearGradient>
  </defs>

  <rect width="100%" height="100%"
     style="fill:url(#myLinearGradient1);" />
</svg>

The document has a height and width of 100%, the gradient is set to expand to 100% and the rectangle is defined with a height and width of 100%. It is possible to turn this SVG image into a datauri and put it directly in the CSS, using use any of the many resources available for datauri conversion. However, the SVG files are just simple text files. If you convert them to datauris, you will not be able to make any changes to them. While putting this demo together I had to constantly tweak the values in the SVG gradients to get them exact. Keeping the SVG files allows you to go back and modify the gradients at any time. Here’s how you use this for IE9:

header {
  background-image: url("svg-gradient.svg");
}

That’s it. IE9 will display the above SVG graphic in a manner indistinguishable from native CSS3 gradients.

For the repeating striped background gradient on the body tag, I’m using a CSS3 gradient with background sizing and letting it repeat across the page. For IE9 I do the same thing, using background sizing on the SVG equivalent to get the same effect.

Like IE9, Opera also does not support the flexible box model nor CSS3 gradients. Notice how Opera renders the demo basically the same as IE9:

Opera initial state no styleOpera final state no style

After creating the SVG workaround for IE9 to mimic CSS3 gradients, I started thinking about Opera’s lack of support for CSS3 gradients. Opera has the best support for SVG out of all the browsers. I therefore tried giving Opera the same CSS that I gave IE9. It worked as well as it did for IE9. You can see the results below:

Opera inital state fixedOpera final state fixed

There is very minimal browser sniffing required to make this work across modern browsers. One stylesheet for Chrome, Firefox and Safari, a conditional comment for IE9 and a browser agent sniff for Opera:

<!--[if IE 9]>
	 <link rel="stylesheet" type="text/css" href="popup-svg.css">
<![endif]-->

<script type="text/javascript">
    var Opera = /opera/i.test(navigator.userAgent);
    if (Opera) {
        var link = document.createElement("link");
        link.setAttribute("rel", "stylesheet");
        link.setAttribute("href", "popup-svg.css");
        document.getElementsByTagName("head")[0].appendChild(link);
}
</script>

Please Note: If you’re going to use this technique in a production environment you should use feature detection because at some point Opera will support CSS gradients. There are a number of ways to accomplish feature detection. Perhaps the easiest is to use Modernizr.

You can try out this demo online or download the source code. Feel free to use the included SVG files as templates for your own gradients.

Oh, and one last thing. I’m using the ChocolateChip mobile JavaScript framework for this demo. Originally I created it to work on mobile devices using Webkit browsers. I therefore provided no support for the JScript quirks of IE. But since IE9 has a completely rewritten JavaScript engine and uses the standard event model and DOM interfaces like the other browsers, ChocolateChip works fine on it without modification. That definitely put a smile on my face.

Making an iPhone Switch Control without Images

Works on desktop Safari, Chrome and Firefox, iPhone, iPod Touch and iPad.

On the iPhone and iPad, Apple uses a control called switch. It’s actually a different take on the checkbox. Like radio buttons, checkboxes do not lend themselves to touch interfaces, especially guys with fat fingers, cough! Instead of making us suffer with those dinky checkboxes, Apple uses a more visual cue to what the user is actually doing, switching something on or off. As a matter of fact, that’s exactly how the control is labeled: “on” or “off”. They’re really easy to use, just swipe your finger to throw the switch, done. In case you’re not sure what I’m talking about, here they are:

switch control

OK, so all the mobile Web frameworks have a switch control. And I hate them all. They either do an instant switch between the on and off state, using an image sprite, or they do this really lame thing where they animate the horizontal background position of the image on a checkbox with its default styles removed. None of those implementations feels the same as when you swipe the switch control in a native iOS app.

So what am I going to do? I tell you, I’m going to throw the friggin’ image out and build the whole control from scratch using just HTML, CSS3 and some JavaScript to make it work. Bada-bing! To start with, here’s the basic markup for a checkbox:

<div class="checkbox unchecked" id="sleepSwitch">
	<div class="on">ON</div>
	<div class="thumb"><span></span></div>
	<div class="off">OFF</div>
	<input type="checkbox" value="ZZZZZZZZ!" offvalue="But, I need more sleep!">
</div>

As we did when we created iPhone style radios buttons, we’re using real checkboxes in our iPhone switch controls. And like in the radio button example, we’ll set the checkbox input’s display value to “none”. We’ll use CSS3 properties to style the markup to look like a real iOS switch control and we’ll attach event listeners to set the input checkbox’s check state to true or false, depending on whether we want it to be selected or not.

To create this switch control we’ll need to style the frame named “checkbox” with rounded corners. Notice that the markup above contains three parts: the on state, the thumb and the off state. The rounded frame will only be wide enough to show one state plus the thumb. Using CSS3 transitions and transforms, a click or touch will cause the three elements to side back and forth within the rounded frame. For positioning the switch’s elements and sliding them back and forth we’re going to use CSS3 3d transforms on the x axis. Here is the CSS to make this happen:

/* Checkbox */
.checkbox {
	display: -webkit-box;
	-webkit-box-orient: horizontal;
	-webkit-box-pack:justify;
	-webkit-box-sizing: border-box;
	-webkit-tap-highlight-color: transparent;
	width: 94px;
	overflow: hidden;
	-webkit-border-radius: 6px;
	text-align: center;
	line-height: 28px;
	cursor: pointer;
	-webkit-user-select: none;
	position: absolute;
	right: 10px;
	top: 7px;
}
.checkbox > input[type="checkbox"] {
	display: none;
}
.checkbox .thumb {
	-webkit-border-radius: 7px;
	position: relative;
	z-index: 3;
	border: solid 1px #919191;
	-webkit-transition: all 0.125s  ease-in-out;
	-webkit-transform: translate3d(0px,0%,0%);
}
.checkbox .thumb span {
	display: block;
	-webkit-box-sizing: border-box;
	height: 25px;
	width: 38px;
	border-top: solid 1px #efefef;
	-webkit-border-radius: 6px;
	background-image: -webkit-gradient(linear, left top, left bottom, from(#cecece), to(#fbfbfb));
	border-top: solid 1px #efefef;
	position:relative;
}
.checkbox .on {
	color: #fff;
	background-image: 
		-webkit-gradient(linear, left top, left bottom, 
			from(#295ab2), 
			to(#76adfc));
	width: 54px;
	padding-right: 4px;
	border: solid 1px #093889;
	-webkit-border-top-left-radius: 6px;
	-webkit-border-bottom-left-radius: 6px;
	margin-right: -6px;
	height: 25px;
	-webkit-transition: all 0.125s  ease-in-out;
	position: relative;
	-webkit-transform: translate3d(0px,0%,0%);
}
.checkbox .off {
	color: #666;
	background-image: -webkit-gradient(linear, left top, left bottom, from(#b5b5b5), color-stop(0.50, #fff));
	width: 54px;
	padding-left: 4px;
	border: solid 1px #a1a1a1;
	-webkit-border-top-right-radius: 6px;
	-webkit-border-bottom-right-radius: 6px;
	margin-left: -6px;
	height: 25px;
	-webkit-transition: all 0.125s  ease-in-out;
	position: relative;
	-webkit-transform: translate3d(-54px,0%,0%);
}
.checkbox.unchecked .thumb {
	-webkit-transform: translate3d(-54px,0%,0%);
}
.checkbox.checked .thumb {
	-webkit-transform: translate3d(0px,0%,0%);
}
.checkbox.unchecked .on {
	-webkit-transform: translate3d(-60px,0%,0%);
}
.checkbox.checked .on {
	-webkit-transform: translate3d(0px,0%,0%);
}
.checkbox.unchecked .off {
	-webkit-transform: translate3d(-54px,0%,0%);
}
.checkbox.checked .off {
	-webkit-transform: translate3d(6px,0%,0%);
}
/* For Very Important changes, use the orange checkbox */
.checkboxBase.important .on {
	border: solid 1px #d87100;
	background-image: -webkit-gradient(linear, left top, left bottom, from(#e75f00), color-stop(.5, #ff9c12));
}
/* End Checkbox */

To make the switch more realistic, I’m transforming all three pieces of the switch at the same time. This gives the switch a more realistic feeling. Notice the comment in at the end of the above CSS about the important class. You can use this to indicate a switch that makes a very important change. This class changes the default switch’s blue color to bright orange. This is the color Apple uses to show that a switch’s action is very important.

Having the CSS defined for the look and animation brings us close to the finished control, but we need to write some JavaScript to make the switch interactive. The JavaScript needs to do two things: toggle the classes “checked” and “unchecked” on the switch, and toggle the checked value of the checkbox between true and false. I’m using the ChocolateChip JavaScript framework to do this. You can switch my code to whatever library you want. If you know basic JavaScript, it shouldn’t be hard. Here’s the JavaScript to make it happen:

Element.prototype.toggleSwitch = function() {
	if (this.hasClass("switch")) {
		if (this.last().checked === true) {
			this.last().checked = false;
			this.toggleClass("checked", "unchecked");
		} else {
			this.last().checked = true;
			this.toggleClass("checked", "unchecked");
		}
	} else {
		return false;
	}
};

The last() used in the code above is a ChocolateChip method to return the last child of the control, which happens to be the checkbox input. That way we can set its checked state to true or false.

Now that we have the code to setup up the switch control, we can make it work as follows:

$(".switch").forEach(function(checkbox) {
	checkbox.bind("click", function() {
		this.toggleSwitch();
	});
	
	checkbox.bind("touchstart", function(e) {
		e.preventDefault();
		this.toggleSwitch();
	});
}); 

That’s it to make the switch switchable. But to make it do something you’d need a bit more as well. In my example, I’m getting some values from the switch and outputting it to a response field like this:

$(".switch").forEach(function(checkbox) {
	checkbox.bind("click", function() {
		if (this.last().checked === true) {
			$("#switchResponse").fill(
				this.last().getAttribute("value"));
		} else {
			$("#switchResponse").fill(
				this.last().getAttribute("offvalue"));
		} 
	});
	
	checkbox.bind("touchstart", function(e) {
		if (this.last().checked === true) {
			$("#switchResponse").fill(
				this.last().getAttribute("value"));
		} else {
			$("#switchResponse").fill(
				this.last().getAttribute("offvalue"));
		}
	});
}); 

You can try this out online or download the source code.

iPad Style Split Layout with Flexible Box Model

Works in Safari, Firefox, Chrome, iPhone, iPad, Android

In a previous post we looked at how CSS3′s flexible box model allowed us to create horizontal alignment of elements. There are several other features in the flexible box model that allow us to create layouts that would require complicated CSS hacks or JavaScript: equal height columns. You know the kind of layout I’m talking about. A header with several columns of material and a footer. You want the columns to always be the same height. You can use a table, but that can introduce a certain nasty kudginess to what you’re trying to achieve. Or you could use background images with nested divs, which is another type of kludginess. Or you could use some JavaScript, which introduces another type of kludginess.

With the flexible box model you can accomplish the equal height columns with a few CSS3 properties. What we’re going to do is show how to put together a typical split-level iPad layout with equal height sections. Here’s what we’re shooting for:
Example Layout with Equal Height Columns using CSS3 Flexible Box Model

To create the layout in this image, we’ll use the following markup:

<!DOCTYPE HTML>
<html lang="en">
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width; height=device-height; initial-scale=1.0, maximum-scale=1.0, user-scalable=0;">
	<meta name="apple-mobile-web-app-capable" content="yes">
	<title>Flexible Box Model Layouts</title>
	<style type="text/css">
	</style>
</head>
<body>
<article>
	<header>
		<h1>Home Base</h1>
	</header>
	<section>
		<aside>
			<nav>
				<ul>
					<li><a href="#">Item 1</a></li>
					<li><a href="#">Item 2</a></li>
					<li><a href="#">Item 3</a></li>
					<li><a href="#">Item 4</a></li>
					<li><a href="#">Item 5</a></li>
					<li><a href="#">Item 6</a></li>
					<li><a href="#">Item 7</a></li>
					<li><a href="#">Item 8</a></li>
					<li><a href="#">Item 9</a></li>
				</ul>
			</nav>
		</aside>
		<section>
			<h2>Subtitle Here</h2>
			<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales ligula in libero. </p>

			<p><b>Lorem ipsum dolor sit amet, consectetur adipiscing elit</b>. Sed dignissim lacinia nunc. Curabitur tortor. Pellentesque nibh. <i>Lorem ipsum dolor sit amet, consectetur adipiscing elit</i>. Aenean quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis tristique sem. Proin ut ligula vel nunc egestas porttitor. Morbi lectus risus, iaculis vel, suscipit quis, luctus non, massa. Fusce ac turpis quis ligula lacinia aliquet. Mauris ipsum. Nulla metus metus, ullamcorper vel, tincidunt sed, euismod in, nibh. Quisque volutpat condimentum velit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. </p>
			
			<p>Nam nec ante. Sed lacinia, urna non tincidunt mattis, tortor neque adipiscing diam, a cursus ipsum ante quis turpis. Nulla facilisi. Ut fringilla. Suspendisse potenti. <b>Nulla metus metus, ullamcorper vel, tincidunt sed, euismod in, nibh</b>. Nunc feugiat mi a tellus consequat imperdiet. Vestibulum sapien. Proin quam. Etiam ultrices. Suspendisse in justo eu magna luctus suscipit. Sed lectus. Integer euismod lacus luctus magna. Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. </p>
		</<span class="hiddenGrammarError" pre=""><span class="hiddenGrammarError" pre="">section>
	</section</span></span>>
	<footer>
		<p>Footer stuff here</p>
	</footer>
</article>
</body>
</html>

If you load this markup in a browser, it’ll be pretty plain. Let’s add some basic styling for the header, footer, list menu, etc. First we’ll get rid of the defaults for the body and list elements.

html, body {
	margin: 0px;
	padding: 0px;
	font: normal 14px/16px Helvetica, Sans-serif;
}
ul, li {
	list-style: none;
	padding: 0px;
	margin: 0px;
}

Next, for Firefox, we need to indicate that the HTML5 tags are block elements. The latest versions of Webkit in Safari, iPhone and iPad already recognize these tags and display them properly.

/* for Firefox */
article, header, section, nav, aside, footer {
	display: block;
}
/* end Firefox */

Now we need to add the styles to give are markup a more polished look. We’re going to add CSS3 background gradients, rgba color and border radius:

section > section {
	padding: 10px 20px;
	background-color: #cbd2d8;
	background-image: -webkit-gradient(linear, left top, right top, from(#c5ccd4), color-stop(0.75, #c5ccd4), color-stop(0.75, transparent), to(transparent)); 
	background-image: -moz-linear-gradient(left, #c5ccd4, #c5ccd4 75%, transparent 75%, transparent);
	-webkit-background-size: 5px 100%;
	-moz-background-size: 5px 100%;
}
header {
	background-color: #b0bccd;
	background-image: -webkit-gradient(linear, left top, left bottom, 
		from(#b0bccd), 
		color-stop(0.5, #889bb3), 
		color-stop(0.5, #8195af), 
		to(#6d84a2));
	background-image: -moz-linear-gradient(top, #b0bccd, #889bb3 50%, #8195af 50%, #6d84a2); 
	padding: 10px 10px;
}
header h1 {
	text-align: center;
	font: bold 21px/21px Helvetica, Arial, Sans-serif;
	letter-spacing: -1px;
	text-shadow: 0px -1px 0px rgba(0, 0, 0, 0.5);
	color: #fff;
	margin: 0px;
}
footer {
	background-color: #b0bccd;
	background-image: -webkit-gradient(linear, left top, left bottom, 
		from(#b0bccd), 
		color-stop(0.5, #889bb3), 
		color-stop(0.5, #8195af), 
		to(#6d84a2));
	background-image: -moz-linear-gradient(top, #b0bccd, #889bb3 50%, #8195af 50%, #6d84a2); 
	padding: 1px 0px;
	text-align: center;
	color: #fff;
}
nav li > a {
	text-decoration: none;
	display: block;
	padding: 8px 10px;
}
nav li > a {
	cursor: pointer;
	padding: 8px;
	border-bottom: 1px solid #acacac;
	background-color: #fff;
	font-weight: bold;
	color: rgba(0,0,0,.75);
}
nav li > a:after {
	content: "›";
	font: normal 28px/28px Verdana;
	color: rgba(0,0,0,.5);
	display: block;
	float: right;
	margin-top: -6px;
}
nav li > a:hover {
	background-image: -moz-linear-gradient(top, #4286f5, #194fdb);
	background-image: -webkit-gradient(linear, left top, left bottom, from(#4286f5), to(#194fdb));
	color: #fff;
}
nav li > a:hover:after {
	color: #fff;
}
h2 {
	color: #666;
	text-shadow: 0px -1px 1px #fff;
}
section > p {
	-webkit-border-radius: 10px;
	-moz-border-radius: 10px;
	background-color: rgba(255,255,255,0.85);
	border: solid 1px rgba(0,0,0,0.5);
	padding: 10px;
}

This gives us a layout that looks like this:
Style Layout Without Flexible Box Model Applied

This doesn’t look too bad, except that we want to the list to be on the left, and the content to be on the right. Normally, to achieve that we would need to put the content section before the list and float it right and then float the list left. Then we’d need to clear that float on the footer. That would work visually, except that neither the list nor the content would know about the other’s height. Or we could use relative and absolute position, and basically have the same problem. Or we could use CSS3′s flexible box model and have no problems at all, well, unless you really, really need to support IE, any version. You could use this for the god browsers and use conditional comments to give IE some crappy float arrangement. Honestly, I would to that to IE without thinking about it.

So, if you look at the document markup, we have an article tag with a header tag, section tag and footer tag as its children. The section tag has and aside tag and another section tag as its children. To make those work they way we want we need to give the parent section tag some flex power:

article > section {
	display: -webkit-box;
	-webikit-box-orient: horizontal;
	-webkit-box-align: stretch;
	display: -moz-box;
	-moz-box-orient: horizontal;
	-moz-box-align: stretch;
	-moz-box-lines: multiple;
}

This will give us cause the aside and section tags to align horizontally in their parent and each will have the same height. However in both Webkit and Firefox they both have some other issues with understanding how to deal with the long, wrapping content in the section tag.

Equal Height Columns in Firefox with Width Adjustment ProblemsEqual Height Columns in Safari with Width Adjustment Problems

To fix the problem with the browsers not knowing how to handle the wrapping content we just need to add a flexible box value to the section tag with the content:

section > section {
	-webkit-box-flex: 1;
	-moz-box-flex: 1;
}

What this does is tell the browser that the child section tag’s width should be whatever space is left over from that occupied by the aside tag, it’s sibling in the same container. Since the aside has a defined width of 200 pixels, the browser will give the rest to the section tag. Suddenly our layout is looking and acting the way you’d expect. It will even expanding dynamically as you resize the browser window.

You can try it out live or download the source.

CSS3 Layouts with Horizontal Alignment

Works with Safari, Chrome, Firefox, iPhone, iPad, Android

One of the most common features in modern Web layouts is to have some with a fixed width on one side or on both sides, with the rest of the space taken up dynamically. This is usually accomplished by floating the first item to the right and the second item to the left, or by using relative and absolute position. With CSS3 there is another, better way. No floats, no clearing floats, no positioning. Instead we use the properties of the flexible box model. The magic all starts with a new display property: box. At the moment, you’ll need to use the -moz and -webkit prefixes to implement these features. They have been supported since version 3 of both Firefox and Safari. If the majority of your users are on Firefox, Chrome and Safari, or if you’re targeting the mobile Web, you can go ahead and use these properties today and achieve the kind of layouts that previously required complex CSS frameworks or JavaScript libraries like YUI or Ext.js. The flexible box model allows us to create the equivalent of stack panels and wrap panels with HTML.

Let’s get started. We’ll create and HTML5 document with a header tag. We’ll style the header and style two links inside it to look like buttons:

<!DOCTYPE HTML>
<html lang="en">
<head>
	<meta charset="utf-8">
	<title>Flexible Box Model Example One</title>
	<style type="text/css">
		html, body {
			margin: 0px;
			padding: 0px;
			font: normal 14px/16px Helvetica, Sans-serif;
		}
		header {
			/* The following line is for Firefox */
			width: 100%;
			padding: 5px 0px;
			background-image: -moz-linear-gradient(top, #b0bccd, #889bb3 50%, #8195af 50%, #6d84a2); 
			background-image: -webkit-gradient(linear, left top, left bottom, from(#b0bccd), color-stop(0.5, #889bb3), color-stop(0.5, #8195af), to(#6d84a2));
		}
		.button
		{
			color: #fff;
			text-decoration: none;
			display: block;
			padding: 4px 10px;
			-webkit-border-radius: 5px;
			-moz-border-radius: 5px;
			font: normal 14px/16px Helvetica, Arial, sans-serif;
			cursor: pointer;
		}
		
		.button.black {
			background-image: -webkit-gradient(linear, left top, left bottom, 	
				from(#7d828c),
				color-stop(0.5, #303749), 
				color-stop(0.5, #121a2e), 
				to(#121a2e));
			background-image: -moz-linear-gradient(top, #7d828c, #303749 50%, #121a2e 50%, #121a2e);
			border: solid 1px rgba(79, 79, 79, 0.75);
		}
		.button.black:hover {
			background-image: -webkit-gradient(linear, left top, left bottom, 
				from(#4286f5), 
				color-stop(0.5, #4286f5),
				color-stop(0.5, #194fdb),
				to(#194fdb));
			
			background-image: -moz-linear-gradient(top, #4286f5, #4286f5 50%, #194fdb 50%, #194fdb);
		}
		.button.back {
			margin-left: 20px;
		}
		.button.next {
			margin-right: 20px;
		}
	</style>
</head>
<body>
	<article>
		<header>
			<a class="button black back">Back</a>
			<a class="button black next">Next</a>
		</header>
	</article>
</body>
</html>

This will give us a layout like this:
Initial setup for a header tag that will use the flexible box model

Now we’ll add the magic. All we have to do is give the header tag a definition of display: box, then tell it which orientation to arrange its child elements and how to pack them in. We just need to add these properties to the header tag’s CSS:

display: -webkit-box;
-webkit-box-orient: horizontal;
-webkit-box-pack:justify;
display: -moz-box;
-moz-box-orient: horizontal;
-moz-box-pack:justify;

By telling the browser to pack the child elements with justification, the browser takes all the space not occupied by the buttons and spreads it out between them. This works as expected in all Webkit based browsers. Unfortunately, although Firefox has implemented every other feature of the flexible box model, they have not as yet implemented the box-pack: justify property. It’s listed on their developer site with a question mark: https://developer.mozilla.org/en/CSS/-moz-box-pack

In the next section of this post I’ll introduce a technique that requires some extra markup that will make this work in Firefox too. For now, here is how this looks in Webkit:
Header tag with buttons aligned at both end using the flexible box model

You can see it in action, or download the document.

Adding Centered Content With Dynamic Width

Now we’ll look at how to add a title into our heading. Since we already have two buttons at either end, we’ll want our title to be centered. We’ll add an h1 tag to the header directly between the two buttons:

<body>
	<article>
		<header>
			<a class="button black back">Back</a>
			<h1>Home Base</h1>
			<a class="button black next">Next</a>
		</header>
	</article>
</body>

We also need to give the h1 some suitable styling. We’re going to make it white with an indented look using a text shadow:

h1 {
	font: bold 21px/21px Helvetica, Arial, Sans-serif;
	text-shadow: 0px -1px 0px rgba(0, 0, 0, 0.5);
	color: #fff;
	margin: 0px;
	-moz-box-flex: 1;
	text-align: center;
}

This gives us the following in Webkit:
Buttons on either end and title centered

Unfortunately, Firefox still needs a couple more lines of code to get it right. Here’s what we have at the moment:
Firefox having problems implementing the flexible box model

There is one more flexible box model property that we can apply to the h1 so that Firefox will display it as we want, that is box-flex. If we give this property a value of one, it tells the browser to have that elements width the equivalent of all left over space from whatever other sibling elements are in the same parent tag. We’ll also need to apply text-alignment to center the text:

h1 {
	font: bold 21px/21px Helvetica, Arial, Sans-serif;
	text-shadow: 0px -1px 0px rgba(0, 0, 0, 0.5);
	color: #fff;
	margin: 0px;
	-moz-box-flex: 1;
	text-align: center;
}

Now Firefox display the header as we want:
h1 { 	font: bold 21px/21px Helvetica, Arial, Sans-serif; 	text-shadow: 0px -1px 0px rgba(0, 0, 0, 0.5); 	color: #fff; 	margin: 0px; 	-moz-box-flex: 1; 	text-align: center; }

You can check out the finished page, or download it.

Update: October 5, 2010

I’ve update these buttons to use subpixel rendering. You can read about the technique here. You can try this out online or download the source code.

Follow

Get every new post delivered to your Inbox.

Join 44 other followers