Semantic Buttons

An obvious common trait of any web app landing page, download page, or any other website offering a product, are the large call-to-action buttons. I usually prefer beginning with a vague idea of a button style, and then code it all (or most) in CSS from the get-go. Button styles will always be subjective, and will need to be custom per website, color scheme, etc. One thing that doesn't change much is the markup and structure used.

Semantic Button Layout View Live Demo See the Code


As I said before, I prefer pure CSS buttons. Most everything a button needs can be done with CSS, with an exception of more unique and particular designs that code either isn't capable of or would be impractical to use for. A downside to using pure CSS, obviously, is backwards compatibility. I tend to design with this in mind, and keep basic user functionality intact on browsers that don't support CSS gradients, shadows, and the like. This means creating hover and click states what will (partially) gracefully degrade in way that also makes sense on old browsers.

Button Examples in the Wild

Dropbox Download Button Realmac Software Buy Buttons Button Wireframe

The above examples show the typical layout for a call-to-action button. Large button with centered content inside, descriptive text nearby with possible other links, and the ability to add things like tooltips to the existing code without breaking structure. Now, these examples use their own layout. If you were to go and view their source, I'm sure it would be very different. But, this is a pattern I have to build so often that I've sought out to make a standard structure of which I'll follow moving forward in development.

The Markup

<div class="btn-wrap">
	<div class="btn">
		<a href="#">Download Now</a>
		<p>For <a href="#">Mac</a> and <a href="#">Windows</a></p>

Here you see a button wrapper div class=btn-wrap From there, each a href button lives inside div class=btn. This gives us the ability to position a number of buttons in an area of our choice, with the option to exclude btn-wrap, and instead use the btn classes separate. Each div class=btn can also contain a paragraph, pre, div, etc of additional content relevant to the surrounding button. Marking it up in this way gives you complete control over text layout and styling, grouping multiple buttons, or using singular buttons without any descriptive text anywhere you want on the page.

Another important thing to consider is responsive layout. These buttons can either grow with the content inside them, or fill their parent container. This can be seen in the live demo as you resize the browser window to a mobile device's viewport size. With media queries, I've added a display property to the base btn class that makes it fill its container. There's also a btn-block class that can be added to make the child buttons display:block by default in a normal sized window.

The Sass

I used Sass's mixin and variable features to draw customizable CSS background gradients. I also made good use of class nesting and parent selecting, which you'll see more of in a moment. Not using Sass? Take a moment to check it out here.

Base Button Class

	display: inline-block;
	position: relative;
	margin:0 10px;
	text-align: left;
	vertical-align: top;

	& > a{
		display: block;
		position: relative;
		padding:0.8em 1.75em 0.7em;

        /* ---- BG Gradient Mixin ---- */
		$basecolor: #CCC;
		@include btn-gradient(top, $basecolor, 10%, 10%);

			@include btn-gradient(top, $basecolor, 15%, 10%);
			@include btn-gradient(top, $basecolor, 5%, 10%);


This is what makes up our button structure. We wrap the a href in div class=btn to control display and layout options, such as displaying them inline or block, floated or not, with margins and padding, etc. You'll notice I used the child combinator (greater-than sign) on my anchor. This is so that only the first anchor in the div is affected by the button styles, and that other descriptive text nearby can also have links without problem. Also, see that @include btn-gradient()? That's a Sass mixin, and it will be defined later.

Customizing Buttons

     /* Add unique background color and gradient styles */
	a{ $basecolor:#34A2FF; @include btn-gradient(top, $basecolor, 10%, 10%);
		&:hover{ @include btn-gradient(top, $basecolor, 15%, 10%); }
		&:active{ @include btn-gradient(top, $basecolor, 5%, 10%); }
	a{ $basecolor:#33BF39; @include btn-gradient(top, $basecolor, 10%, 10%);
		&:hover{ @include btn-gradient(top, $basecolor, 15%, 10%); }
		&:active{ @include btn-gradient(top, $basecolor, 5%, 10%); }

Here you see classes that can extend the original div class=btn to incorporate other colors and styles. In this case, we've got a blue and green button, both with their own hover and active states. Because of variable scope in Sass, we do have to @include the background gradient mixin again on hover and active states. If we didn't, the button would fall back on its original styles and the variable that is set in its default class.

The Background Gradient Sass Mixin

@mixin btn-gradient($dir, $basecolor, $hi, $lo){
	background-image: -webkit-linear-gradient($dir, lighten($basecolor, $hi), darken($basecolor, $lo));
	background-image: -moz-linear-gradient($dir, lighten($basecolor, $hi), darken($basecolor, $lo));
	background-image: -ms-linear-gradient($dir, lighten($basecolor, $hi), darken($basecolor, $lo));
	background-image: -o-linear-gradient($dir, lighten($basecolor, $hi), darken($basecolor, $lo));
	background-image: linear-gradient($dir, lighten($basecolor, $hi), darken($basecolor, $lo));

This mixin takes 4 arguments to create linear background gradients: Direction, Base Color, Hi, and Lo values for gradient intensity. The $hiand $lo variables are the percent at which $basecolor is lightened or darkened. lighten() and darken() are features of Sass.

This style is actually new to me. Up until now, I've used transparent gradients to get the effect I want, like this: background-image: linear-gradient(top, rgba(255,255,255,0.1), rgba(0,0,0,0.1) );

But, this method has some issues. Using transparent white and black means the button color can become slightly desaturated with higher opacity values. RGBA also isn't supported everywhere (but then again neither is linear-gradient). The new method I'm using takes the base color of the button, and creates a light and a dark starting and stopping point for the gradient. Sass takes care of figuring the color codes for me so I don't have to go back and fourth from image editors to find the right shade. It might sound lazy, but the colors tend to come out great.

Summing Up

After recently employing this method on the sites I build at work, I realized the buttons become very versatile and receptive to change in surrounding layout. I had to re-design a page header incorporating these buttons, and after swapping a few class names I had them laid out exactly how I needed them without redoing any CSS. While obviously the design will always change, I believe this code structure is very helpful. Please, share your thoughts with me on Twitter.