XHTML Links
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)
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.
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.
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).
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:
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',Note that the
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; "
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:
- Avoid 'color: inherit' in inline CSS (the
style
attribute). It won't work in Internet Explorer. Use 'color: #XXXXXX' (or other specific declarations) instead. - You can use 'border-bottom' as a more flexible, and subtle alternative to 'text-decoration: underline'. Avoid any CSS borders if you want to support very old browsers like Netscape 4.
- Avoid dotted borders of width 1px/1pt/0.09em or less. IE will do dashed borders instead.
- Avoid dotted borders of width 3px/2pt/0.2em or more if you want them to look the same in major browsers. IE will do diamond-shaped or round dots.
- Double border width has to be 3px/2pt/0.2em or more to be visible on your display (may work differently in print).
- Don't hide links from your audience. Make them obvious with color (or colored underline) as a minimum. Leave them unstyled (blue and underlined) if your visitors are internet beginners.
- Avoid wide borders and 3D-borders if you're a cross-browser perfectionist. Independantly colored borders is a good alternative to the CSS 3D-styles ().
- Give a thought to old browsers without (or limited) CSS support. With only a groove border of background color on your links, some people (<1%) will never see your link at all.
- Most of the above applies to any element (not only to links), but the quirks are more critical for links since we want people to find them, and percieve them as links.
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:
:link
This is the link pseudo-class for for unvisited links. In (X)HTML it is only applicable toa
elements withhref
attributes. CSS Example:a:link {color: red}
makes an (unvisited) link red. The browsers have blue underlined text as the default setting for this class.:visited
This is the link pseudo-class for for visited links. It's used as the:link
pseudo-class. CSS Example:a:visited {color: green}
makes a link green if the url it refers to (in thehref
attribute) has been visited (lately). The browsers have purple underlined text as the default setting for this class. After some experiments, I found that there are differences in how this class is applied to a link. Opera will apply the class when the mousebutton is released (even if the link is dead). IE won't apply it until the new page starts to load, so you won't see the change if the page is loading in the same window. The class is applied even if the link is dead. Firefox goes further. It doesn't apply the 'visited' pseudo class until the page is found. A dead link is not considered visited, which may be logical, but not very helpful. I may want to know that I have tried to follow a link.
a
elements with href
attributes.
:focus
The focus pseudo class isn't supported at all in Opera. IE has a focus state for links but applies the active pseudo class settings to links that are focused. Focus can be achieved with the tab key. Pushing it moves the focus from one link (or other input element) to the next through the document. A mouse click also gives focus to a link (or other user input element). In IE and Firefox, focus is indicated by a dotted gray line around the link, regardless of any CSS styling. There is no special deafualt styling in the browsers. Remember to put your CSS for this class after the link pseudo-classes, and before the other dynamic classes. Having a link pseudo class after a dynamic pseudo class, in your style sheet, will cancel the dynamic effect.:hover
This is the dynamic pseudo-class that corresponds to the mouseover event. It works in most browsers, but none of them have a default style setting. There is no effect until you specify it in your CSS. Unfocused links will allways get the specified styling on mouseover. If a link is focused (not applicable to Opera) the effect is cancelled if there is focus declaration after the hover declaration. If you want your hover declarations to have higher priority, you need to put them after the focus (for Firefox) and active (IE) declarations.:active
This should be the equivalent of a mousedown event, but browsers implement the class differently. With default CSS values (the settings a browser has before an author add CSS to any links), Firefox does the right thing: A link becomes active, and this is indicated with color on the link text (red is the default), when the mouse button is held down. This styling is cancelled however, when any style is specified for any of the link pseudo-classes. When the button is released, the link goes back to the state it had before the click. IE and Opera are different. They do have support for the pseudo class, but no default styling properties. A mousedown action doesn't change the color unless you add styling to the pseudo-class. Opera goes back to the original state before the link is followed. In IE the state is active until the new page loads. You wont see it going back to 'link' or 'visited' (if the link opens in the same window). IE will use the CSS for this pseudo element when a link is focused (and Opera doesn't supprt focus), so you may want to use the same styling for active and focus.
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.
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.
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.Copyright © 2003-2006 Carpe Design. All rights reserved.