Create Back & Next Buttons with CSS3

Works with Safari, iPhone, iPad

Update: March 21, 2011

I’ve update the method of create “Back” and “Next” button without the need for any extra markup, such as the span tag used in post below. Instead I use a CSS technique to create the pointer through only CSS. Read the new post and checkout the new example.

In an earlier post about the iPad’s distinctive dropdown menus I devised a scheme for creating an angular pointer. Now I’m going to use the same technique to create back and next buttons using only CSS3. Unfortunately, Android and Google Chrome do not presently support image masks, so this only works with iPhone, iPad and the Safari desktop browser. If you wish to reproduce this look for Android or Chrome, you’ll need to use image pieces, or be satisfied with simpler button styles. Eventually the CSS3 image mask will be supported on Android and Chrome.

To make the backward/forward pointer on the buttons possible we will need to add some extra markup to the basic button. The markup will look like this:

<a href="#" class="button back black"><span></span>Back</a>
<a href="#" class="button next black"><span></span>Next</a>

You’ll notice the inclusion of the span in the two link buttons above. We’ll be styling these spans to be the left and right pointing part of our buttons. First we’ll start with the basic button styles. We’ll start with the styles for our button class:

.button {
	color: #fff;
	text-decoration: none;
	display: inline-block;
	padding: 4px 10px;
	-webkit-border-radius: 5px;
}

This class gives us some basic properties for all our button styles. I’m using a black class to enhance this with border and background styles. But I could just as easily create some other color scheme using a different class, like blue or gold. So, here’s the style definitions for the black class:

 .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));
	 border: solid 1px rgba(79, 79, 79, 0.75);
 }

We’ve given the button a border color that is slightly transparent using RGBA values. We also styled the background of the button using a CSS3 gradient. It starts at the top, stop half way and changes to another color, creating a chiseled or beveled look. We’ll also add in a bright blue hover effect for mouse-based systems:

.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));
}

This will give us a button with a hover state as indicated in the image below:
How the basic button class look with the addition of the black class.

As you can see, this creates a fairly slick looking button with a minimum of markup and can easily be adjust for other color schemes. We could also get fancy with the text by beveling it with an offset text shadow or give the button some depth with a box shadow.

Now let’s see how to create the pointer part that we need for back and next buttons. Because we’re using a basic, empty span, we can use the same span for either a back or next button, we just need to flip its styles to achieve the two effects.

Let’s do the back button first. First we need to do a little prep to the parent button. We’ll give it relative positioning because we’ll want to use absolute position on the span to move it into place. We’ll also want to change the default padding from 10px on the left to just 8. This is to balance out the space created by the back pointing part of the button the finished button.

.button.back {
	position: relative;
	padding-left: 5px;
	margin-left: 8px;
}

Now we’ll give the span some formatting styles and a matching background gradient. And, since we plan on rotating the span to the right and clipping off the right half, we only need a border on the left and bottom part of the span. Here’s the styles:

