memonic

1 12/2011 Creating Custom Font Stacks with Unicode-Range

Save

1 12/2011 Creating Custom Font Stacks with Unicode-Range

by Drew McLellan

Any web designer or front-end developer worth their salt will be familiar with the CSS @font-face rule used for embedding fonts in a web page. We’ve all used it — either directly in our code ourselves, or via one of the web font services like Fontdeck, Typekit or Google Fonts.

If you’re like me, however, you’ll be used to just copying and pasting in a specific incantation of lines designed to get different formats of fonts working in different browsers, and may not have really explored all the capabilities of @font-face properties as defined by the spec.

One such property — the unicode-range descriptor — sounds pretty dull and is easily overlooked. It does, however, have some fairly interesting possibilities when put to use in creative ways.

Unicode-range

The unicode-range descriptor is designed to help when using fonts that don’t have full coverage of the characters used in a page. By adding a unicode-range property to a @font-face rule it is possible to specify the range of characters the font covers.

@font-face {
    font-family: BBCBengali;
    src: url(fonts/BBCBengali.ttf) format("opentype");
    unicode-range: U+00-FF;
}

In this example, the font is to be used for characters in the range of U+00 to U+FF which runs from the unexciting control characters at the start of the Unicode table (symbols like the exclamation mark start at U+21) right through to ÿ at U+FF – the extent of the Basic Latin character range.

By adding multiple @font-face rules for the same family but with different ranges, you can build up complete coverage of the characters your page uses by using different fonts.

When I say that it’s possible to specify the range of characters the font covers, that’s true, but what you’re really doing with the unicode-range property is declaring which characters the font should be used for. This becomes interesting, because instead of merely working with the technical constraints of available characters in a given font, we can start picking and choosing characters to use and selectively mix fonts together.

The best available ampersand

A few years back, Dan Cederholm wrote a post encouraging designers to use the best available ampersand. Dan went on to outline how this can be achieved by wrapping our ampersands in a <span> element with a class applied:

<span class="amp">&amp;</span>

A CSS rule can then be written to select the <span> and apply a different font:

span.amp {
    font-family: Baskerville, Palatino, "Book Antiqua", serif;
}

That’s a perfectly serviceable technique, but the drawbacks are clear — you have to add extra markup which is borderline presentational, and you also have to be able to add that markup, which isn’t always possible when working with a CMS.

Perhaps we could do this with unicode-range.

A better best available ampersand

The Unicode code point for an ampersand is U+26, so the ampersand font stack above can be created like so:

@font-face {
    font-family: 'Ampersand';
    src: local('Baskerville'), local('Palatino'), local('Book Antiqua');
    unicode-range: U+26;
}

What we’ve done here is specify a new family called Ampersand and created a font stack for it with the user’s locally installed copies of Baskerville, Palatino or Book Antiqua. We’ve then limited it to a single character range — the ampersand. Of course, those don’t need to be local fonts — they could be web font files, too. If you have a font with a really snazzy ampersand, go for your life.

We can then use that new family in a regular font stack.

h1 {
    font-family: Ampersand, Arial, sans-serif;
}

With this in place, any <h1> elements in our page will use the Ampersand family (Baskerville, Palatino or Book Antiqua) for ampersands, and Arial for all other characters. If the user doesn’t have any of the Ampersand family fonts available, the ampersand will fall back to the next item in the font stack, Arial.

You didn’t think it was that easy, did you?

Oh, if only it were so. The problem comes, as ever, with the issue of browser support. The unicode-range property has good support in WebKit browsers (like Safari and Chrome, and the browsers on most popular smartphone platforms) and in recent versions of Internet Explorer. The big stumbling block comes in the form of Firefox, which has no support at all.

If you’re familiar with how CSS works when it comes to unsupported properties, you’ll know that if a browser encounters a property it doesn’t implement, it just skips that declaration and moves on to the next. That works perfectly for things like border-radius — if the browser can’t round off the corners, the declaration is skipped and the user sees square corners instead. Perfect.

Less perfect when it comes to unicode-range, because if no range is specified then the default is that the font is applied for all characters — the whole range. If you’re using a fancy font for flamboyant ampersands, you probably don’t want that applied to all your text if unicode-range isn’t supported. That would be bad. Really bad.

Ensuring good fallbacks

As ever, the trick is to make sure that there’s a sensible fallback in place if a browser doesn’t have support for whatever technology you’re trying to use. This is where being a super nerd about understanding the spec you’re working with really pays off.

We can make use of the rules of the CSS cascade to make sure that if unicode-range isn’t supported we get a sensible fallback font. What would be ideal is if we were able to follow up the @font-face rule with a second rule to override it if Unicode ranges aren’t implemented.

@font-face {
    font-family: 'Ampersand';
    src: local('Baskerville'), local('Palatino'), local('Book Antiqua');
    unicode-range: U+26;
}
@font-face {
    font-family: 'Ampersand';
    src: local('Arial');
}

In theory, this code should make sense for all browsers. For those that support unicode-range the two rules become cumulative. They specify different ranges for the same family, and in WebKit browsers this has the expected result of using Arial for most characters, but Baskerville and friends for the ampersand. For browsers that don’t have support, the second rule should just supersede the first, setting the font to Arial.

Unfortunately, this code causes current versions of Firefox to freak out and use the first rule, applying Baskerville to the entire range. That’s both unexpected and unfortunate. Bad Firefox. On your rug.

If that doesn’t work, what can we do? Well, we know that if given a unicode-range Firefox will ignore the range and apply the font to all characters. That’s really what we’re trying to achieve. So what if we specified a range for the fallback font, but made sure it only covers some obscure high-value Unicode character we’re never going to use in our page? Then it wouldn’t affect the outcome for browsers that do support ranges.

@font-face {
    font-family: 'Ampersand';
    src: local('Baskerville'), local('Palatino'), local('Book Antiqua');
    unicode-range: U+26;
}
@font-face {
    /* Ampersand fallback font */
    font-family: 'Ampersand';
    src: local('Arial');
    unicode-range: U+270C;
}

By specifying a range on the fallback font, Firefox appears to correctly override the first based on the cascade sort order. Browsers that do support ranges take the second rule in addition, and apply Arial for that obscure character we’re not using in any of our pages — U+270C.

So we get our nice ampersands in browsers that support unicode-range and, thanks to our styling of an obscure Unicode character, the font falls back to a perfectly acceptable Arial in browsers that do not offer support. Perfect!

That obscure character, my friends, is what Unicode defines as the VICTORY HAND.

So, how can we use this?

Ampersands are a neat trick, and it works well in browsers that support ranges, but that’s not really the point of all this. Styling ampersands is fun, but they’re only really scratching the surface. Consider more involved examples, such as substituting a different font for numerals, or symbols, or even caps. Things certainly begin to get a bit more interesting.

How do you know what the codes are for different characters? Richard Ishida has a handy online conversion tool available where you can type in the characters and get the Unicode code points out the other end.

Of course, the fact remains that browser support for unicode-range is currently limited, so any application needs to have fallbacks that you’re still happy for a significant proportion of your visitors to see. In some cases, such as dedicated pages for mobile devices in an HTML-based phone app, this is immediately useful as support in WebKit browsers is already very good. In other cases, you’ll have to use your own best judgement based on your needs and audience.

One thing to keep in mind is that if you’re using web fonts, the entire font will be downloaded even if only one character is used. That said, the font shouldn’t be downloaded if none of the characters within the Unicode range are present in a given page.

As ever, there are pros and cons to using unicode-range as well as varied but increasing support in browsers. It remains a useful tool to understand and have in your toolkit for when the right moment comes along.

Like what you read?

Spritebaker - Ridiculous easy Base64 encoding for Designers

Save

A free tool for designers and web developers. It parses your css and returns a copy with all external media "baked" right into it as Base64 encoded datasets. The number of time consuming http-requests on your website is decreased significantly, resulting in a massive speed-boost (server-side gzip-compression must be enabled).

CSS Grid Alignment Level 3

Save

CSS Grid Alignment Level 3

W3C Editor's Draft 26 October 2010

Abstract

CSS Grid Alignment Level 3 contains features that enable authors to align UI elements horizontally and vertically. By using the features in this module authors can position layout elements such as controls and application content into columns and rows, defining a grid structure with fixed, fractional, or automatic units. The elements can then be positioned and sized into the logical cells of the grid. Further, this module enables stacking and spanning of elements to build cohesive experiences out of a collection of modular UI pieces.

