How To Add Images To Your CSS Borders

The last few posts I’ve been working through the background and borders module for css3. So far we’ve looked at css backgrounds, simple borders, and rounded corners.

Today I want to walk through the border-image property and close with a couple of miscellaneous properties around the boxes we’ve been talking about.

Browser support: At the moment browser support for css border images is limited. The latest version of Chrome should support everything here. Safari, Firefox, and Opera should support border images only when the shorthand is used. There is currently no support in IE.

A border image and the resulting border it creates

Border Images

CSS3 introduces the ability to use an image as the border around an element in place of one of the border-styles.

It also provides properties for controlling to a greater degree how these images will display as the border. The border-image properties we can use are:

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

Let’s talk about each of these in more detail and then take a look at the border-image drawing process, which will hopefully tie everything together.

border-image-source

This is the easiest of the properties to understand and perhaps the only one you’ll ever set. As you’d expect it’s used for the path of the image you want to use as the border.

1
2
3
div {
  border-image-source: url("path-to-image"); 
}

If a value of none is used or if the image can’t be found then border-styles will be applied instead, suggesting that when using border-image you should still provide some default border-styles to fall back to.

This seems pretty simple, but it may surprise you to look at the image above and realize the image on the left becomes the border for the right.

That might not seem obvious, but will hopefully become clearer with the remaining properties. Keep the image above in mind when reading through the rest of this post.

Diagram showing an image sliced into 9 regions

border-image-slice

What’s happening with the border-image above is that it and the area it will be painted on are first sliced into 9 different regions (like a tic-tac-toe board) and then those slices are set around the border of the element.

The border-image-slice property sets how the image itself is divided.

The 9 slices of the image will be 4 corners, 4 edges, and a middle. Again think tic-tac-toe or better, just look at the image above. The middle slice is discarded. It’s treated as fully transparent unless you use the fill keyword.

The border-image-slice property allows you to set the offsets to slice the image into these 9 regions.

Basically it lets you move the lines of the tic-tac-toe board up and down or left and right. The values are the usual number or % with numbers representing px for a raster image and vector coordinates for a vector image.

1
2
3
div {
  border-image-slice: 20 40 20 40;
}

You can add the optional fill value at the end. Assuming a raster image, the above would draw the lines for slicing 20px from the top and bottom and 40px from the left and right.

Negative values are not allowed and values greater then the image size are reduced to 100%. If the 4th value is absent it’s the same as the 2nd. If the 3rd and/or 2nd is absent it’s the same as the 1st value.

The regions may overlap, but if the sums for left and right are greater than the image’s width, the top, bottom, and middle are considered empty or transparent.

A rectangle divided into 9 unequal slices

border-image-width

The border-image-width property also sets offsets. These are used to divide the painting area into 9 parts that will contain the 9 regions of the image sliced above.

The 4 values set represent the inward distances from the sides of the image area.

1
2
3
div {
  border-image-width: 20px 10% 20 10%;
}

Values can be a length, number, or % with the default being auto.

As above if the 4th value is absent it’s the same as the 2nd. If the 3rd and/or 2nd is absent it’s the same as the 1st value.

Also as above negative values are not allowed and if there’s overlap the numbers are reduced until there is no longer an overlap.

The auto value uses a width that is intrinsic to the width or height of the image slice.

border-image-outset

The border-image-outset specifies the amount by which the border area extends outside the border box

It’s values can be a length or number and the same 4th being absent, etc applies. Once again no negative numbers can be used.

Even if the outset is set to increase the apparent size of the border box, that expanded area doesn’t trigger things like scrolling or mouse events. The area is there for the border-image, but nothing else.

border-image-repeat

The border-image-repeat property sets how the border images for the sides and middle are sized and scaled and has the following values and definitions

  • stretch — the image is stretched to fill the area (default)
  • repeat — the image is tiled to fill the area
  • round — the image is tiled to fill the area with a whole number of images and then rescaled to fill the area remaining
  • space — the image is tiled to fill the area with a whole number of images and then space is evenly distributed around the images

Two values should be given, the first for the horizontal and the second for the vertical. If the second isn’t given it’s considered the same as the first.

Diagram illustrating the different border image properties

border-image Drawing Process

The above properties aren’t difficult to understand, but reading through them you may still be thinking, huh? How exactly did that border-image we started with end up looking like the border in the image on the right?

That’s how I felt too reading through the spec. Hopefully the drawing process below helps clarify things a bit.

After the border image (source) is sliced into 9 parts, the resulting nine images are scaled, positioned and tiled into their corresponding regions in 4 steps.

  1. Scale to border-image-width — For the top and bottom images the height is set according to the image-slice and then the width is scaled. For the left and right images the width is set and then the height scaled. The corners are scaled to match both the horizontal and the vertical. The middle image is finally scaled to match the top and left images.
  2. Scale to border-image-repeat — The top middle and bottom images are the ones that repeat and they are further scaled according to the rules of the value set — stretch, repeat, round, or space.
  3. Position the first tile — If repeat is used, the images are centered and then scaled — top, middle, bottom and then left, middle, right. Otherwise the images are placed along the top or left edge
  4. Tile and draw — The images are lastly tiled to fill their respective areas. All images are drawn at the same stacking level as normal borders, which is immediately in front of the background. If space was set for background-repeat, partial tiles are discarded and extra space is distributed before, after, and between tiles.

The basic idea again is the border image area and the border image are each divided into 9 parts — 4 corners, 4 edges, and a middle. The size of these parts are determined by the border-image-slice and border-image-width and border-image-outset properties.

The 9 image parts are then placed into the 9 regions of the border image area according to one of several border-image-repeat algorithms.

Using jQuery Nora Brown set up a nice demo to show how border-images work. Play around with the demo if the above isn’t making complete sense to get a better feeling for how it all works and ties together.

border-image Shorthand

Of course all of the above properties can be shorthanded as follows:

<border-image-source> | <border-image-slice> [ / <border-image-width>? [ / <border-image-outset> ]? ]? | <border-image-repeat>

1
2
3
div {
  border-image: url("path-to-image") 20 40 20 40 / 10 20 10 20 / 10 space;
}

Anything omitted is set to its default.

You’re more likely not to set the outset and keep the slice and width the same so:

1
2
3
div {
  border-image: url("path-to-image") 20% repeat;
}

If you’re going to play with border-images you’ll have to use the shorthand. No browser currently supports the individual properties. The usual players should support the shorthand though. All except IE, which is only introducing support in IE10.

Diagram showing a sliced box on the left and a cloned box on the right as it breaks across pages

Miscellaneous Properties

There are two more properties in regards to boxes that are covered under the css backgrounds and borders module.

  • box-decoration-break
  • box-shadow

box-decoration-break

The box-decoration-break property sets how to treat boxes that are broken by a page break, a column break, or a line break for inline elements.

It’s used to determine whether to treat the box as broken pieces or continuous and whether each box is wrapped individually with padding and border. It also defines how the background-positioning area is set

The following 2 values can be used:

  • clone — each box is individually wrapped with padding, border, border-radius, border-image, and box-shadow. Clone treats the boxes as two individual boxes.
  • slice — no individual wrapping of padding and border. The box is considered to be a single box that’s been sliced in two. Padding and border are applied as though the box wasn’t split.

Slice is the default value and probably better indicates that the box is the same from page to page, etc.

1
2
3
p {
  box-decoration-break: clone;
}

As far as I could find, there’s not much browser support yet, though Opera seems to be supporting box-decoration-break.

Diagram showing the different box shadow properties and the resulting shadow

box-shadow

As you would guess box-shadow adds a shadow to the box, something we previously had to use images to do.

It’s values are a comma-separated list of shadows, each specified by 2–4 length values, an optional color, and an optional ‘inset’ keyword.

<shadow> = inset? && [ <length>{2,4} && <color>? ]

These values represent the horizontal offset, vertical offset, blur radius, spread distance, color, and the optional inset.

1
2
3
.shadow {
  box-shadow: 5px 5px 10px #999;
}

Inset changes the shadow from a drop shadow to an outer shadow and can be used to create some interesting effects. A drop shadow moves an element above the page, while an outer shadow makes an element recede into page.

With spread positive values expand the shadow and negative values contract the shadow. With blur the larger the value the greater the blur.

The shadow shape matches the shape creates by the border-radius, but a border-image has no effect on box shadow.

As is usually the case when talking browser support, the box-shadow property is supported in modern browsers including IE9, but won’t work in IE8 and below.

Rusty picture frame around a demolished building

Summary

Being able to use an image for an element’s border is something you probably agree is nice to be able to do. If you’ve been following along with this post you’ll have noted browser supported isn’t quite what it could be.

However outside of IE8 and below the shorthand should work so you can play with border-images now. And since the fallback is the ordinary border-styles you’d have to use anyway you really should be fine using border-images in any browser, especially as a border image shouldn’t be conveying any essential information.

How border images are drawn may be a little confusing at first, but hopefully this post has helped clear up any confusion you might have had. Hopefully it hasn’t created more confusion.

As I’ve been asking in some of the other css3 posts, have you used border-image in your work and if so how have you found it?

Download a free sample from my book, Design Fundamentals.

2 comments

Leave a Reply

Your email address will not be published.

css.php