Building a Starburst with CSS

Avatar of Ryan Buttrey
Ryan Buttrey on (Updated on )

If there’s one thing I love most about what I do it’s building out the challenges that a designer throws my way. There’s almost always a way to reproduce a design in code, and I love figuring out how to get as close to the original design as possible with CSS.

Recently, our creative director here at Sparkbox, Drew, gave me a design to build out for an e-commerce site. There was an element in the site that was sort of a starburst shape that had the price of the product inside. Being that it included a dynamic price, the thing had to grow and adjust appropriately, so I set out to build this thing with CSS.

Dissecting the Design

So here we go. We’ve got a rather pointy circle with the product price inside. (Also notice the subtle inner border Drew’s got going on here. We’ll talk about that a little later.) I took this design and made this:

I know it’s not exactly the same – it has a few less “points” – which I technically could have achieved with a little more markup, but I decided a little less markup and fewer points was worth it. Let’s walk through what’s going on here.

Visualizing What’s Going on Here

Think of this starburst as a series of rotated boxes. The way I wrapped my head around what’s going on here is with a few post-its. Check it:

So I’ve got three elements here, each rotated 30 degrees. (In the finished design I’ll actually have six elements, you’ll see…)

The Markup

<div class="price-container">
  <div class="price">
    <span class="label">Buy</span>
    <span class="number">$15.00</span>
    <span class="label">Now</span>
  </div>
</div>

I have <div class="price-container"> that, you guessed it, contains the price starburst. I’ll use this for the background of the starburst. The <div class="price"> is the container for the text inside (the price info.) That’s it for the markup. From here, I’ll be styling pseudo classes to create the multiple points. Also, I mentioned earlier that there were a few less points in the CSS version of this starburst. This markup doesn’t really have anything unnecessary in it.

Stylin’ It Up

Now on to the fun part. Let me overview what I’m going to do, then I’ll show you the styles needed to achieve it. I’m going to style .price-container, .price, and the :before and :after pseudo elements for each. Essentially, I’ve got six elements to work with. I created this background image to apply to each of the elements and I will rotate 15 degrees each:

If you look back at the post its picture above, notice how I drew on the inner border with pencil. Disassembling the post its model gave me one piece that looks like this.

So here are the styles of each element (the comments should help you understand what’s going on here. I also have some notes below.)

.price-container,
.price-container:before,
.price-container:after,
.price-container .price,
.price-container .price:before,
.price-container .price:after {
	height: 8.5em;
	width: 8.5em;
	background: #760B1F url(price-bg.png) top left no-repeat;
	background-size: 8.5em;
}

.price-container:before,
.price-container:after,
.price-container .price:before,
.price-container .price:after {
	content: "";
	position: absolute;
}

.price-container {
	margin: 100px auto; /* Centering for demo */
	position: relative; /* Context */
	top: 2.5em;
	left: 2.5em;
	-webkit-transform: rotate(-45deg);
	  -moz-transform: rotate(-45deg);
	   -ms-transform: rotate(-45deg);
	    -o-transform: rotate(-45deg);
	       transform: rotate(-45deg);
}

.price-container:before {
	top: 0;
	left: 0;
	-webkit-transform: rotate(-30deg);
	  -moz-transform: rotate(-30deg);
	   -ms-transform: rotate(-30deg);
	    -o-transform: rotate(-30deg);
	       transform: rotate(-30deg);
}

.price-container:after {
	top: 0;
	left: 0;
	-webkit-transform: rotate(-15deg);
	  -moz-transform: rotate(-15deg);
	   -ms-transform: rotate(-15deg);
	    -o-transform: rotate(-15deg);
	       transform: rotate(-15deg);
}

.price-container .price {
	padding: .5em 0em;
	height: 7.5em; /* height minus padding */
	position: absolute;
	bottom: 0;
	right: 0;
	-webkit-transform: rotate(45deg);
	  -moz-transform: rotate(45deg);
	   -ms-transform: rotate(45deg);
	    -o-transform: rotate(45deg);
	       transform: rotate(45deg);
	z-index: 1; /* important so the text shows up */
}

.price-container .price:before {
	top: 0;
	left: 0;
	-webkit-transform: rotate(60deg);
	  -moz-transform: rotate(60deg);
	   -ms-transform: rotate(60deg);
	    -o-transform: rotate(60deg);
	       transform: rotate(60deg);
}

.price-container .price:after {
	top: 0;
	left: 0;
	-webkit-transform: rotate(75deg);
	  -moz-transform: rotate(75deg);
	   -ms-transform: rotate(75deg);
	    -o-transform: rotate(75deg);
	       transform: rotate(75deg);
}

A few things I’ll point out about the styles:

  • Notice the order of the rotation angles: This order is important because there is going to be text inside the inner-most element. Therefore, the last element (the one the text going in, in this case .price) has to be straight. Notice that .price-container is rotated -45 degrees and .price is rotated 45 degrees – back to 0.
  • The height and width: The height and width has to be set since we are dealing with background images here. I’ve set it in ems to adjust appropriately when the text size increases.
  • There’s a padding top and bottom on .price-container .price. That’s why the height is a little different than all the others.
  • Everything is positioned absolutely inside the first container. .price-container has left: 2.5em and top: 2.5em just to move the whole thing a little. When everything is rotated, the corners go of the page and out of the container a little.
  • z-index: There’s a z-index defined for .price-container .price. This is so the price information inside this div is visible.

Now all that’s left is styling the text.

.price-container .price span {
  position: relative;
  z-index: 100;
  display: block;
  text-align: center;
  color: #FE3D5C;
  font: 1.8em/1.4em Sans-Serif;
  text-transform: uppercase;
}

.price-container .price span.number {
  font-weight: bold;
  font-size: 2.5em;
  line-height: .9em;
  color: #fff;
}

Doing It Image-Free

Now, I have some extra stuff in here because the design called for this very subtle inner border. If you don’t like or need the inner border, just remove the bit about background image and background size and design will hold up fine.

Browser Support

This works as-is in IE 9+, Firefox 4.0+, Safari 4.1+ and Chrome 3.0+. IE 8 and below do not support background-size, and Chrome 1.0, Firefox 3.6 and Safari 3.0 will require some vendor prefixes. IE8 does support pseudo elements, however doesn’t support transform.

The fallback would be a colored square. Very likely not a huge problem.

There You Have It

It’s a price star thing. Flexible enough to grow when you increase your font size. Made with some CSS.

View Demo   Download Files

This was a guest post by Ryan Buttrey of Sparkbox. Thanks for sharing your process Ryan! I too get a kick out of figuring out clever and efficient ways to solve bits of design.