CSS Grid Alignment Level 3 also helps to manage changes in available space for layout. For example, the features in this module can help manage changes by allowing placement of elements in the grid independent of source order. Such management may be required when a browser window is resized or when a screen's aspect ratio changes, due to screen rotation.

2. Introduction

2.1 Basic Capabilities of the Grid

Image: Application layout example requiring horizontal and vertical alignment.

Application layout example requiring horizontal and vertical alignment.

As websites evolved from simple documents into complex, interactive applications, tools for document layout (e.g. floats) were not necessarily well suited for layout of applications. By using a combination of tables, JavaScript, or careful measurements on floated elements, authors discovered workarounds to achieve a desired layout. Layouts that adapted to the available space were often brittle and resulted in counter-intuitive behavior as space became constrained. As an alternative, authors of many web applications opted for a fixed layout that cannot take advantage of changes in the available rendering space on a screen.

CSS Grid Alignment Level 3 provides layout capabilities to address these problems. The Grid element provides a mechanism for authors to divide available space for layout into regions by using a set of predictable sizing behaviors which are assigned to the columns and rows of the Grid. The regions defined by the columns and rows serve as anchor points for the author to place the building block elements of their application. These anchor points maintain their positions relative to other anchors in accordance with the sizing behaviors that the author assigned to the columns and rows of the Grid element. Figure 1 illustrates a basic layout of a Grid.

2.2 Adapting to Available Space for Layout

Image: Five grid items arranged according to content size and available space.

Five grid items arranged according to content size and available space.

Image: Growth in the grid due to an increase in available space.

Growth in the grid due to an increase in available space.

The Grid element can be used to intelligently reflow elements within a webpage. Figure 2 represents a game with five major areas in the layout: the game title, stats area, game board, score area, and control area. The author's intent is to divide the space for the game such that:

  • the stats area always appears immediately under the game title.
  • the game board appears to the right of the stats and title.
  • the top of the game title and the game board should always align.
  • the bottom of the game board and the stats area align when the game has reached its minimum height, but otherwise the game board will stretch to take advantage of all the screen real-estate available to it.
  • the score area should align into the column created by the game and stats area, while the controls are centered under the board.

As an alternative to using script to control the absolute position, width, and height of all elements, the author can use the Grid element, as shown in Figure 3. The following example allows the author to achieve all the sizing, placement, and alignment rules declaratively.

<style type="text/css">
    #grid     { grid-columns: auto minmax(min-content, 1fr); 
                grid-rows: auto minmax(min-content, 1fr) auto
              }
    #title    { grid-column: 1; grid-row: 1 }
    #score    { grid-column: 1; grid-row: 3 }
    #stats    { grid-column: 1; grid-row: 2; grid-row-align: start }
    #board    { grid-column: 2; grid-row: 1; grid-row-span: 2 }
    #controls { grid-column: 2; grid-row: 2; grid-column-align: center }
</style>

<div id="grid">
    <div id="title">Game Title</div>
    <div id="score">Score</div>
    <div id="stats">Stats</div>
    <div id="board">Board</div>
    <div id="controls">Controls</div>
</div>

2.3 Source Independence

Image: An arrangement suitable for 'portrait' orientation.

An arrangement suitable for 'portrait' orientation.

Image: An arrangment suitable for 'landscape' orientation.

An arrangment suitable for 'landscape' orientation.

Continuing the prior example, the author also wants the game to be as enjoyable as possible for traditional computer monitors, handheld devices, or tablet computers. The game should therefore optimize the placement of the components when viewed either in landscape or portrait orientation (Figures 4 and 5). By combining the CSS markup for the Grid element with media queries, the author is able to use the same HTML markup, but rearranged independent of its source order, to achieve the desired layout in both landscape and portrait modes. The following example shows the markup that achieves optimization for the different screen orientations.

<style type="text/css">
    @media (orientation: landscape) {
        #grid     { grid-columns: auto minmax(min-content, 1fr); 
                    grid-rows: auto minmax(min-content, 1fr) auto
                  }
        #title    { grid-column: 1; grid-row: 1 }
        #score    { grid-column: 1; grid-row: 3 }
        #stats    { grid-column: 1; grid-row: 2; grid-row-align: start }
        #board    { grid-column: 2; grid-row: 1; grid-row-span: 2 }
        #controls { grid-column: 2; grid-row: 2; grid-column-align: center }
    }
    @media (orientation: portrait) {
        #grid     { grid-columns: auto minmax(min-content, 1fr); 
                    grid-rows: auto auto minmax(min-content, 1fr) auto
                  }
        #title    { grid-column: 1; grid-row: 1 }
        #score    { grid-column: 1; grid-row: 2 }
        #stats    { grid-column: 2; grid-row: 1; grid-row-span: 2 }
        #board    { grid-column: 1; grid-row: 3; grid-column-span: 2 }
        #controls { grid-column: 1; grid-row: 4; grid-column-span: 2; grid-column-align: center }
    }
</style>

<div id="grid">
    <div id="title">Game Title</div>
    <div id="score">Score</div>
    <div id="stats">Stats</div>
    <div id="board">Board</div>
    <div id="controls">Controls</div>
</div>

2.4 Grid Layering of Elements

Image: A control composed of layered HTML elements.

A control composed of layered HTML elements.

In the example shown in Figure 6, the author is creating a custom slider control. The control has six parts. The lower and upper labels align to the left and right edges of the control. The track of the slider spans the area between the labels. The lower and upper fill parts touch beneath the thumb, and the thumb is a fixed width and height that can be moved along the track by updating the two fraction-sized columns.

Prior to the Grid element, the author would have likely used absolute positioning to control the top and left coordinates, along with the width and height of each HTML element that comprises the control. The z-index CSS property would have been used to control element drawing order. By leveraging the Grid element, the author can instead limit script usage to handling mouse events on the thumb, which snaps to various positions along the track as the grid-column CSS property of the Grid element is updated. The Grid element's grid-layer CSS property provides capabilities which are analagous to z-index.

<style type="text/css">
    #grid        { grid-columns: auto 0.5fr auto auto 0.5fr auto }
    #lower-label { grid-column: 1; grid-row-align: center }
    #upper-label { grid-column: 6; grid-row-align: center }
    #track       { grid-column: 2; grid-row-align: center}
    #lower-fill  { grid-column: 2; grid-column-span: 2; grid-row-align: center; grid-layer: 5 }
    #upper-fill  { grid-column: 4; grid-column-span: 2; grid-row-align: center; grid-layer: 5 }
    #thumb       { grid-column: 3; grid-column-span: 2; grid-layer: 10 }
</style>

<div id="grid">
    <div id="lower-label">Lower Label</div>
    <div id="upper-label">Upper Label</div>
    <div id="track">Track</div>
    <div id="lower-fill">Lower Fill</div>
    <div id="upper-fill">Upper Fill</div>
    <div id="thumb">Thumb</div>
</div>

Generate CSS Sprites on the Fly with Lemonade

Save
Lemonade—a Sass sprite generator

Generate CSS Sprites
on the Fly with Lemonade

Lemonade’s goal as a sprite generator is to be incredible easy to use, so you’ll use ist for every project—just because there’s no overhead. It needs no configuration, no Rake task, no Photoshop, just a little change in your Sass or SCSS files. All you need to write is:

background: sprite-image("icons/home.png");

This will generate a sprite icons.png, insert the url(…) and calculate the background-position. On the fly. Everytime your Sass/SCSS file will be compiled.

504 KB

Ingredients: Pure Ruby, Sass, Compass, RMagick, No artificial flavors or sugar added.

Gemmed under the MIT licence with jeweler by Nico Hagenburger, Berlin/Germany.

Spcial thanks to Chris Eppstein.

Best served—Ice cold

Source (SCCS or Sass):

.logo {
  background: sprite-image("lemonade/lemonade-logo.png");
}
.lime {
  background: sprite-image("lemonade/lime.png");
}
.coffee {
  background: sprite-image("other-drinks/coffee.png") no-repeat;
}

Result (CSS):

.logo {
  background: url('/images/lemonade.png');
}
.lime {
  background: url('/images/lemonade.png') 0 -26px;
}
.coffee {
  background: url('/images/other-drinks.png') no-repeat;
}

