CSS3 Border-Image

A feature that is new in CSS3, but not so new to browsers, is the border-image property. Border-image provides a method to add decorative borders to any element. With the border image properties you can create decorative borders for elements, beyond simple rounded corners, with images of very small file size ore even with gradients.

The border image property allows you to take a small image, slice it virtually into 9 sections, and place /spread the portions of your small image across a much larger element.

You can take an image and stretch it across a button or a whole page.

This is a div with a border image
and three lines of text
making it much bigger than the original image

We've used image on the left as a border-image for the div on the right, maintaining the corners, while stretching the center of the border image to cover the entire div on the right.

This is a div with a border image
and three lines of text
making it much bigger than the original image

In this second example, instead of stretching the middle of the border image, we've repeated, slightly distorting the image if necessary to ensure we don't have a broken image in supporting browsers.To ensure that the image is not 'broken', the width should be a multiple of the slice's width.

While we'ver repeated the top, bottom and sides, we've maintained the four corners, creating a stamp-like effect.

In this article we'll cover how to take a background-image, virtually cut it up, and either repeat or stretch the image to cover the borders and background of our element.

The border-image is a shorthand property used to declare:

  border-image-source:
  border-image-slice:
  border-image-width:
  border-image-outset:
  border-image-repeat:

The syntax for the shorthand is:

 border-image: <source>
<slice {1,4}> / <width {1,4}> <outset> <repeat{1,2}>;

At this time, Opera, Firefox, Chrome and Safari all support the vendor prefixed border-image shorthand property but don't support any of the longhand properties that make up the shorthand. So, while we'll cover the various properties that define border images, you should always use the shorthand instead of the shorthand properties described below.

border-image-source:

The border-image-source, is the URL, gradient or data URI of the image you want to use for as your border image. In the above examples, while the long hand property is NOT supported, it is as if we we had used

.gradientBox {
  border-image-source: url(gradient.png);
}
.stamp {
  border-image-source: url(stamp.gif);
}

Just as you can include gradients, base 64, gifs, jpegs, pngs, and even SVG images as background images, you can include all these image types as border images.

border-image-slice:

The border-image-slice property defines from one to four lengths that set the distance from each edge of the image marking the area that will be used to cut, or slice, up our border image.

The ‘border-image-slice’ property values represent inward offsets from the top, right, bottom, and left (TRouBLe) edges respectively of the image. In effect, with the four lines you define, the browser divides the one border image into nine regions: four corners, four edges and a middle. The four corners maintain their exact size. The other five values can be stretched or repeated or a combo of the two (round), depending on the values of the other border image properties.

The black lines in the images above delineate how our four defined slice lines cut up our border-iamge.

In our examples, we've sliced the image 30px in from each side for our gradient, and 8 pixels in from each side for our stamp.

In the above examples, while the long hand property is NOT supported, it is as if we we had used

.gradientBox {
  border-image-slice: 30 30 30 30;
}
.stamp {
  border-image-slice: 8 8 8 8;
}

or, since the values are repeated, like the TRBL of border or padding, we can use a single value for all four sides

.gradientBox {
  border-image-slice: 30;
}
.stamp {
  border-image-slice: 8;
}

Note we've used no length units. If you are setting the slice values in length, and the value will be interpreted as pixels, omit the units. If you are using percentage values, include the percent. In our example, we could also have used the following:

.gradientBox {
  border-image-slice: 30%;
}
.stamp {
  border-image-slice: 26.7%;
}

For bitmap images, the omitted values are interpolated as pixel values. For vector images (SVG), the values are coordinates. For percentages use the percent sign (%).

border-image-width:

The border-image-width property sets the width of the element's border. If the border-image-width property is declared, it takes precedence over the border-width if one is declared. If omitted and the border-width is omitted, the value defaults to the border-width default which is 'medium', or generally 3px.

This shorthand is NOT supported in Opera (build 1024 is the most recent one checked). Additionally, the value of auto is not supported in any browser. As such, it is often recommended to include border-width as a separate property. Declaring as part of the shorthand is as if we had declared:

.gradientBox {
  border-image-width: 30px 30px 30px 30px;
}
.stamp {
  border-image-width: 8px 8px 8px 8px;
}

or, since all the value are the same,

.gradientBox {
  border-image-width: 30px;
}
.stamp {
  border-image-width: 8px;
}

So far we have:

.gradientBox {
  border-image: url(gradient.png) 30 / 30px;
}
.stamp {
  border-image: url(stamp.gif) 8 / 8px;
}

Since including border-image-width in the shorthand currently makes Opera fail, it is recommended to exclude this property, and instead opt for including the CSS2 border-width value.

.gradientBox {
  border-width: 30px;
}
.stamp {
  border-width: 8px;
}

Having the border-image-width be the same width as the border-image-slice will create the best looking border image with no distortion. But, they don't need to have the same values. The slice will be stretched (or contracted)to be the width of the border-image-width if the values are not the same.

Remember the box model! As you increase the border-image-width, your element will grow larger.

border-image-outset

The border-image outset property specifies the amount by which the border image area extends beyond the border box on all four sides. It is not supported in any browsers, and makes the entire declaration fail, so, for now, don't include it. The default value is 0.

border-image-repeat

The border-image-repeat property allows you to delineate how non-corner images (the sides and middle) are repeated and/or scaled. The first value is the top and bottom, the second value is the left and right sides. If the second value is omitted, all four sides will have the same value.

The specifications currently define 4 possible values, but only three are well supported. 'stretch' means that the image should not be tiled, but rather stretched to fill the area. 'repeat' means the image is tiled ( or repeated) to fill the area. If the area allocated for the repeating image is not exactly divisible by the width of the image, the last tiled image may be cut off. With 'round' the image is tiled (repeated) to fill the area, with the image being scaled down, possibly losing it's aspect ratio, but ensuring that the image is never cropped. Note that Webkit doesn't support the 'round' value, replacing it with 'repeat' instead (which is better than failing, I guess).

The 'space' value is not currently supported, but when supported, the border-image will be repeated as many times as can fully fit in the area provided, with the tiles evenly spaced, showing white space between the tiles if the width provided is not an exact multiple of the image size.

In our above examples, we used 'stretch' for the gradient and 'round' for the stamp. You will always want to stretch gradients, as repeating them creates harsh lines as one tile ends and the next begins. And, while it may seem to make sense to use 'repeat' for the stamp, we have no way of knowing if the image is evenly divisible by the width of our design. The 'round' does distort the image ever so slightly, but that is better than having the image cut off.

If we had used the inverse, the effect would be odd. While the top and bottom can use round, repeat or stretch, the left and right sides definitely need the 'stretch' value:

This is a div with a border image
that is correctly stretched
creating no odd lines
This is a div with a border image
that is erroneously rounded
when it should be stretched
Border image is rounded
with no tiles cut incorrectly
in supporting browsers (FF and Opera)
This is a div with a border image
that is erroneously stretched
when it should be rounded
This is a div with a border image
that is erroneously repeated
which may cause the design to break

 

Border-image shorthand

As mentioned earlier, no browser supports the long hand properties defined above, but Opera, Firefox, Chrome and Safari understand the prefixed shorthand border-image property. Now that we understand the components of the shorthand property, let's put it all together.

The correct syntax is

border-image: <source>
<slice {1,4}> / <width {1,4}>  / <outset> <repeat{1,2}>;

Since outset is not currently supported, we can omit it:

border-image: <source>
<slice {1,4}> / <width {1,4}> <repeat{1,2}>;

Like all border-images, we've cut our gradient image into 9 slices defined by the border-image-slice property. Generally, the slices are the same width as the border-width. And, since we have a gradient, we want to stretch the image, not tile it, so we don't get harsh color transitions. As such our code is:

.gradientBox {
    border-image: url(gradient.png) 34 34 34 34 / 34px 34px 34px 34px stretch stretch;
}

which, with repeated values, we can narrow down to:

.gradientBox {
    border-image: url(gradient.png) 34  / 34px  stretch;
}

Since opera doesn't understand border-image-width when included in the short hand, we include the border-width separately and then expand our declarations to include the various vendor prefixes:

.gradientBox {
   border-width: 34px; 
  -moz-border-image: url(gradient.png) 34 / 34px  stretch;
  -webkit-border-image: url(gradient.png) 34 / 34px  stretch;
  -o-border-image: url(gradient.png) 34   stretch;
   border-image: url(gradient.png) 34 / 34px   stretch;
}

Similarly, our stamp effect includes the stamp image as the border-image-source, has borders that are 8 pixels wide, has a repeating border which can't have a partial image showing lest we break the design. We still have the opera issue of border width, and all supporting browsers still use the vendor prefix. As such, our code looks like this:

.stamp {
    border-width: 8px;
   -webkit-border-image: url(stamp.gif) 8 / 8px round;
   -moz-border-image: url(stamp.gif) 8 / 8px round;
   -o-border-image: url(stamp.gif) 8  round;
    border-image: url(stamp.gif) 8 / 8px  round;
    }

Resources

At this point, you hopefully have a good understanding of how to create a border image. There are a few tools to help you along: