Border-Image Bits

As a front-end dev at Envy Labs, I have the fun task of marking up some of Justin Mezzell’s designs. I recently worked on the UI for Ruby Bits, a course available at Code School.

For this particular course, Justin created a fantastic 8-bit environment with some really interesting borders that would require a special solution. They could technically be achieved by tables with repeating backgrounds, background images, or using the CSS border-image property. The best solution was border-image, but I hadn’t used it before.

To the Googles!

A quick Google search for “border-image” resulted in the usual suspects: CSS-Tricks, Mozilla Developer Network, and a border-image generator. There were many more resources, but these are the three that I dove into.

The syntax is a little weird, but it is similar to the old table background tricks if they had used a single image like a CSS sprite. You need to declare an image, the border widths, and how the CSS is supposed to cut the image.

Making an Element with Border-Image

The first step is creating the image that you want to use. For brevity sake, I’ll only show one of them, but I’ll share them all in a Code Pen where you can see the code as well.

The CSS establishes the four corners of the border when you set values for the top, right, bottom, and left. Once those are set, you have to set how you want the in-between areas to behave. They can be stretched or repeated. Finally, there is a middle area that can be hidden or shown. By default, most browsers hide them but I didn’t want to risk that so I used transparent pngs.

This particular element had some specific visuals that I needed to work around. There was some pixel shading that I wanted to be sure only stayed on one side and indentations that looked like fittings that needed to stay on each end and not repeat. Below you can see each step shown, including the beginning element. As a visual helper, each of the defined regions are indicated with black: top, right, bottom and left respectively. Finally, the areas that will repeat are indicated with red.


Here is a quick look at the CSS and how it works, step-by-step.

border-image: url('http://d35nyfeeu8zws1.cloudfront.net/assets/border-modal-379f146691e718e5de7084a90c85d93e.png') 48 22 46 31 repeat;

This sets the png as the target, then tells it to be ‘cut’ 48px from the top, 22px from the right, 46px from the bottom, and 31px from the left. You can’t actually declare the px value in the border-image property, though. Finally, we’re telling the other areas to repeat.

border-style: solid;

Declaring the border-style is necessary for Firefox 15 and up.

border-width: 48px 22px 46px 31px;

To give the border width in the DOM, you set the values including their type of px.

Putting that into an element with a class of .border-modal would look like this:

.border-modal { border-image: url('http://d35nyfeeu8zws1.cloudfront.net/assets/border-modal-379f146691e718e5de7084a90c85d93e.png') 48 22 46 31 repeat; border-style: solid; border-width: 48px 22px 46px 31px; }

Yay! We’re done, right?

As far as having an element with a border image, this is all you would need to do. However, there is no IE9 support and browser prefixes are needed for some browsers. You can see support on caniuse.com. Figuring out fallbacks is case-by-case. For IE9, I instead used box-shadow to make some two-toned borders. Setting up the fallbacks was the easy part, unfortunately. Setting up the elements to contain content the way they were designed to was a little tricky.

The Catch(es)

As great as it is that this works, it causes some complexity on elements that will contain content. Backgrounds require some extra thought and there is a need for some negative margins to align the content evenly when your borders are not of equal widths.

To help visualize this, there is a black background set on the element and a paragraph with a red border. (I left the text dark because it’s an image and it blurs).

The Workarounds

The background issue is a problem. There are some things like background-clip that can normally help, but the edges of this particular border are too complex for that. It has these staggered elements that require transparency. The solution that I used was to create a pseudo element and use the stretch technique. This meant absolutely positioning the element and manually setting the top, right, bottom, and left to have them end at the edges of the blue. To make it appear beneath the element, a negative z-index was necessary.

.border-modal:after { background: black; bottom: -28px; content: ""; left: -14px; position: absolute; right: -6px; top: -31px; z-index: -2; }

The content positioning is a little easier as you just need to set negative margins on the element inside.

.border-modal .inner { border: 1px solid red; margin: -36px -10px -34px -19px;

This is how the container ends up, with the background within the main border and even spacing around the content.

Code Samples

If you’re interested in seeing the code for this and a few other samples, I created a Code Pen with the ones used for the Ruby UI. This way you can see them in action and play with the code a bit, if you’re into that kind of thing.

10.23.12 ← See All Posts
blog comments powered by Disqus