A List Apart: Articles: Sliding Doors of CSS

来源:百度文库 编辑:神马文学网 时间:2024/06/13 06:12:14
Sliding Doors of CSS
byDouglas Bowman
Published in:CSS,HTML and XHTML,User Interface Design |
Discuss this article »
A rarely discussed advantage of CSS is the ability to layer background images, allowing them to slide over each other to create certain effects. CSS2’s current state requires a separate HTML element for each background image. In many cases, typical markup for common interface components has already provided several elements for our use.
One of those cases is tabbed navigation. It’s time to take back control over the tabs which are continually growing in popularity as a primary means of site navigation. Now that CSS is widely supported, we can crank up the quality and appearance of the tabs on our sites. You’re most likely aware that CSS can be used totame a plain unordered list. Maybe you’ve even seen lists styled as tabs, looking something like this:

What if we could take the exact same markup from the tabs above, and turn them into something like this:

With simple styling, we can.
Where’s the Innovation?
Many of the CSS-based tabs I’ve seen suffer from the same generic features: blocky rectangles of color, maybe an outline, a border disappears for the current tab, a color changes for the hover state. Is this all CSS can offer us? A bunch of boxes and flat colors?
Prior to a more widespread adoption of CSS, we started seeing a lot of innovation in navigation design. Creative shapes, masterful color blending, and mimicry of physical interfaces from the real world. But these designs often relied heavily on a complex construction of text-embedded images, or were wrapped with multiple nested tables. Editing text or changing tab order involved a cumbersome process. Text resizing was impossible, or caused significant problems with page layout.
Pure text navigation is much easier to maintain and loads more quickly than text-as-image navigation. Also, even though we can add alt attributes to each image, pure text is even more accessible since it can be resized by users with impaired vision. It’s no wonder that pure text-based navigation, styled with CSS, is leaping back into web design. But most CSS-based tab design so far is a step back in appearance from what we used to do — certainly nothing to be included in a design portfolio. A newly adopted technology (like CSS) should allow us to create something better, without losing the design quality of previous table hacks and all-image-based tabs.
The Sliding Doors Technique
Beautifully crafted, truly flexible interface components which expand and contract with the size of the text can be created if we use two separate background images. One for the left, one for the right. Think of these two images as Sliding Doors that complete one doorway. The doors slide together and overlap more to fill a narrow space, or slide apart and overlap less to fill a wider space, as the diagram below shows:

With this model, one image covers up a portion of the other. Assuming we have something unique on the outside of each image, like the rounded-corner of a tab, we don’t want the image in front to completely obscure the image behind it. To prevent this from happening, we make the image in front (left-side for this example) as narrow as possible. But we keep it just wide enough to reveal that side’s uniqueness. If the outside corners are rounded, we should make the front image only as wide as the curved portion of the image:

If the object grows any larger than the width shown above, due to differing text or type size changes, the images will get pulled apart, creating an ugly gap. We need to make an arbitrary judgment about the amount of expansion we’ll accommodate. How large do we think the object might grow as text is resized in the browser? Realistically, we should account for the possibility of our tab text increasing by at least 300%. We need to expand the background images to compensate for that growth. For these examples we’ll make the back image (right-side) 400x150 pixels, and the front image 9x150 pixels.
Keep in mind that background images only show in the available “doorway” of the element to which they’re applied (content area + padding). The two images are anchored to the outside corners of their respective elements. The visible portions of these background images fit together inside the doorway to form a tab-like shape:

If the tab is forced to a larger size, the images slide apart, filling a wider doorway, revealing more of each image:

For this example, I used Photoshop to create two smooth, slightly three-dimensional, custom tab images shown at the beginning of this article. For one of the tabs, the fill was lightened and the border darkened — the lighter version will be used to represent the “current” tab. Given this technique’s model for left and right tab images, we need to expand coverage area of the tab image, and cut it into two pieces:

The same thing needs to happen with the lighter current tab image. Once we have all four images created, (1,2,3,4) we can jump into the markup and CSS for our tabs.
Tab Creation
As you explore the creation of horizontal lists with CSS, you’ll notice at least two methods for arranging a group of items into one row. Each comes with its own benefits and drawbacks. Both require dealing with rather funky aspects of CSS which quickly become confusing. One uses the inline box, the other uses floats.
The First Method — and possibly the more common — is to change the display of each list item to “inline”. The inline method is attractive for its simplicity. However, the inline method causes a few rendering problems in certain browsers for the Sliding Doors technique we’re going to discuss. The Second Method, which is the one we’ll focus on, uses floats to place each list item in a horizontal row. Floats can be equally frustrating. Their seemingly inconsistent behavior circumvents all natural logic. Still, a basic understanding of how to deal with multiple floated elements, and the means to reliably “break out” of floats (or contain them) can achieve wonders.
We’re going to nest several floated elements within another containing floated element. We do this so that the outer parent float completely wraps around the floats inside. This way, we’re able to add a background color and/or image behind our tabs. It’s important to remember that the next element following our tabs needs to reset its own position by using the CSS clear property. This prevents the floated tabs from affecting the position of other page elements.
Let’s begin with the following markup:

In reality, the #header div might also contain a logo and a search box. For our example, we’ll shorten the href value in each anchor. Obviously, these values would normally contain file or directory locations.
We begin styling our list by floating the #header container. This helps ensure the container actually “contains” the list items inside which will also be floated. Since the element is floated, we also need to assign it a width of 100%. A temporary yellow background is added to ensure this parent stretches to fill the entire area behind the tabs. We also set some default text properties, ensuring everything inside will be the same:
#header {float:left;width:100%;background:yellow;font-size:93%;line-height:normal;}
For now, we also set all of the default margin/padding values of the unordered list and list items to “0”, and remove the list item marker. Each list item gets floated to the left:
#header ul {margin:0;padding:0;list-style:none;}#header li {float:left;margin:0;padding:0;}
We set the anchors to block-level elements so we can control all aspects without worrying about the inline box:
#header a {display:block;}
Next, we add our right-side background image to the list item (changes/additions are bolded):
#header li {float:left;background:url("norm_right.gif")no-repeat right top;margin:0;padding:0;}
Before adding the left-side image, we pause so we can see what we have so far inExample 1. (In the example file, ignore the rule I’ve applied to the body. It only sets up basic values for margin, padding, colors, and text.)
- - -
Now we can place the left-side image in front of the right by applying it to the anchor (our inner element). We add padding at the same time, expanding the tab and pushing the text away from the tab edges:
#header a {display:block;background:url("norm_left.gif")no-repeat left top;padding:5px 15px;}
This gives usExample 2. Note how our tabs have begun to take shape. At this point, a word of acknowledgement to confused IE5/Mac users, who are wondering, “What’s going on here? The tabs are stacked vertically and stretch across the entire screen.” Don’t worry, we’ll get to you soon. For now, do your best to follow along, or temporarily switch to another browser if one is handy, and be assured we’ll fix the IE5/Mac issue shortly.
- - -
Now that we have the background images in place for normal tabs, we need to change the images used for the “current” tab. We do this by targeting the list item which contains id="current" and the anchor inside it. Since we don’t need to alter any other aspects of the background, other than the image, we use the background-image property:
#header #current {background-image:url("norm_right_on.gif");}#header #current a {background-image:url("norm_left_on.gif");}
We need some kind of border along the bottom of our tabs. But applying a border property to the parent #header container won’t allow us to “bleed” the current tab through this border. Instead, we create a new image with the border we want included along the bottom of the image. While we’re at it, we also add a subtle gradient so it looks like this:

We apply that image to the background of our #header container (instead of the yellow color we had), push the background image to the bottom of the element, and use a background color matching the top of this new image. At the same time, we remove the padding from the body element I originally inserted for us, and apply 10 pixels of padding to the top, left, and right sides of the ul:
#header {float:left;width:100%;background:#DAE0D2 url("bg.gif")repeat-x bottom;font-size:93%;line-height:normal;}#header ul {margin:0;padding:10px 10px 0;list-style:none;}
To complete the tab effect, we need to bleed the current tab through the border, as mentioned above. You might think we would apply bottom borders to our tabs matching the border color in the #header background image we just added, then change the border color to white for the current tab. However, doing this would result in a tiny “step” visible to pixel-precision eyes. Instead, if we alter the padding of the anchors, we can create perfectly squared-off corners inside the current tab, as the magnified example below shows:

We do this by decreasing the bottom padding of the normal anchor by 1 pixel (5px - 1px = 4px), then adding that pixel back to the current anchor:
#header a {display:block;background:url("norm_left.gif")no-repeat left top;padding:5px 15px 4px;}#header #current a {background-image:url("norm_left_on.gif");padding-bottom:5px;}
The change allows the bottom border to show through for normal tabs, but hides it for the current tab. This brings our code up toExample 3.
Finishing Touches
Keen eyes may have noticed white tab corners showing up in the previous example. These opaque corners are currently preventing the image in the back from showing through the left corner of the image in front. In theory, we could attempt to match the corners of the tab images with a portion of the background behind them. But our tabs can grow in height, which pushes the background behind them lower, shifting the background color we tried to match. Instead, we change the images, making the corners of our tabs transparent. If the curves are anti-aliased, we matte the edges to an average of the background color behind them.
Now that the corners are transparent, a piece of the right-side image shows through the corner of the left-side image. To compensate for this, we add a small amount of left padding to the list item equivalent to the width of the left-side image (9px). Since padding was added to the list item, we need to remove that same amount from the anchor to keep the text centered (15px - 9px = 6px):
#header li {float:left;background:url("right.gif")no-repeat right top;margin:0;padding:0 0 0 9px;}#header a {display:block;background:url("left.gif")no-repeat left top;padding:5px 15px 4px 6px;}
However, we can’t leave it at that either, because our left-side image now gets pushed away from the left tab edge by the 9 pixels of padding we just added. Now that the inner edges of the left and right visible doorways butt up against each other, we no longer need to keep the left image in the front. So we can switch the order of the two background images, applying them to opposite elements. We also need to swap the images used for the current tab:
#header li {float:left;background:url("left.gif")no-repeat left top;margin:0;padding:0 0 0 9px;}#header a, #header strong, #header span {display:block;background:url
_xyz