Mixing absolute and relative measurements with faux borders
Creating faux borders with CSS is not a new technique. In fact, it's basically just a primitive version of
Dan Cederholm's Faux Columns,
but just applied to the edge of an element instead painting the element's entire
background.
What I have found useful about faux borders is that in certain situations it allows
us to appear to mix absolute and relative units to achieve layouts that would otherwise
be impossible or extremely difficult to produce without tons of non-semantic markup.
According to the CSS box model, the horizontal space used by an element is defined
by seven properties:
- padding-left;
- padding-right;
- margin-left;
- margin-right;
- border-left;
- border-right;
- width;
Let's say we want to lay out a horizontal banner 500 pixels wide containing five
items, each 100 pixels wide. An extremely basic layout could look something like
this first example.
That fits the bill, but how about adding borders to better define each item? Well,
if we add a left-side border to each item (with the exception of the first item,
else it would not be flush with the left-side of the banner), the banner now breaks
over two lines as shown in Example 2.
Remember that borders add to the space taken up by an element on a page. So, if
our element's width is 100 pixels, and we add a 1 pixel border, the actual space
taken up by the element is 101 pixels. Since we have four items with a border, the
total space occupied by those five items is 504 pixels, 4 pixels greater than the
banner's 500 pixels. Since the items are being floated and cannot all be contained
within their parent, the last item is float dropped to the next line.
The fix is simple enough - subtract a pixel from the width of elements with a border
as I have done in Example 3.
Things get more complicated when we start using relative measurements. Let's extend
our banner to the full width of the page by giving it a width of 100%. Since we
have five items in the banner, we will give them each a width of 20%. Have a look
at Example 4.
As in our second example, the banner cannot accommodate all five items. And in this
situation, we cannot simply subtract a pixel from each item's width because their
width is defined as a percentage, and we cannot express a width as a percentage
value minus a pixel value. We could try paring down the percentage a bit, but your
results will never be completely accurate. In
Example 5, try resizing the screen horizontally and notice that over
a certain page width all items are on the same line, but past that threshold the
last item is float dropped.
You could add some additional markup to effect the desired results (more on this
below), but let's see what we can do with what we have. The solution is incredibly
simple. Instead of applying borders, we instead take an image of a 1 by 1 pixel
white dot and tile it vertically down the right side of the item, as we see in Example 6. The solution is a one-liner:
li{ background-image: url(whitedot.gif) top right repeat-y; }
Whereas borders add to the space used by an element, background images do not, so
our last item in our banner will never be float dropped. And we aren't limited to
giving the illusion of borders, we can be creative and give the illusion of margins
using the proper image, as I did in Example
7. Again, where margins would have added to space consumed by each item
in the banner, the background image does not.
Faux borders and margins can be an attractive option because they also sometimes
allow us to sidestep certain hairy Internet Explorer bugs that result from the confluence
of margins, background colours, padding, borders, and/or floating.
This was a very simplified example, the instances where I have used these techniques
are too complex for a simple tutorial. But hopefully the next time you come across
a situation where you are mixing relative and absolute units, you'll remember that
you may have some options at your disposal.
And now for something completely different
You may have noticed that our banner looks a lot like a navigation menu. If it
were actually marked up thusly, we would have additional options to effect our solution.
I was able to apply a border without any kind of image thanks to the addition
of anchors in Example 8. This is the
most elegant solution, and it allows us to apply some padding so the anchor doesn't sit flush on the border. By setting the anchor's display property to
block level and setting its width to auto (which is the default, but I typed it
in for clarity's sake), we can add borders, padding and margins to the anchor and
be assured that the anchor will continue to occupy the same amount of space as its
parent list item, in effect 'sitting' on top of it.
a{
display:block;
width:auto;
border-right:1px solid #fff;
padding-left:5px;
color:#fff;
text-decoration:none;
}
We can have more fun by using faux borders, however. This is basically the
Sliding Doors technique, just turned over on its side. By applying one background
image to the list item and another to the anchor, we can give the appearance of
a bullet-shaped border. See Example 9
and the relevant CSS below:
li{ background:#000080 url(border-top.gif) top right no-repeat; }
a{ background:url(border-bottom.gif) bottom right no-repeat; }
Things will get even more interesting when browsers begin supporting
border images and
multiple background images. Safari has
already begun.
Sound off