Examples

#1 Use an Offset for the Background-Position

You can provide an offset as 2nd (X) and 3rd (Y) parameter. The will be added to the calculated sprite background offset:

.lemonade-example-1 {
  background: sprite-image("lemonade/example-1/blue-10x10.png", 10px, 2px) yellow no-repeat;
}

Result:

Some text

Generated sprite image: sprite image

#2 Space Between Sprite Images

Example #1 works well just because there’s only one image in the sprite. With two images, you would see a part of the other images (here the pink one) like this:

Some text

Generated image: sprite image

To avoid this, you can add a 4th parameter which generates transparent space between the sprite images. The 4th sets the space before and after the current image. If you set both, th 4th creates space before, the 5th space after.

.lemonade-example-2-b {
  background: sprite-image("lemonade/example-2-b/blue-10x10.png", 20px, 9px, 20px) yellow no-repeat;
}

Some text

Generated image: sprite image
Please note the 20px transparent space between pink and blue.

Installation

I’ve tested it with both Ruby 1.8.7 and 1.9.2. It works with Haml/Sass 3.0.x. But it depends on Compass 0.10.x. You can integrate it in Rails 2.3.x and 3.0, Staticmatic or just run compass watch.

gem install lemonade

Now open your config.rb (Compass cofiguration file) and add one line after this comment:

# Require any additional compass plugins here.
require "lemonade"

Development, Support, Bugs

If you find any bug, please quote it at github. If you want to fix it by yourself, fork my project and send me a pull request.

You’ll find the source code at: http://github.com/hagenburger/lemonade Feel free to fork!

Have fun :)

Further Stuff

A Specialized JavaScript Library for Querying CSS

Save

A Specialized JavaScript Library for Querying CSS

by James Edwards

Some faintly-written CSS on leaf-patterned paper, tied with string in the corner.

For the last few months I’ve been beavering away on a fascinating project, that’s now finally seen the light of day! It’s called CSSUtilities, and it’s a specialized JavaScript library for querying CSS style sheets.

Perhaps the most unique thing about it is that can give you non-normalized properties information — in other words, you can get the colors and dimensions that apply to an element in the original unit they were specified with, rather than the normalized values you get from built-in query methods like getComputedStyle or even from the CSSStyleSheet interface.

There are scores of examples of this in all browsers, but to cite a few: Firefox normalizes most color values to RGB, when you might have originally defined them in hex or as color names; Opera normalizes colors to 6-digit hex; Internet Explorer splits-up margin properties, so even though you may have defined a single shorthand, it will return separate values for each direction.

But when you’re working with the CSSUtilities library, you get back exactly what was specified, and this makes it possible to work with dynamic styles in a way that was previously impossible — for example, when you’re reading the width of an element you always get a value in px, but now you can get its width in em or % that you can then apply to a clone, giving it exactly the same scaling or resizing characteristics as the original.

Some of the other things it can do include: listing all the rules that apply to a specified element, telling you the properties it inherits, or the media they apply to, or the specificity of any selector. It can tell you basically everything, about every rule in every style sheet.

I hope that many people will find it useful and that it spawns the development of some new and interesting applications and tools; I’ve made a few demos you can check-out at http://www.brothercake.com/scripts/cssutilities … perhaps they’ll inspire you to try something!

And in fact you can already see CSSUtilities in the wild, because a pre-release version powers the CSS inspection interface in CodeBurner for Adobe AIR, Opera Widgets and Mac OS X Dashboard. Their ability to extract and analyze style sheets, list their rules, and give you information about each one’s properties and selectors — all of that functionality is powered by CSSUtilities, and it’s the only thing that makes that possible — There simply isn’t anything else available to unprivileged code that can do the same job.

The only reason Firebug can give you this information is because it can call on Firefox’s dom-utilities class to tell it the rules that apply to the element you’re inspecting, but of course that’s only available in Firefox to privileged scripts like add-ons (and it’s still normalized data, not necessarily what the author originally specified). One of the demos I made is a Live CSS Inspector, that lays-out rules in a similar format; and it works in all browsers — even IE6!

