Type study: An all CSS button

February 10, 2011

This is part of a series of guest posts covering tips and tricks for working with fonts on the web. Today’s post was written by Dan Cederholm of SimpleBits.

A few years ago I gave a talk about why a button made a great place to bring in type from a branding element (such as a logo). My point was that if the type in your logo was an image, and stylish buttons were also often images, then why not align the fonts in both to bring some cohesiveness to the typography. This was probably four years ago, and we’ve come a long way since. Now, in certain situations, CSS can replace the inflexible image buttons we used in the past. Add on top of that the advances made in @font-face and you have yourself a powerful combination for creating a wide variety of interface elements that are reusable and will degrade well in older browsers.

The button is also a great place to showcase many of the new CSS3 properties in one place, which is another reason I’m particularly taken with buttons at the moment. Through the use of box-shadow, text-shadow, border-radius, and CSS gradients, we can create highly polished interface components that don’t require images. Check out the demos from Rogie King and Mark Otto to get a sense of how CSS3 can be used to add dimension to otherwise flat objects.

Let’s build a button, friends.

The markup

I’m going to use a hyperlink in this example, but the styles we’re going to add could just as easily be applied to a <button> or <input> element as well.

<a href="#" class="btn"><span>Press this!</span></a>

Notice the extra <span> element here. Don’t panic; we’ll use that to create an animated effect when pressing the button (more on that later). Trust me, this harmless extra element is worth it.

Adding the styles

Our first step is to add basic styles for background, color, and rounded corners to make this simple little link look more like a button.

.btn span {	
  display: inline-block;
  padding: 10px  20px;
  background: #3194c6;
  -webkit-border-radius: 8px;
  -moz-border-radius: 8px;
  border-radius: 8px;
}

I’m adding the vendor-prefixed border-radius properties for WebKit and Mozilla browsers, followed by the real, non-prefixed version for future-proofing. I’m also setting display: inline-block; on the link so that we can animate the clicking of the button later on.

A blue button with rounded corners that reads Press this!

Next, let’s hop on over to Typekit and choose a typeface for the button. As I mentioned earlier, buttons are a great place to reintroduce brand type, and with Typekit we can quickly and easily add a custom font here without using an image.

With the classic Cooper Black font chosen, and the simple Typekit scripts in place, I’ll now apply that font to the button style.

.btn span {	
  display: inline-block;
  padding: 10px  20px;
  font-family: "cooper-black-std-1", "cooper-black-std-2";
  background: #3194c6;
  -webkit-border-radius: 8px;
  -moz-border-radius: 8px;
  border-radius: 8px;
}

A blue button that reads Press this! in Cooper Black

This button is starting to become far more interesting.

For browsers that currently support it (WebKit and Mozilla), I’m going to override the background color with a CSS gradient that runs from the original blue to a slightly lighter blue. This will make the surface of the button appear slightly concave.