.back.black > span {
       display: block;
       height: 20px;
       width: 20px;
       background-image: -webkit-gradient(linear, left top, left bottom, 
              from(#7d828c),
              color-stop(0.5, #303749), 
              color-stop(0.5, #121a2e), 
              to(#121a2e));
       border-left: solid 1px rgba(79, 79, 79, 0.75);
       border-bottom: solid 1px rgba(79, 79, 79, 0.75);
}

Our styled span now looks like this:
Pointer span with gradient and borders

Since we’re going to rotate the span, we might as well realign the direction of the gradient so that it appears to be vertical. To do that we need to make it flow from left top to right bottom, creating a diagonal dragient:

.back.black > span {
       display: block;
       height: 20px;
       width: 20px;
       background-image: -webkit-gradient(linear, left top, right bottom, 
              from(#7d828c),
              color-stop(0.5, #303749), 
              color-stop(0.5, #121a2e), 
              to(#121a2e));
       border-left: solid 1px rgba(79, 79, 79, 0.75);
       border-bottom: solid 1px rgba(79, 79, 79, 0.75);
}

Now the span looks like this:

Pointer span with angled gradient

Next we’re going to rotate the span using -webkit-transform: rotate.

.back.black > span {
       display: block;
       height: 20px;
       width: 20px;
       background-image: -webkit-gradient(linear, left top, right bottom, 
              from(#7d828c),
              color-stop(0.5, #303749), 
              color-stop(0.5, #121a2e), 
              to(#121a2e));
       border-left: solid 1px rgba(79, 79, 79, 0.75);
       border-bottom: solid 1px rgba(79, 79, 79, 0.75);
      -webkit-transform: rotate(45deg);
}

This give us a rotated span:
Pointer span rotated 45 degrees.

.back.black > span {
       display: block;
       height: 20px;
       width: 20px;
       background-image: -webkit-gradient(linear, left top, right bottom, 
              from(#7d828c),
              color-stop(0.5, #303749), 
              color-stop(0.5, #121a2e), 
              to(#121a2e));
       border-left: solid 1px rgba(79, 79, 79, 0.75);
       border-bottom: solid 1px rgba(79, 79, 79, 0.75);
      -webkit-transform: rotate(45deg);
}

To get rid of the right half we’ll use a CSS3 image mask. But instead of using an actual image, we’ll use a CSS3 gradient. The gradient needs to go from black to transparent. To create the cut off effect we go from solid black halfway, stop, then go the rest of the way with full transparency. The syntax is fairly straightforward: -webkit-mask-image.

.back.black > span {
       display: block;
       height: 20px;
       width: 20px;
       background-image: -webkit-gradient(linear, left top, right bottom, 
              from(#7d828c),
              color-stop(0.5, #303749), 
              color-stop(0.5, #121a2e), 
              to(#121a2e));
       border-left: solid 1px rgba(79, 79, 79, 0.75);
       border-bottom: solid 1px rgba(79, 79, 79, 0.75);
      -webkit-transform: rotate(45deg);
      -webkit-mask-image: -webkit-gradient(linear, left bottom, right top, 
              from(#000000), 
              color-stop(0.5,#000000), 
              color-stop(0.5, transparent), 
              to(transparent));
}

The final, masked span now looks like this:
Masked pointer span

However, if we look at it inside of our regular button, it looks awful because of its rotation:

Since the parent button already has relative positioning, we just need to give the span absolute position with a left and top value to move it into place:

Back button with unpositioned pointer

.back.black > span {
       display: block;
       height: 20px;
       width: 20px;
       background-image: -webkit-gradient(linear, left top, right bottom, 
              from(#7d828c),
              color-stop(0.5, #303749), 
              color-stop(0.5, #121a2e), 
              to(#121a2e));
       border-left: solid 1px rgba(79, 79, 79, 0.75);
       border-bottom: solid 1px rgba(79, 79, 79, 0.75);
      -webkit-transform: rotate(45deg);
      -webkit-mask-image: -webkit-gradient(linear, left bottom, right top, 
              from(#000000), 
              color-stop(0.5,#000000), 
              color-stop(0.5, transparent), 
              to(transparent));
       position: absolute;
       left: -8px;
       top: 2px;
}

And here’s the finished button:
Completed back button

To create a next button, we can use the same button, but switch out a “next” class with all the values flipped to produce a button pointing the opposite way:

.back.black > span {
       display: block;
       height: 20px;
       width: 20px;
       background-image: -webkit-gradient(linear, left top, right bottom, 
              from(#7d828c),
              color-stop(0.5, #303749), 
              color-stop(0.5, #121a2e), 
              to(#121a2e));
       border-left: solid 1px rgba(79, 79, 79, 0.75);
       border-bottom: solid 1px rgba(79, 79, 79, 0.75);
      -webkit-transform: rotate(45deg);
      -webkit-mask-image: -webkit-gradient(linear, left bottom, right top, 
              from(#000000), 
              color-stop(0.5,#000000), 
              color-stop(0.5, transparent), 
              to(transparent));
       position: absolute;
       left: -8px;
       top: 2px;
}

You can view the file or download the complete file here to see the “back” and “next” buttons with their hover states.

NOTE
Although this technique does not work properly in Google Chrome because it presently lacks the CSS3 image mask property, you could make it work by enclosing the text of the link in a second span tag, give that span tag relative positioning with a z-index of 2 or greater. This would effectively position the text over the rotated span tag used a the pointer.

Update for Chrome and Android – August 29/2010
OK. Some good news, image masks are coming to Google Chrome 6. It has support for image masks the same as desktop Safari, iPhone, iPod Touch and iPad. The bad news is that this will most like not trickle down to the many Android devices out there. If you want to have the back and next buttons work on iOS and be backward compatible with existing Android devices, you can makes some slight changes to how the buttons are put together. Enclose the button’s text in a span and rename the empty span that gets used as a pointer to something sensible. I’m giving it a class of “pointer.” What we’ll do is give the text span relative positioning. Then we’ll give the pointer span a z-index of 1 and the text span a z-index of 2. That way the text will sit on top of the pointer and for Android devices that don’t support image masks you’ll still get the same look. Here’s the new markup:

<a href="#" class="button back black"><span class="pointer"></span><span>Back</span></a>
<a href="#" class="button next black"><span class="pointer"></span><span>Next</span></a>

With the CSS we’ll give all spans in the button relative positioning with a z-index of 2, then we’ll give the pointer span absolute positioning with a z-index of 1:

.back.black > span {
    position: relative;
    z-index: 2;
}
.back.black > span.pointer {
       display: block;
       height: 20px;
       width: 20px;
       background-image: -webkit-gradient(linear, left top, right bottom, 
              from(#7d828c),
              color-stop(0.5, #303749), 
              color-stop(0.5, #121a2e), 
              to(#121a2e));
       border-left: solid 1px rgba(79, 79, 79, 0.75);
       border-bottom: solid 1px rgba(79, 79, 79, 0.75);
      -webkit-transform: rotate(45deg);
      -webkit-mask-image: -webkit-gradient(linear, left bottom, right top, 
              from(#000000), 
              color-stop(0.5,#000000), 
              color-stop(0.5, transparent), 
              to(transparent));
       position: absolute;
       left: -8px;
       top: 2px;
       z-index: 1
}

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.

About these ads

About Robert Biggs
Front end Web developer skilled at creating interactive, dynamic interfaces using HTML5, CSS3, JavaScript, SVG. Passionate about developing awesome user experiences in the mobile space.

Comments are closed.

Follow

Get every new post delivered to your Inbox.

Join 46 other followers

%d bloggers like this: