XHTML Links

BY TOM HERMANSSON SNICKARS
Just as I explored form buttons in more depth, I would like to do something similar about (X)HTML links. They can be just as simple as writing <a href="..." >link text</a>, but there are a lot of interesting things to explore beyond that. With some images, CSS, and javascript there are virtually no limits, but I have some goals here. I want to have validating and uncluttered XHTML mark-up, separate stylesheet, no image files (at least not in the mark-up), and links that look the same in the major browsers (at least the newer ones). Let's start from scratch, with the simple code above:
This is a link without styling.
There are a few things to note right away. Links turn blue (or purple for visited links) and get underlined as a default setting in most browsers. This is what we are used to, and fortunately different browsers all do the same thing. Links also inherit a lot of styling from it's parent element (font settings, letter-spacing, etc.). That is also fine, and expected behavior. One more thing to note here is that links are inline elements (read up on the CSS display property if you want to explore this further). So one thing I will experiment with is to change the display property to 'block' (or 'run-in' or 'compact'). For now I'll just show you some ways to vary the static look of a link as an inline element.
This is a link with font settings. There are changes made to the letter-spacing property, and most font properties.

Links with text-decoration settings:     underline    overline    line-through    none    blink  (Don't use blink unless you really want to annoy people! It won't work in IE, which is fine with me. Firefox blinks faster than Opera)
Let's also try to do some color changes:
This is a link with inherited color. This does not work in IE. With Firefox and Opera you can simply put 'color:inherit;' in your style attribute.

This is a red link. This works in all browsers. Some people argue that links should always be blue, and underlined. I say it depends on your audience. Make links obvious to your guests, but allow some changes to make it look good. Very few users will be confused by moderatly styled links.

This is a link with background-color.
If you don't need to support old browsers like Netscape 4 you may also want to experiment with borders as an alternative to the default settings and their limided variations. CSS borders may not show up the oldest browsers, and may even stop your links from working, but they give you a lot more freedom: The line under your link text can have a different color than the text itself. The thickness/width can be set in pixels (or other units), and you can even have dotted, double and dashed lines. See more below:
This is a link with 2px colored border.

Link with 2px dashed border.

Link with double border. The border width has to be 3px/2pt/0.2em or more.

Link with dotted 1px border. This is not supported by Internet Explorer (version 6.x and earlier). Thin (1px) dotted borders turn into dashed borders in IE. With even thinner borders (and different width units) even Firefox and Opera have problems. In Opera the border becomes invisible, and in FF they turn into dashes like in IE.

Link with dotted 2px border. This works in Internet Explorer. And it looks the same in Firefox (1.5) and Opera (8). If you want dotted borders that look exactly the same in major browsers (on any element) you have to use a border width of 2px. Avoid the pt, em, and % units for dotted borders, if you want them to look good.

Link with 3px dotted border. This works, but looks different in the three browsers. IE produces round dots, but with this border width they look like little stars or diamonds, rather than dots. Opera and Firefox produce square dots, but Opera puts them closer together.

Link with 7px dotted border. With wide/thick borders you get new problems with the following line. IE now has round dots for higher width values. Opera and Firefox look almost the same with their square dots.

Borders can also have a 3D-look with these border-styles: 'groove', 'ridge', 'outset', 'inset':
This is a link with a 2px groove border. The width has to be 2px or more. It looks different in the three browsers, but they all use the same strategy. They draw two lines with different brightness to give an illusion of a 3D-groove in the surface, lit up by a light source above the screen. I use a border with the same color as the background here, so you only see the effects from the browser's treament of the color changes. Firefox and Opera looks better with these settings. Somehow IE doesn't get it right here, but with other colors the browser does ok (but never really good).

Link with groove border (4px). The effect is easier to study with a wider border.

Link with ridge border (2px). The same priciple, but here the brighter border is above the darker one.

Link with ridge border (4px).

Link with outset border (2px), and padding (2px). Border on all sides to give the link a 'button look'.

Link with inset border (2px), and padding (2px).

None of the 3D border-styles ('groove', 'ridge', 'outset', 'inset') look the same in the major browsers, and IE (the most common browser) doesn't do a good job with them. One cross-browser solution is to use the solid border-style, and optionally style the borders indepenently:
Link with solid border (width: 2px and padding: 1px 4px).

Link with custom outset border (2px), and padding (1px/4px). The borders are styled independently to look better in IE, and the same in all browsers. The idea is to make the top and left borders slightly brighter than the background, and the right and bottom borders slightly darker than the background. This gives a subtle 3D-effect suggesting a light source in the upper left corner of the screen. The small differences in color gives the impression of a very low 3D-profile or a more ambient light. In this example i use the following border-color settings: '#ddd #aaa #aaa #ddd' ('top' 'right' 'bottom' 'left'). The background-color is set to #ccc.

Link with custom inset border (2px), and padding (1px/4px). In this example i use the following border-color settings: '#999 #eee #eee #999' ('top' 'right' 'bottom' 'left').

Link with custom groove border. To get the groove (or ridge) effect without using the CSS property values, we need two lines with different color. In this example a span tag is wrapped around the link to get a second bottom-border, so it's not perfect if we want really clean markup. There is also a browser difference here that makes the styling tricky. Firefox and Opera doesn't wrap the span border properly around the a tag. I solve this by setting a negative margin (margin: -2px;) on the link, which is not very logical, but works (and looks the same) in IE, Opera, and Firefox. The border-bottom settings for the span and a elements: '1px solid #eee' and '2px solid #999' respectively.

Link with custom ridge border The border-bottom settings for the span and a elements: '2px solid #999' and '1px solid #eee' respectively. The “negative margin hack” is here also.

Link with custom styling (2px custom border, 1px/6px padding, white text, blue background, Font: 'Trebuchet MS'). It may look like a button but it's still just a styled inline element, so be prapared for some surprises if you have long link texts that wrap around to the next line. It works fine, but may not look that good:

Link with custom styling This example combines the span wrapper with the coulored 3D-link above. Browser quirks are fixed with a “negative margin CSS hack”.

Link that looks like a button until it reaches the end of the line, so don't go crazy with too much fancy CSS where it doesn't make sense. To get around this problem you can make your link into a block element. More about that below.

And finally, a 3D-link with background image
The style declaration for this link looks like this:
style="color: #666; font: 16px 'Trebuchet MS',
  Verdana, Helvetica, sans-serif bold;
  background-color: #09f;
  background-image: url(images/bg1.jpg);
  text-decoration: none;
  border: 2px solid; color: #fff;
  border-color: #7bf #07c #07c #7bf;
  cursor: default;
  padding: 1px 6px; "
Note that the cursor property is set to 'default' here (an arrow instead of a hand). Use that possibility with moderation. We are all used to the 'hand' cursor on links, so this may confuse your visitors. The link is now more difficult to distinguish from a proper form button.
So there are some browser quirks and differences even with static links like the ones above. Most of them are general differences in CSS compliance. The conclusions so far:
Link behavior: The links above have no 'mouseover' or 'hover' effect, but they do change when we click on them. The default settings for these states are different in different browsers though. Let's start with finding the basic states a link kan have and their corresponding CSS pseudo classes. There are two link pseudo-classes, and three dynamic pseudo-classes: According to the W3C standard (CSS 2.1), all dynamic pseudo-classes can be used with any (X)HTML element, but Internet Explorer does not support them for other elements than a elements with href attributes. The conclusions and tips: You have to care about the order of the pseudo-elements. Put the link pseudo-elements first in you CSS, then the focus, active, and hover classes, in that order (unless you have some very special design needs). CSS selector pseudo-elements can not be specified in an elements style attribute. You need to put your CSS in a style element or a separate CSS-file. Let's try it out. The following CSS specifies some different foreground colors for the five pseudo classes:
a:link    { color: blue }
a:visited { color: purple }
a:focus   { color: red }
a:hover   { color: green }
a:active  { color: red }
Link to Google.com. This should be a purple link if you have visited www.google.com. On mouseover it should turn green. When the (left) mouse button is pushed (and held down), and when focused (not for Opera), it should be red.

Link to abc.def.ghi. This should be a blue link if you havn't visited abc.def.ghi. If you try to follow the link and then return here, the link should be red and focused (except in Opera). Clicking anywhere on the page will blur ('un-focus') the link. Only Firefox agree that you havn't been to the URL that doesn't exist.
This gives us a cross-browser behavior with four states ('link', 'visited', 'hover' and 'active/focused'). That's the best we can do right now, if we want all browsers to have the same look and feel. Since we have the same property values for focused and active links, it may be tempting to group the two like this: a:focus, a:active {color:red}. Don't do it! It will ruin the order of the classes and give 'hover' priority over 'active'. That would cancel the active-style, since you allways are 'mouseover' if you are 'mousedown' on a link.
To make your CSS smaller you may put common styling before the specific styling of each pseudo-class, but color: and text-decoration: will be over-ridden by browser defaults for links.
Let's try some more dynamic links:
Styled link with dynamic behavior. The benefits of using CSS borders are exploited in this example. The dotted line turns solid orange on mouseover. On mousedown the text and background color is changed.