So please do check it outhave a browse through the demos … let us know what you think (or if you find any bugs … hopefully unlikely, but always possible!). But most of all, I’d really love to hear your ideas for any tools or applications that could use it. I confess that I’m very excited about the possibilities; I haven’t had so much fun with DOM CSS since querySelectorAll came along :-)

Recreating the button

Save

Recreating the button

Until some future version of HTML gives us new native controls to use in a browser, at Google, we’ve been playing and experimenting with controls we call “custom buttons” in our apps (among other custom controls). These buttons just launched in Gmail yesterday, and they’ve been in Google Reader for two months now. The buttons are designed to look very similar to basic HTML input buttons. But they can handle multiple interactions with one basic design. The buttons we’re using are imageless, and they’re created entirely using HTML and CSS, plus some JavaScript to manage the behavior. They’re also easily skinnable with a few lines of CSS, which was a key factor now that Gmail has themes.

Gmail buttons

I thought it would be interesting to provide a portion of the background on our buttons here, and discuss some of the iterations we’ve been through so far to get to the current state.

Background

Today’s web apps allow increasingly complex interactions. Users can view, create, manage, and manipulate all kinds of data, from email messages to feeds to photos to blog posts, or even choosing what their DVR records on any given night. We’re at the point where these apps need something beyond standard HTML form controls and basic hypertext links to represent the actions a user can take.

A basic <input type="submit"> could be used for single actions, a <select> element could be used for a compact menu of actions, and <input type="radio"> could be used for selecting mutually exclusive options. But we’re left with no way to represent other interactions common in desktop apps. Such as a checkbox that represents more than just on or off. Or the use of auto-complete to refine or narrow the options in a drop-down menu. On top of this, the controls we can render have significantly different appearances across browsers and platforms. Even within a single browser, buttons and select menus have quite different designs.

Enter: the concept of custom buttons.

The first iteration

Not long after I started at Google, I remember seeing mockups for a new product that eventually become Google Spreadsheets. The mockups I saw used simple buttons that looked similar to default HTML buttons in certain browsers. But they were subtly different than any default buttons I had ever seen before. The giveaway was seeing three buttons sandwiched together to make a pill button:

Spreadsheet buttons

At first, I thought they were just generic browser-agnostic representations — and wishful thinking for the appearance — of actual HTML buttons. But once we started using an internal-only version of the product, I realized this button design actually got built into the product. That was fine. But I cringed when I realized how the buttons had been implemented. Each button was set up with a nine-cell table so they could place each corner image, and still allow the button to expand in all four directions according to the width and height of the text inside:

nine-cell table

Eliminating the table and corner images

button 2.0 I knew there had to be a better way to render these buttons than using tables, and especially nine-cell tables just for the tiny little corners. So I tried creating a few prototypes to improve our button code. My first button attempt, which I named Custom Buttons 2.0, (version 1.0 would be the nine-cell tabled version done by one of our engineers) used a similar trick that I used for event chips in Google Calendar: the top border was one element with 1px left and right margins, the middle of the button was another element with left and right borders, and the bottom border recycled the styles of the top border with 1px left and right margins. This created a one-pixel notch in each of the four corners, giving the subtle illusion of a small rounded corner.

That 2.0 attempt was fine, and worked pretty well (as I expected) in almost all browsers. But it required that each button as a whole either be floated or positioned absolutely with a width. I wanted a set of buttons that could be treated as inline elements, and that would take up as much horizontal space as the text inside each button needed.

Going inline

My 3.0 attempt relied on treating the buttons and everything inside them as inline elements. The top/bottom borders still needed to be rendered separately from the left/right borders to get 1px-notched corners. The left/right borders were rendered on the outer element. The top/bottom borders were rendered on the inner element. Because borders don’t compound and add to the width or height of an inline element, we get the 1px notches in each corner. I ran into a lot of frustration with this inline approach until I remembered display: inline-block. That seemed to solve everything at once.

Demo page for Custom Buttons 3.0 A demo page for Custom Buttons 3.0 shows my progress to this point. As you can see there, I built in affordances for changing the border color on hover, and for reversing the gradient direction for the active/click state to make it feel like the button is actually pressable. I also attempted to show how we could sandwich multiple buttons together to form a pill button. The pill button wasn’t perfect — I didn’t want gaps in the top/bottom borders between each button. But it was a start.

The magical inline-block solved everything, except in IE. That’s where the genius of Google engineers came in. They knew how to get tricks working in all browsers, and this technique interested a couple of them enough that they dedicated the time to make it work.

So 3.0 buttons were fine. After some modifications by our engineers, they made it into live production code. I believe 3.0 buttons are currently still in use for edit buttons in Google Sites, and in editor modes for Google Docs. (As of this writing. Expect those to change in the near future to buttons described below.) But I was still bothered by the requirement of a background gradient image. Not only was this an extra request to the server, but if anyone wanted to change the colors of a button, they’d be required to create a new gradient image. This wasn’t flexible enough, in my opinion, and I thought we could push further.

Eliminating the gradient image

Instead of rendering the gradient with an image, I thought we might be able to simulate a gradient with a few bands of color. With a few light grays laid beside each other that were close enough in value, we’d get something that looked like a gradient. With only two bands of color, I got a glossy-looking button with a sharp division between the two bands of color. Not what I wanted. Adding a third band of color between the first two colors blended each color together better. So three color bands it had to be.

To get that band of color and fake the gradient, I had to insert one more element in the button code. I chose <b> because it was short, and semantically, it didn’t mean anything. That element was absolutely positioned, so it could live inside the button and behind the text without affecting anything else. For the button itself, I used the almost-white #f9f9f9. For the <b> element I used #e3e3e3. The <b> element was absolutely positioned to the bottom of the button, and given a height of 40%. To get the middle band of color, I added a top border of #eee to the <b> element.

Another demo page for Custom Buttons 3.1 shows my attempt at getting this pseudo-gradient to work. It works in Firefox and Safari, and probably a few other modern browsers. But not everywhere. It was never perfect, and I don’t recommend using it in production code. Again, I couldn’t get this working right in IE. Google eng to the rescue again. To see the final code we ended up using in Gmail and Reader, you’ll have to reverse engineer the button code in one of those products.

Sweating the details

If we were going to undertake the task of recreating basic HTML form controls, we knew there were a lot of details that need to be accounted for and thought through. Like all the possible states of a button: resting, hover, focus, active, toggled-on, and disabled. There are also the accessibility ramifications of creating non-standard controls. I’m sure we haven’t factored in or solved every access issue yet. But engineers are working on that. Here’s a glimpse of the many states and types of buttons, along with the visual specs we had to think about and create if we were really going to replace default buttons and menus:

Visual spec for Custom Buttons 3.1

Major credit

I certainly didn’t create the concept of custom buttons at Google. Nor did I write the final code that made it into production. I merely initiated a couple steps to improve the methods we use to render custom buttons. My portion of the iteration is what’s documented here. There were many other steps in making these buttons a reality.

These buttons never would have made it into production code without the help of several Google engineers. One of the primary aids, Emil Eklund, helped fix a lot of my code for these custom buttons, and got it working in the browsers Gmail supports. He just posted an entry on the Official Gmail Blog yesterday about the label and folder-like functionality behind the new buttons in Gmail. Two developers (no longer at Google) also contributed heavily to the original button code: Ryan Carver and Greg Veen. They deserve huge props too.

Even more credit for the launch of these buttons in Gmail goes to one of the Gmail designers, Michael Leggett, who dreamed up all the fancy new functionality and interactions behind applying labels. Michael gave me lots of feedback and suggestions as we were building the original specs for 3.0 and 3.1 buttons. He also created countless iterations of the button interactions for Gmail, and endured numerous reviews and feedback cycles to finally get them launched in the product. If you like the new labeling menus in Gmail, Michael is the one to thank. The menus are especially slick if you use the new v and l keyboard shortcuts, along with auto-complete to apply labels (and even archive at the same time) without ever touching your mouse.

There are numerous other designers, developers, and engineers at Google who touched these buttons at one point or another. They all deserve credit too. I’ve only given props to four of the most prolific people who made these buttons a reality.

These buttons don’t permeate the entire Gmail or Reader interfaces yet for all browsers. (e.g. Compose view is still using default buttons for older WebKit browsers.) But now that these buttons are reusable components, expect to see us using them in more places throughout Google as we find good uses for them.