Blog

Replacing Common UI Icons with CSS

Let’s be honest, dealing with images on the web is kind of a pain. They’re a pain to modify, load slowly and require all sorts of progressive techniques in a responsive environment. But, unfortunately, images are here to stay; there’s no better way to capture a moment in time than with an image. However, we can significantly reduce our use of images by using CSS to recreate elements. But how can we do this while still keeping our designs visually appealing?

With our powers combined

Modern browser technology is our best friend, namely the technology of CSS with its shape rendering capabilities. We can do some crazy stuff with CSS alone! So in this article, we’re going to start simple and see how we can replace common user interface icons with just CSS. No more loading custom icon fonts or exporting PNGs.

Let’s jump right in

We’re going to go through the creation of 5 fairly standard UI icons:

Hamburger icon

Mail icon

Heart icon

Home icon

Camera icon

I’ve chosen these mainly because they can be easily created with little code and with only one element.

A quick note on browser support: anytime I use the border-radius or transform properties, I’m not prefixing them with vendor prefixes, so you may want to add their proper prefixes for wider browser support. Also, all of the examples below work in all modern browsers, including IE9.

Hamburger icon

We see this hamburger-looking icon a lot in mobile navigation patterns. It’s a very simple one to create with CSS, as it’s just 3 rows with some space in between.

The markup for all of these icons will be the same. We’ll use the i element with a reusable icon class and a unique identifier class, like icon_hamburger.

<i class="icon"></i>
.icon {
  position: relative;
  display: inline-block;
}

.icon::before,
.icon::after {
  content: "";
  position: absolute;
}

Notice I created rules for the ::before and ::after pseudo-elements and set the content property to an empty string and positioned them absolutely. We’ll be relying heavily on these pseudo-elements to get the job done (hence why we can create these icons with only one HTML element).

For the hamburger icon, we’ll start off by giving .icon_hamburger a width, height and background.

.icon_hamburger {
  width: 1.625em;
  height: .313em;
  background: black;
}

Hamburger icon step 1

Now to add in the top and bottom lines. We’ll use ::before for the top line and ::after for the bottom.

.icon_hamburger::before,
.icon_hamburger::after {
  width: 1.625em;
  height: .313em;
  background: black;
}

.icon_hamburger::before {
  top: -.625em;
}

.icon_hamburger::after {
  bottom: -.625em;
}

Hamburger icon step 2

That’s it! It’s so much easier than an image to maintain, too. Want to change the width? Just modify the pixel value; no Photoshop required! Want to change the color? Easy!

Mail icon

The mail icon (envelope) is another item commonly seen in many UIs. To start out, we’ll set the borders to create a rectangle with a triangle notched out of the top. Joel Glovier wrote a great article a while ago on the appendTo blog explaining how CSS triangles work.

.icon_mail {
  border-top: 1.063em solid transparent;
  border-right: 1.25em solid black;
  border-bottom: .5em solid black;
  border-left: 1.25em solid black;
}

Mail icon step 1

Then to create the envelope flap, we’ll use the same technique again to create a triangle with a negative top and left value. The negative top value offsets it from the top just enough to provide the space between the flap and the actual envelope.

.icon_mail::before {
  top: -1.25em;
  left: -1.25em;
  border-top: 1.063em solid black;
  border-right: 1.25em solid transparent;
  border-left: 1.25em solid transparent;
}

Mail icon

Heart icon

Creating the heart shape involves rotating the pseudo-elements with the transform property, and applying a large border-radius to the top of each tilted rectangle. The main element itself needs no properties at all. First, we’ll create two rectangles out of our ::before and ::after pseudo-elements.

.icon_heart::before,
.icon_heart::after {
  width: 1em;
  height: 1.563em;
  background: black;
}

.icon_heart::after {
  left: .375em;
}

Heart icon step 1

Then we’ll rotate them.

.icon_heart::before,
.icon_heart::after {
  width: 1em;
  height: 1.563em;
  background: black;
}

.icon_heart::before {
  transform: rotate(135deg);
}

.icon_heart::after {
  left: .375em;
  transform: rotate(45deg);
}

Heart icon step 2

And lastly, add a border-bottom-radius to the ::before pseudo-element (because it’s rotated upside down) and a border-top-radius to the ::after.

.icon_heart::before {
  transform: rotate(135deg);
  border-bottom-radius: .5em;
}

.icon_heart::after {
  left: .375em;
  transform: rotate(45deg);
  border-top-radius: .5em;
}

Heart icon step 3

Home icon

Creating a home icon starts out by morphing the main element into a triangle.

.icon_home {
  border-bottom: .938em solid black;
  border-left: .938em solid transparent;
  border-right: .938em solid transparent;
}

Home icon step 1

Then we’ll just create two vertical rectangles below the triangle and space them apart to give the impression of a door in the middle.

.icon_home::before {
  width: .563em;
  height: .625em;
  background: black;
}

.icon_home::before {
  margin: .938em 0 0 -.688em;
}

.icon_home::after {
  margin: .938em 0 0 .125em;
}

Home icon step 2

Camera icon

The camera icon, like the mail icon, starts out as a rectangle with a small border-radius.

.icon_camera {
  width: 1.938em;
  height: 1.375em;
  margin-top: .813em;
  background: black;
  border-radius: .125em;
}

Camera icon step 1

Then we’ll use the ::before pseudo-element to create a flash on top of the camera, in the shape of a trapezoid. The trapezoid shape is defined similarly to the way we create triangles, except we need to add a width.

.icon_camera::before {
  height: 0;
  width: .938em;
  margin: -.313em 0 0 .313em;
  border-bottom: .313em solid black;
  border-left: .188em solid transparent;
  border-right: .188em solid transparent;
}

Camera icon step 2

And finally we’ll add the lens to the front of the camera, using a circle with a border.

.icon_camera::after {
  width: .438em;
  height: .438em;
  margin: .125em 0 0 .5em;
  border: .25em solid white;
  border-radius: .438em;
}

Camera icon step 3

Taking it further

As you hopefully saw, creating CSS icons is really not that difficult and doesn’t require a ton of code. I’ve created a CodePen with all of these icons plus a few more. Feel free to play around with it!

Browser support

As mentioned above, all of these examples work in all modern browsers, including IE9. Some of the new CSS3 properties require vendor prefixes, so make sure you use the proper prefixes. In my CodePen, I’m using Compass @includes, which automatically adds in the proper vendor prefixes. If your project requires IE8 support, you unfortunately might want to rethink the use of solely CSS icons, or at least stay away from icons that require border-radius and transform. My suggestion for a fallback would be to use Modernizr to detect which browsers don’t support border-radius and transform, and provide a background image as a fallback.

Tweet about this on TwitterShare on FacebookShare on RedditShare on Google+Share on LinkedIn

  • GrantStanley

    This is great! Can’t wait to use these.

  • Pingback: Replacing Common UI Icons with CSS | Multipop

  • DilanLeelarathna

    Finally came to the right place. Thank you Trevan.

  • http://blog.andreiduma.ro/ Andrei Duma

    Interesting article. I wasn’t aware of the tricks you can do with ::before and ::after. Thanks! :)