.btn span {	
  display: inline-block;
  padding: 10px  20px;
  font-family: "cooper-black-std-1", "cooper-black-std-2";
  background: #3194c6;
  background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#3194c6), to(#5bacd6));
  background: -moz-linear-gradient(#3194c6, #5bacd6);
  -webkit-border-radius: 8px;
  -moz-border-radius: 8px;
  border-radius: 8px;
}

(I recommend this handy tool to construct your gradient rules.)

Notice that we’ll keep the original solid background color prior to the gradient rules; browsers that don’t yet support CSS gradients will degrade to this solid color.

The same blue button, with a light blue to darker blue gradient background

To make the wonderfully-chunky Cooper Black text look as though it’s sunken into the button a bit, we’ll add a subtle text-shadow with a negative vertical value. That will create a darker shadow just above the text.

.btn span {	
  display: inline-block;
  padding: 10px  20px;
  font-family: "cooper-black-std-1", "cooper-black-std-2";
  text-shadow: 0 -1px 1px rgba(19,65,88,.8);
  background: #3194c6;
  background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#3194c6), to(#5bacd6));
  background: -moz-linear-gradient(#3194c6, #5bacd6);
  -webkit-border-radius: 8px;
  -moz-border-radius: 8px;
  border-radius: 8px;
}

The same button,  with a slight drop shadow applied to the text

So far, we’ve been adding styles to that inner <span> inside the hyperlink, but to finish off the styles that will make the button look three-dimensional, we’ll tack on a few rules to the outer <a> element itself.

.btn {		
  display: inline-block;
  -webkit-border-radius: 8px;
  -moz-border-radius: 8px;
  border-radius: 8px;
  -webkit-box-shadow:
    0 8px 0 #1a74a1,
    0 15px 20px rgba(0,0,0,.35);
  -moz-box-shadow:
    0 8px 0 #1a74a1,
    0 15px 20px rgba(0,0,0,.35);
  box-shadow:
    0 8px 0 #1a74a1,
    0 15px 20px rgba(0,0,0,.35);
}

I’m repeating the inline-block and border-radius rules here to match the <span>. To add dimension, I’m adding two box-shadows: one for the darker blue that creates the bottom portion of the button, and one for the shadow that the button casts on the white background. Multiple box-shadows can be strung together and delimited with commas in a single rule. Notice I’m adding the vendor-prefixed rules for WebKit and Mozilla, followed by the non-prefixed box-shadow property at the end.

And voilà. A three-dimensional button using CSS3, a custom embedded font via Typekit, and zero images. I think a tasty beverage is in order.

But wait, let’s make things even more interesting and enrich the experience here a bit by animating the button when it’s clicked. Again, we’ll lean on CSS3 to do the animating in browsers that support it, while safely degrading in browsers that don’t.

If we add two new declarations for the :active state (as the button is clicked), we can give the illusion that the button has been depressed.

.btn:active {	
  -webkit-box-shadow: 
    0 8px 0 #1a74a1,
    0 12px 10px rgba(0,0,0,.3);
  -moz-box-shadow: 
    0 8px 0 #1a74a1,
    0 12px 10px rgba(0,0,0,.3);
  box-shadow: 
    0 8px 0 #1a74a1,
    0 12px 10px rgba(0,0,0,.3);
}

.btn:active span {	
  -webkit-transform: translate(0, 4px);
  -moz-transform: translate(0, 4px);
  -o-transform: translate(0, 4px);
  transform: translate(0, 4px);
}

The first declaration adjusts the box-shadow on the <a> element: dimming it slightly and making it less pronounced (since when depressed, the button is shorter and will cast a smaller shadow).

The second declaration applies a translate transition on the <span> inside the <a>. Translate moves an element from its initial position on the page using x and y coordinates. Here, we’re simply moving the surface portion of the button down 4 pixels. The reason we’re using a transform — rather than say position or adjusting margins — is that we can also apply a transition to that transform, smoothing out the move with a bit of animation. Moving the <span> 4 pixels down hides 4 pixels of the darker box shadow on the <a> element and the effect is complete.

The final button, pressed down

Our last step is to add CSS transitions to smooth out both the shadow-dimming and the translate move. We’ll again use the appropriate vendor prefixes for all the capable browsers (WebKit, Mozilla, and Opera), plus the real properties for the future.

.btn {		
  display: inline-block;
  -webkit-border-radius: 8px;
  -moz-border-radius: 8px;
  border-radius: 8px;
  -webkit-box-shadow:
    0 8px 0 #1a74a1,
    0 15px 20px rgba(0,0,0,.35);
  -moz-box-shadow:
    0 8px 0 #1a74a1,
    0 15px 20px rgba(0,0,0,.35);
  box-shadow:
    0 8px 0 #1a74a1,
    0 15px 20px rgba(0,0,0,.35);
  -webkit-transition: -webkit-box-shadow .2s ease-in-out;
  -moz-transition: -moz-box-shadow .2s ease-in-out;
  -o-transition: -o-box-shadow .2s ease-in-out;
  transition: box-shadow .2s ease-in-out;
}

.btn span {	
  display: inline-block;
  padding: 10px  20px;
  font-family: "cooper-black-std-1", "cooper-black-std-2", Helvetica, Arial, sans-serif;
  line-height: 1;
  text-shadow: 0 -1px 1px rgba(19,65,88,.8);
  background: #3194c6;
  background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#3194c6), to(#5bacd6));
  background: -moz-linear-gradient(#3194c6, #5bacd6);
  -webkit-border-radius: 8px;
  -moz-border-radius: 8px;
  border-radius: 8px;
  -webkit-box-shadow: inset 0 -1px 1px rgba(255,255,255,.15);
  -moz-box-shadow: inset 0 -1px 1px rgba(255,255,255,.15);
  box-shadow: inset 0 -1px 1px rgba(255,255,255,.15);
  -webkit-transition: -webkit-transform .2s ease-in-out;
  -moz-transition: -moz-transform .2s ease-in-out;
  -o-transition: -o-transform .2s ease-in-out;
  transition: transform .2s ease-in-out;
}

Notice I’ve added two transition stacks here: one on the <a> element, which transitions the subtle shadow change, and one on the <span> element which smooths out the translate transform, making the button push a bit more realistic.

Check out the demo to see it in action! And next time you need to make a button, remember that it’s a great place to use CSS3 and web fonts. Go make a button that can’t wait to be pushed.

Avatar for Dan Cederholm

Dan Cederholm is the author of CSS3 for Web Designers, founder of SimpleBits (a tiny design studio), and co-founder and designer of Dribbble.com. He plays a mean ukelele.

This is part of a series of guest posts covering tips and tricks for working with CSS. These techniques, along with web fonts, make rich interactive sites achievable with simple and accessible standards-based markup and CSS. Today’s guest post was written by Andy Clarke, author of Hardboiled Web Design.

In this example we’ll use CSS3 two-dimensional transforms to add realism to a row of hardboiled private detectives’ business cards.

The final hardboiled result using CSS transforms

There are a number of transform properties we can use, including:

  • translate: moves an element horizontally and vertically
  • skew: distorts an element horizontally and vertically (not covered in this article)
  • rotate: rotates an element
  • scale: increases or decreases the size of an element

The basic syntax for transforms is simple:

transform: transform type(value);

There’s no getting away from the fact that CSS transforms are an emerging standard. But there’s already widespread support for them in contemporary browsers; Firefox, Google Chrome, Opera, and Safari have all implemented transforms using vendor-specific prefixes and Microsoft is soon to follow. For the transforms we’ll be covering in just a minute, we’ll need vendor-specific prefixes for Mozilla, Microsoft, Opera, and WebKit, followed by the W3C’s official transforms syntax. (From now on, I’ll use only the W3C’s official transforms syntax. I’ll leave it up to you to add the corresponding vendor-specific prefixes.)

.vcard {
  -webkit-transform: translateY(90px); 
  -moz-transform: translateY(90px);
  -ms-transform: translateY(90px);
  -o-transform: translateY(90px);
  transform: translateY(90px); 
}

Quite a fistful I know, but necessary, because these vendor-specific prefixes allow each browser maker to perfect their implementations as the standard develops. Two scripts make Hardboiled Web Design possible. First, selectivizr enables CSS3 selectors in older versions of Internet Explorer. Then, Modernizr tests a browser’s ability to render CSS3 two-dimensional transforms and adds class attribute values of csstransforms or no-csstransforms to the HTML element, depending on the result.

Setting up the HTML

Here we have four microformat hCards, each with its own set of values to describe a detective’s contact information. These act as styling hooks and enable our users to extract the data from each hCard more easily:

<div class="vcard">
  <h3 class="fn">The Fat Man</h3>
  <p>Private Investigation</p>
  <p>$50 a day plus expenses. By appointment only</p>
  <p>Dial: M for Murder</p>
</div>

<div class="vcard">
  <h3 class="fn org">Nick Jefferies</h3>
  <p><span class="role">Private eye</span> 
  <span class="tel">WA6-0089</span></p>
</div>

<div class="vcard">
  <h3 class="fn org">Shoes Clues</h3>
  <p>Finding the footprints they leave</p>
</div>

<div class="vcard">
  <h3 class="fn org">Hartless Dick</h3>
  <p class="role">Private investigations</p>
  <p>Dial <span class="tel">#333</span> for a quick fix</p>
</div>

Laying out the hCards

Let’s start by writing styles that will be common to every card. We’ll float each one to the left and give them identical dimensions:

.vcard {
  float: left;
  width: 300px; 
  height: 195px; 
}

Our next task is add individual background images to each card. But how? Remember there are no id attributes anywhere in our HTML?

The :nth-of-type pseudo-element selector targets an element based on its type and position in the document. Want to target the first, second, third, or fourth card, no matter where they appear in the document order? Not a problem. This makes :nth-of-type pseudo-element selectors one of CSS’s best-kept secrets:

.vcard:nth-of-type(1) {
  background-image: url(c01.jpg); 
}

.vcard:nth-of-type(2) {
  background-image: url(c02.jpg); 
}

.vcard:nth-of-type(3) {
  background-image: url(c03.jpg); 
}

.vcard:nth-of-type(4) {
  background-image: url(c04.jpg); 
}

As we only want the background images to show and not the HTML text, indent every element inside those cards to move them off-screen:

.vcard * {
  text-indent: -9999px; 
}

Just the cards, no text

The best way to learn transforms is to see them in action, so we’ll use scale, translate (move), rotate, and a combination of all three to adjust the size, position, and rotation of each card.

Transform ‘scale’

When we use the scale property, we make elements appear larger or smaller. By how much and on what axis is determined by a scaling factor, which can range between 0.99 and 0.01 to make an element smaller, or 1.01 and above to make it larger. A scaling factor of 1 maintains the intrinsic size of an element. You can scale elements along the horizontal (X) or vertical (Y) axis, or a combination of the two. Other elements remain unaware of a new size and so don’t reflow around it.

To vary the size of several hardboiled cards, we’ll scale them in two dimensions using the combined scale property. Scale the first card down to 80% (.8):

.csstransforms .vcard:nth-of-type(1) {
  transform: scale(.8); 
}

Next, increase the size of the second and third cards by 10% (1.1):

.csstransforms .vcard:nth-of-type(3),
.csstransforms .vcard:nth-of-type(4) {
  transform: scale(1.1); 
}

Transform ‘translate’

Moving elements with translate behaves in a similar way to relative positioning, where an element is offset visually but keeps its position in the document’s normal flow; translate moves elements on the x- and y-axes. We can specify how far they move by using pixels, ems, or percentages that are relative to the size of the element. We’ll translate each card along both the horizontal (X) and vertical (Y) axis:

.csstransforms .vcard:nth-of-type(1) {
  transform: scale(.8) translateY(90px); 
}

.csstransforms .vcard:nth-of-type(2) {
  transform: translate(150px, 60px); 
}

.csstransforms .vcard:nth-of-type(3) {
  transform: scale(1.1) translate(144px, 55px); 
}

Look carefully and you’ll notice that in that last example, we combined two transform values into a single declaration. To set multiple values, string them together and separate each with a space. A browser applies these transforms in order — reading from the left.

Laying the cards out with transforms

The space you see between the first and second cards is a perfect spot into which we can position the fourth and final card.

Transform ‘rotate’

We can rotate an element between 0 and 360 degrees (clockwise) and even use negative values to rotate an element counterclockwise. The syntax is quick to learn. First, declare the rotate value, then the angle inside parentheses. The fourth card’s artwork has a portrait orientation whereas all others are landscape. Fix this by rotating that errant card ninety degrees clockwise (90deg), scale it by 10% (1.1) and finally move it into position by translating it down 20px and left 630px:

.csstransforms .vcard:nth-of-type(4) {
  transform: scale(1.1) rotate(90deg) translate(20px, 630px); 
}

The last card in place

Embracing the natural differences between browsers

No two browsers are the same, so to make the most from emerging technologies such as HTML5 and CSS3, we need to banish the notion that websites should look and be experienced exactly the same in every browser. We should design around browser differences instead of hacking around them. That will likely mean that designs will look different — sometimes very different — across browsers.

To make this simple alternative, adjust each card’s margins to float them into a simple grid.

.no-csstransforms .vcard {
  margin: 0 20px 20px 0; 
} 

The graceful fallback styles

How adventurous your alternatives are depends on you, your clients, and the project you’re working on. Be under no illusion though: CSS3 selectors and properties give us the power to create designs that are tailored to browsers of all capabilities. With this variety comes new opportunities to show our creative skills and new opportunities for business. It’s time to grab those opportunities with both hands.

Avatar for Andy Clarke

Author of Hardboiled Web Design, Andy Clarke is a seasoned brand steward, a fancy pixel wrangler, and no mean hand at code. A triple talent. The bastard.

This is part of a series of guest posts covering tips and tricks for working with fonts on the web. Today’s post was written by Trent Walton of Paravel.

Lettering.js is a jQuery plugin for radical web typography. With all the exciting progress in the realm of web fonts, Lettering.js allows you to target specific letters, words, or lines within an element by wrapping them in spans, all while keeping the markup manageable. You can learn more about how and why Lettering.js was developed by reading Dave Rupert’s post, but here we’re going to walkthrough a use case, so let’s get going!

Screenshot of Cowpoke's website

I’ve built a quick webpage for a fictitious cowboy hat outfitter, set in LTC Bodoni, called Cowpoke’s Wide Brim Cowboy Hats. I’ve included jQuery and Lettering.js and have added a block of script to the <head>:

  $(document).ready(function(){
    $("#company").lettering();
    $(".hat-name").lettering('words');
    $("#footer-text").lettering('lines');
  });

We have Lettering.js applied to 3 elements on the page:

  • #company is the Cowpoke’s title, which is broken into letter spans such as .char1 and .char2
  • .hat-name is the name of each hat, broken into word spans such as .word1 and .word2
  • #footer-text is the “Hand Crafted” blurb at the bottom of the page, which is broken into line spans such as .line1 and line2

The Cowpoke title, after kerning; hover to see the title before it was kerned.

Let’s start with the Cowpoke’s title itself. The font size is set at 105px, and it could use a bit of kerning. Here’s the markup along with the corresponding CSS to tweak each O and the apostrophe:

<h1 id="company">Cowpoke&rsquo;s</h1>

<style type="text/css">
h1 .char2{margin-right: -6px;}	
h1 .char5{margin-right: -8px;}
h1 .char8{margin-right: -3px;}
</style>

Of course you could use relative positioning or margins to adjust every character, but in this case these few slight tweaks go a long way. It’s also worth noting that since each browser handles kerning differently, it will be necessary to test your results for the desired outcome.

Screenshot of the hats on the Cowpoke's site

Next, let’s take a look at the hat titles; the word “the” is set in italics, while the hat name is displayed in all caps. In the head, we’ve already told Lettering.js to target .hat-name for words, so all we’ve got to do is apply some style to this markup:

<h3 class="hat-name">The Rambler</h3>

<style type="text/css">
h3.hat-name .word1{text-transform: lowercase;font-style: italic;font-weight: normal;}
h3.hat-name .word2{font-weight: normal;text-transform: uppercase;}
</style>

Screenshot of Hand Crafted footer on Cowpoke's site

To wrap things up, we’ll target the “Hand Crafted” footer text. In this case, we’re using Lettering.js to break the following markup into spans for specific styling:

<p id="footer-text">Hand crafted<br /> from the finest quality fur felt<br /> Sure to outlast its owner

Lettering.js translates that into:

<p id="footer-text">
  <span class="line1">Hand crafted</span>
  <span class="line2">from the finest quality fur felt</span>
  <span class="line3">Sure to outlast its owner</span>
</p>

Now, we can add some CSS to stack and style those spans:

#footer-text .line1{
  font-size: 38px;
  text-transform: uppercase;
  display: block;
  letter-spacing: 4px;
}

#footer-text .line2{
  font-size: 21px;
  text-transform: lowercase;
  display: block;
  font-style: italic;
  margin-bottom: 6px;
}

#footer-text .line3{
  font-size: 13px;
  text-transform: uppercase;
  display: block;
  line-height: 24px;
}

There you have it. There are lots of ways Lettering.js can be put to good use. While it’s probably not something you’d apply to every element on every site you’re working on, it can come in handy — providing extra control whenever necessary. In the future, I can’t help but wonder if expanding CSS selector capabilities to yield similar results without Javascript would be sensible. In the meantime, download Lettering.js, build your kit, and get to experimenting!

Avatar for Trent Walton

Trent Walton is Founder and one-third of Paravel.
He blogs at http://trentwalton.com/.

This is the first in a series of guest posts covering tips and tricks for working with fonts on the web. Today’s guest post was written by Ryan Essmaker of Designing Monsters.

The redesign of Designing Monsters was heavily inspired by traditional newspaper layouts. The narrow column width, large headline text (in League Gothic), and serif body text (FF Tisa) all pay homage to classic newsprint.

Screenshot of the header on designingmonsters.com
The header on Designing Monsters.

The header and quote at the bottom of the site are set apart by a text shadow. This gives it a three-dimensional feel and emulates offset printing mishaps occasionally seen in newspapers.

To accomplish this I used the CSS3 text-shadow property. Actually, I used it twice: a white shadow sits atop a larger gray shadow:

h1 { 
  text-shadow: 2px 2px 0 #fff, 
  5px 5px 0 #bbb; 
  }

Closeup of the text shadow on Designing Monsters
A close-up of the two shadows in place.

In the text-shadow syntax, the first value is the horizontal offset, while the second value is the vertical offset. Offsets can be positive or negative. (You can use a negative offset to create the inset type effect that all the cool kids are using these days).

The third value sets the blur of the shadow. Blurs can get out of hand quickly, so use with caution. I chose not to blur the shadows in this case.

The fourth and final value is color. You could also use RGBA colors to set the opacity of the text-shadow, like so:

h1 { 
  text-shadow: 2px 2px 0 rgba(255, 255, 255, 1), 
  5px 5px 0 rgba(187, 187, 187, .75); 
  }

In this case, the gray shadow is set at .75 (or 75% opaque) which would allow the background to bleed through a bit.

If you choose this method, be sure to set an RGB fallback color for browsers that don’t support RGBA. Older browsers will use the RGB value and ignore RGBA.

h1 { 
  text-shadow: 2px 2px 0 rgb(255, 255, 255), 
  5px 5px 0 rgb(187, 187, 187);
  text-shadow: 2px 2px 0 rgba(255, 255, 255, 1), 
  5px 5px 0 rgba(187, 187, 187, .75);  
  }

Text-shadow is supported in Safari 1.1+, Chrome 2+, Firefox 3.1+, and Opera 9.5+. Unfortunately, Internet Explorer does not yet support text-shadow, even in the new IE9 beta. But the nice thing about text-shadow is that it doesn’t affect the layout so it degrades nicely in less capable browsers. Enjoy!

Avatar for Ryan Essmaker

Ryan Essmaker is the founder of Designing Monsters, a small design studio. He’s a sucker for good typography and well-written markup. In his spare time you can find him with camera in hand or strumming on the ole six-string.