Styled link with hidden button effect. A link styled like a 3D-button appears on mouseover, and is pushed in on mousedown.

Link styled as a button On mouseover the 3D-effect is more accentuated and the text is brighter. On mousedown the color changes to orange. A focused, but not active, button have black text (not possible in IE and Opera).

Link styled as a button This button gets help from a span element to form an inset border around the link itself.

Button with background-image Two repeated background-images are used for this link (around 500 bytes each). One for the 'link', 'visited', and 'hover' states, and one for the 'active' and 'focus' states. Only the foreground (text) color is changed on mouseover. This, and the image swap is controlled in the CSS, so your HTML is kept uncluttered. The images used can be repeated horizontally, but you're stuck with a certain height in this example. This gives you a button that can expand to whatever width you need in each link, but you cannot do much about line-height or font-size. Neither can you have nice rounded corners with this kind of button. Internet Explorer 6.x has a problem with background-swapping in CSS. It tends to 'forget' one of the backgrounds, so there may be an annoying delay or flicker effect (fixed here). Opera also has a problem. It doesn't seem to load the second image until it's time to display it. See more about the solutions to these problems below.

So, links can have nice styling and some dynamic behavior, without cluttering our markup with things like onMouseOver="doStuff();" etc. Using colors and borders can also give us some nice cross-browser 3D-effects. With background images we get more design freedom, but less flexibility. Keeping the link text in the markup, and repeated backgrounds in the stylesheet is a good compromise. This gives us links that can expand to fit the link text (or button label). Putting your link in a container element linke span can add some nice effects, but it also clutters your markup. Adding the span element from a script may be a solution if clean (X)HTML is a requirement.
In all of the above examples the a element has the default display property setting, which is inline. That's fine for regular links in most cases, but what if we want button-like links with a fixed width, or buttons that can be floated, or automatically expand to fit the width of its container? Well, then we need to change the display property to block. Block elements can have width and can be floated. Without float and width ('width: auto;') the block takes up the full width of its container/parent element. Let's try:
Link as a block elementA dashed border is added so we can see how the link behaves. Apart from that, only the display property is changed (to 'block'). The block expands to fit its parent element, minus the parent's padding. The text-align is set to 'center'.
Link as a floated block When the float property is set to 'left' (as in this example) or 'right' the width changes. According to W3C's CSS 2.1 recommendation, a float must have an explicit width. This one hasn't, but all three browsers adjust the width to fit the link text (the element's content width). This may be useful (even though it's not entirely 'legal' CSS). This link also has a margin of 10px. Normally a floated block element causes IE to produce a double left-margin. Fortunately there is a simple hack for this bug: 'display: inline'. A float should always be considered a block element according to the standard, so this declaration should not do any harm. For some reason it also fixes the IE-bug. Read more about it here.
Floated link with fixed width This link is 250px wide, and floated to the right. It has a padding of 10px, and a margin of 10px. Margins are not collapsed with floated blocks, so on the right of the link's block you find the container's padding plus the link's margin.
All three alternatives work in IE, Firefox, and Opera, but more complicated (more realistic) situations may still cause unexpected behavior. At least one IE bug shows upp if you add several floated boxes to a container. I suggest you read up on the CSS float model, the float bugs, and some known hacks if you get into trouble. These problems are common to floated elements in general, not only links. Check out this link button test page for an example with three different block element buttons in one container div: buttons.htm
Button This floated button uses 6 background-images (around 0.5 kB each). The middle part of the button works like the background button above. In addition, the left and right parts of the button uses two images each. The background-images of all three parts changes on mousedown. The foreground color changes on mouseover. The effects are handled by CSS, but extra (X)HTML tags are needed to hold the three backgrounds. If you want uncluttered mark-up you can add these with some unobtrusive DOM-scripting. This button has the same limitations as this button. The lable is plain text or any styled content, and the width depends on the label, but your stuck with a certain button height (depending on your background-images).
Attributes: In the W3C recommendation you can find all possible attributes for the a tag. Some are rarely used, but there is not much that can go wrong. How to use the attributes is beyond the scope of this article but there is one thing I should mention. If you want to have validating pages you should be careful with the target attribute. It's not allowed in strict XHTML. Avoid it or use the transitional, or the frameset doctype.