#精通CSS高级Web标准解决方案
#Chapter 5 Styling Links
In this chapter you will learn about
• Ordering your link selectors based on the cascade
• Creating stylized link underlines
• Styling external links using attribute selectors
• Making links behave like buttons
• Creating visited-link styles
• Creating pure CSS tooltips
##Simple link styling
The easiest way to style a link is to use the anchor type selector. For instance, this rule will make
all anchors red:
a {color: red;}
The first anchor contains a fragment
identifier, and when the user clicks that anchor, the page will jump to the second named anchor:
<p><a href="#mainContent">Skip to main content</a></p>
...
<h1><a name="mainContent">Welcome</a></h1>
CSS has two special selectors called link pseudo-class selectors. The
:link pseudo-class selector is used to target links that have not been visited, and the :visited
pseudo-class selector is used to target visited links. In this example, all unvisited links will be
blue, and all visited links will be green:
a:link {color: blue;} /* Makes unvisited links blue */
a:visited {color: green;} /* Makes visited links green */
The other two selectors you can use for styling links are the :hover and :active dynamic pseudoclass
selectors. The :hover dynamic pseudo-class selector is used to target elements when they
are hovered over, and the :active dynamic pseudo-class selector targets elements when they
are activated. In the case of links, activation occurs when the link is clicked. In this example, links
will turn red when hovered over or clicked:
a:hover, a:active { color: red;}
To ensure your pages are as accessible as possible, it is always a good idea to add a :focus
pseudo-class to your links when defining hover states. This will allow your links to take on the
same styles when they are tabbed to using the keyboard as they have when hovered over using
the mouse.
a:hover, a:focus { color: red;}
Other elements can also use the :hover, :active, or :focus pseudo-class selectors. For
instance, you could add a :hover pseudo-class on your table rows, an :active pseudo-class on
your submit buttons, or a :focus pseudo-class on your input fields to highlight various forms of
interactivity. Unfortunately, IE 7 and below don’t support the use of pseudo-class selectors on
anything other than links, but all modern browsers do.
/* makes table rows yellow when hovered over */
tr:hover {
background: yellow;
}
/* makes submit buttons in some browsers yellow when pressed */
input[type="submit"]:active {
background:yellow;
}
/* makes inputs yellow when selected */
input:focus {
background:yellow;
}
One of the first things most people learn to use these selectors for is turning off the underline for
links, and then turning them back on when they are hovered over or clicked. This can be done by
setting the text-decoration property to none for unvisited and visited links and to underline for
hovered or active links:
a:link, a:visited {text-decoration: none;}
a:hover, a:focus, a:active {text-decoration: underline;}
In the previous example, the order of the selectors is very important. If the order is reversed, the
hover and active styles won’t work.
a:hover, a:focus, a:active {text-decoration: underline;}
a:link, a:visited {text-decoration: none;}
The reason for this is the cascade. In Chapter 1, you learned that when two rules have the same
specificity, the last rule to be defined wins out. In this situation, both rules have the same
specificity so the :link and :visited styles will override the :hover and :active styles. To make
sure this doesn’t happen, `it’s a good idea to apply your link styles in the following order:
a:link, a:visited, a:hover, a:focus, a:active
An easy way to remember this order is the phrase “Lord Vader Hates Furry Animals,” where L
stands for link, V stands for visited, H for hover, F for focus, and A for active.`
###Simple link embellishments
Designers tend to dislike link underlines, as they add too much weight and visual clutter to a
page. If you decide to remove link underlines, you could choose to make links bold instead. That
way, your page will look less cluttered, but the links will still stand out:
a:link, a:visited {
text-decoration: none;
font-weight: bold;
}
You can then reapply the underlines when the links are hovered over or activated, reinforcing
their interactive status:
a:hover, a:focus, a:active {
text-decoration: underline;
font-weight: bold;
}
However, it is possible to create a low-impact underline using borders instead. In the following
example, the default underline is removed and replaced with a less obtrusive dotted line. When
the link is hovered over or clicked, this line turns solid to provide the user with visual feedback
that something has happened:
a:link, a:visited {
text-decoration: none;
border-bottom: 1px dotted #000;
}
a:hover, a:focus, a:active {
border-bottom-style: solid;
}
###Fancy link underlines
You can create some very interesting effects by using images to create your link underlines.For
instance, I have created a very simple underline graphic comprised of diagonal lines (see Figure
5-1).
You can then apply this image to your links using the following code:
a:link, a:visited {
color:#666;
text-decoration: none;
background: url(/img/underline1.gif) repeat-x left bottom;
}
You do not have to stop with link and visited styles. In this example, I have created an animated
GIF for the hover and active states, which I apply using the following CSS:
a:hover, a:focus, a:active {
background-image: url(/img/underline1-hover.gif);
}
When you hover over or click the link, the diagonal lines appear to scroll from left to right, creating
an interesting pulsing or poling effect. Not all browsers support background image animations, but
those that do not will usually display the first frame of the animation, ensuring that the effect
degrades nicely in older browsers.
hint:Remember to use animation carefully, as it can cause accessibility problems
for some users. If in doubt, always remember to check the Web Content
Accessibility Guidelines (WCAG 1.0) at www.w3.org/TR/WAI-WEBCONTENT.
##Visited-link styles
Designers and developers often forget about the visited-link style and end up styling visited links
the same as unvisited ones. However, a separate visited-link style can help orientate users,
showing them which pages or sites they have already visited and avoiding unnecessary
backtracking.
You can create a very simple visited-link style by adding a check box to every visited link:
a:visited {
padding-right: 20px;
background: url(/img/check.gif) no-repeat right middle;
}
##Styling link targets
As well as linking to a specific document, you can use a link containing a fragment identifier to
point people to a particular part of a page.` You do this by adding a hash character, followed by
the ID of the element you want to link to, at the end of your href.` This can be extremely useful if
you want point to a specific comment in a long comment thread.For instance, say I wanted to link to the third comment on this page.
<a href="http://example.com/story.htm#comment3">
A great comment by Simon
</a>
When you click the preceding link, you will be taken to the appropriate document, and the page
will scroll down to the comment3 element. Unfortunately, if the page is quite busy, it is often
difficult to tell to which element the link has sent you. To get around this problem, `CSS 3 allows
you to style the target element using the :target pseudo-class. `In this next example, I am going
to highlight the target element by giving it a yellow background (see Figure 5-3).
.comment:target {
background-color: yellow;
}
If you wanted to be even cleverer, you could choose to give the element an animated background
image that fades from yellow to white, thus simulating the yellow fade technique popularized by
companies like 37 Signals.
.comment:target {
background-image: url(img/fade.gif);
}
The target selector is supported by all recent versions of Safari and Firefox, but isn’t supported
by Internet Explorer at the time of writing.
##Highlighting different types of links
On many sites, it is difficult to tell if a link points to another page on that site or to a different site
altogether. We have all clicked a link expecting it to go to another page in the current site, only to
be whisked away somewhere different and unexpected.
A better solution would be to indicate external links somehow and let the user decide to leave the
site, open the link in a new window, or more probably these days, open it in a new tab. You can
do this by adding a small icon next to any external links.
The easiest way to include an external link icon on your page is to add a class to any external
links and apply the icon as a background image. In this example, I have created space for the
icon by giving the link a small amount of right padding and then applied the icon as a background
image at the top right of the link (see Figure 5-5).it is not a particularly smart as you
have to manually add your class to each external link.
.external {
background: url(/img/externalLink.gif) no-repeat right top;
padding-right: 10px;
}
As you learned in Chapter 1, attribute selectors allow you to target an element based on the
existence or value of an attribute. CSS 3 extends the ability with substring matching. As the name
suggests, these selectors allow you to target an element by matching your chosen text to part of
the attribute’s value. CSS 3 is not an official specification yet, so using these advanced selectors
may invalidate your code. However, the majority of standards-compliant browsers support these
nifty CSS 3 selectors.
This technique works by first targeting any links that start with the text http: using the [att^=val]
attribute selector:
a[href^="http:"] {
background: url(/img/externalLink.gif) no-repeat right top;
padding-right: 10px;
}
This should highlight all external links. However, it will also pick up internal links using absolute
rather than relative URLs. To avoid this, you need to reset any links to your own site by removing
the external link icon. This is done by matching links that point to your domain name, removing
the external link icon, and resetting the right padding (see Figure 5-6).
a[href^="http://www.yoursite.com"],
a[href^="http://yoursite.com"] {
background-image: none;
padding-right: 0;
}
You could even highlight nonstandard protocols such as the AOL instant messaging protocol
(AIM), with a little AIM buddy icon (see Figure 5-7):
a[href^="aim:"] {
background: url(img/im.png) no-repeat right top;
padding-right: 10px;
}
<a href="aim:goim?screenname=andybudd">instant message</a>
###Highlighting downloadable documents and feeds
Another common frustration is clicking a link thinking it will take you to a page and discovering
that the site has started downloading a PDF or Microsoft Word document. Luckily, `CSS can help
us distinguish these types of links as well. This is done using the [att$=val] attribute selector,
which targets attributes that end in a particular value, such as .pdf or .doc`:
a[href$=".pdf"] {
background: url(img/pdfLink.gif) no-repeat right top;
padding-right: 10px;
}
a[href$=".doc"] {
background: url(img/wordLink.gif) no-repeat right top;
padding-right: 10px;
}
Last, many people have RSS feeds on their websites. The idea is for people to copy these links
into their feed readers. However, inadvertently clicking one of these links may take you to a page
of seemingly meaningless data. To avoid possible confusion, you could highlight RSS feeds using
a similar method, with your own RSS icon:
a[href$=".rss"], a[href$=".rdf"] {
background: url(img/feedLink.gif) no-repeat right top;
padding-right: 10px;
}
All these techniques can help to improve the user experience on your site.
hint:Unfortunately, IE 6 and below don’t support the attribute selector. Luckily, you
can create a similar effect by adding a class to each element using JavaScript
and the DOM. One of the best ways to do this is with Simon Willison’s excellent
getElementBySelector function; you can find more details at
http://simonwillison.net/2003/Mar/25/getElementsBySelector/.
Alternatively, jQuery allows you to do something very similar.
##Creating links that look like buttons
Anchors are inline elements, which means they only activate when you click the contents of the
link. However, there are instances when you may want to create more of a button-like effect with
a larger clickable area. You can do this by setting the display property of the anchor to block and
then changing the width, height, and other properties to create the style and hit area you desire.
a {
display: block;
width: 6.6em;
line-height: 1.4;
text-align: center;
text-decoration: none;
border: 1px solid #66a300;
background-color: #8cca12;
color: #fff;
}
The resulting link should now look like Figure 5-8.
With the link now displaying as a block-level element, clicking anywhere in the block will activate
the link.
If you look at the CSS, you’ll see that the width has been explicitly set in ems. By their nature,
block-level elements expand to fill the available width, so if the width of their parent elements
were greater than the required width of the link, you would need to apply the desired width to the
link. This would likely be the case if you wanted to use such a styled link in the main content area
of your page. However, if your styled links were going in a sidebar, for example, you would
probably just set the width of the sidebar and not worry about the width of the links.
You may wonder why I am using line-height to control the height of the button instead of
height. Well, this is actually a handy little trick for centering the text in the button vertically. If you
were to set a height, you would probably have to use padding to push the text down and fake
vertical centering. However, text is always vertically centered in a line box, so by using lineheight
instead, the text will always sit in the middle of the box. There is one downside, though. If
the text in your button wraps onto two lines, the button will be twice as tall as you want it to be.
The only way to avoid this is to size your buttons and text in such a way that the text won’t wrap,
or at least won’t wrap until your text size has been increased beyond a reasonable amount.
If you choose to use this technique, make sure that you only use it on things that are actually links
and don’t update the server. Otherwise, you may experience some undesirable results. When
Google accelerator launched, people found that content in their CMS or web application was
mysteriously disappearing. Sometimes, the entire contents of a site would vanish overnight. It
turns out that the authors of these tools had used anchor links rather than form elements for their
delete buttons. Google accelerator would spider these links in order to cache them and
inadvertently delete the content! Search engines spiders can have the same effect, recursively
deleting vast swathes of data. For that reason, you should never use links to make changes on
the server. Or to put it in technical terms, links should only ever be used for GET requests, and
never for POST requests.
###Simple rollovers
In the bad old days, people used large and overly complicated JavaScript functions to create
rollover effects. Thankfully, using the :hover pseudo-class allows us to create rollover effects
without the need of JavaScript. You can extend the previous example to include a very simple
rollover effect simply by setting the background and text color of the link when hovered over (see
Figure 5-9):
a:hover,
a:focus {
background-color: #f7a300;
border-color: #ff7400;
}
### Rollovers with images
for more complicated buttons, you
will probably want to use background images.I have created three button
images: one for the default state, one for the hover and focus states and one for the active state
(see Figure 5-10).
The code for this example is very similar to the preceding example. The main difference is that
background images are being used instead of borders and background colors.
a:link, a:visited {
display: block;
width: 203px;
height: 72px;
text-indent: -1000em;
background: url(/img/button.png) left top no-repeat;
}
a:hover, a:focus { background-image: url(/img/button-over.png);
}
a:active {
background-image: url(/img/button-active.png);
}
This example uses fixed-width and fixed-height buttons, which is why I have set explicit pixel
dimensions in the CSS. To get the exact text treatment I wanted, I have included the button text
on the graphic and then hidden the anchor text off the screen with a large negative text indent.
However, there is nothing to stop you from creating oversized button graphics or using a
combination of background colors and images to create a fluid or an elastic button.
###Pixy-style rollovers
there is another way. Instead of swapping in
multiple background images, use a single image and switch its background position instead.
Using a single image has the added benefit of reducing the number of server requests as well as
allowing you to keep all your button states in one place. This method is known as the Pixy
method after the nickname of its creator, Petr Staníček (you can find more information at his
website: http://wellstyled.com/css-nopreload-rollovers.html).
Begin by creating your combined button image (see Figure 5-11). In this case, I am limiting the
button to an up state, an over state, and an active state. However, you could also include a
visited state if you desired.
The code is almost identical to the previous example. However, this time, you align the
background image so the normal state is in the center and then shift the background to the right
or left for the hover and active states.
a:link, a:visited {
display: block;
width: 203px;
height: 72px;
text-indent: -1000em;
background: url(/img/buttons.png) -203px 0 no-repeat;
}
a:hover, a:focus {
background-position: right top;
}
a:active {
background-position: left top;
}
Unfortunately, Internet Explorer still makes a round-trip to the server to request a new image,
even though all you are doing is changing the alignment of the image. This causes a slight flicker,
which can be a little annoying. To avoid the flicker you need to apply the rollover state to the link’s
parent element, for example, its containing paragraph.
p {
background: url(/img/ buttons.png)
no-repeat right top;
}
The image will still disappear for an instant while it is being reloaded. However, during this time,
the same image will be revealed underneath, hiding the flicker.
An alternate way to remove the flicker is to include the following line of code in your Internet
Explorer specific CSS file, which turns background caching on.
html {
filter: expression(document.execCommand("BackgroundImageCache",
false, true));
}
###CSS sprites
Multiple requests to the server can have a dramatic effect on the performance of your site, so the
Pixy method aims to reduce the number of requests by including all your button states in a single
image. But why stop there? Why not go one step further and include all your icons or even your
site navigation in a single image? That way, you could reduce the number of calls to the server
from multiple figures to just two or three. This is exactly what CSS sprites are—a single image
containing a multitude of different icons, buttons, or other graphics. Many large websites use this
technique including the Yahoo! homepage. In fact, we use the same technique for the Clearleft
site navigation (see Figure 5-12).
#nav li a {
display: block;
text-indent: -9999px;
height: 119px;
width: 100px;
background-image: url('/img/nav.png');
background-repeat: no-repeat;
}
#nav li.home a,
#nav li.home a:link,
#nav li.home a:visited {
background-position: 0 0;
}
#nav li.home a:hover,
#nav li.home a:focus,
#nav li.home a:active {
background-position: 0 -119px;
}
#nav li.who-we-are a,
#nav li.who-we-are a:link,
#nav li.who-we-are a:visited {
background-position: -100px 0;
}
#nav li.who-we-are a:hover,
#nav li.who-we-are a:focus,
#nav li.who-we-are a:active {
background-position: -100px -119px;
}
By using this technique, you can cut down on the requests the web browser makes to your
server, considerably speeding up the download times. Furthermore, using sprites keeps all your
buttons, icons, and miscellaneous graphics in one location, improving maintainability. So it’s a
win-win situation.
###Rollovers with CSS 3
CSS 3 includes a number of properties like text-shadow, box-shadow, and border-radius that
make it possible to create heavily styled buttons that require no images whatsoever. To create
such a button, I will start with the code from our first example:
a {
display: block;
width: 6.6em;
height: 1.4em;
line-height: 1.4;
text-align: center;
text-decoration: none;
border: 1px solid #66a300;
background-color: #8cca12;
color: #fff;
}
Next, I’ll add curved borders and a drop shadow. I’m also going to give the button text a subtle
drop shadow (see Figure 5-13).
a {
display: block;
width: 6.6em;
height: 1.4em;
line-height: 1.4;
text-align: center;
text-decoration: none;
border: 1px solid #66a300;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;
background-color: #8cca12;
color: #fff;
text-shadow: 2px 2px 2px #66a300;
-moz-box-shadow: 2px 2px 2px #ccc;
-webkit-box-shadow: 2px 2px 2px #ccc;
box-shadow: 2px 2px 2px #ccc;
}
Figure 5-13. A rounded corner button using only CSS
To re-create the gradient, Safari 4 beta supports a proprietary value called -webkit-gradient.
While I would never normally recommend the use of proprietary code, this may provide a hint of
where CSS is heading in the future. This proprietary value takes a number of different arguments
including the type of gradient (liner or radial), the direction of the gradient (in this case, top-left to
bottom-left), a starting color, an end color, and any stops along the way. Obviously, if you didn’t
want to use this proprietary code, you could simply produce your own background image gradient
instead.
a {
display: block;
width: 6.6em;
height: 1.4em;
line-height: 1.4;
text-align: center;
text-decoration: none;
border: 1px solid #66a300;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;
background-image: -webkit-gradient(linear, left top, left bottom,
from(#abe142), to(#67a400));
background-color: #8cca12;
color: #fff;
text-shadow: 2px 2px 2px #66a300;
-moz-box-shadow: 2px 2px 2px #ccc;
-webkit-box-shadow: 2px 2px 2px #ccc;
box-shadow: 2px 2px 2px #ccc;
}
Last, Safari includes another proprietary property called box-reflect, which as the name
suggests, allows you to create reflections of an object. This property contains a number of
different arguments including the position and distance of the reflection along with a masking
image. Interestingly, you can use the –webkit-gradient value to automatically generate this
mask. In this instance, I’m positioning the reflection 2 pixels below the button and using a mask
that fades to white (see Figure 5-14).
a {
display: block;
width: 6.6em;
height: 1.4em;
line-height: 1.4;
text-align: center;
text-decoration: none;
border: 1px solid #66a300;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;
background-image: -webkit-gradient(linear, left top, left bottom,
from(#abe142), to(#67a400));
background-color: #8cca12;
color: #fff;
text-shadow: 2px 2px 2px #66a300;
-moz-box-shadow: 2px 2px 2px #ccc;
-webkit-box-shadow: 2px 2px 2px #ccc;
box-shadow: 2px 2px 2px #ccc;
-webkit-box-reflect: below 2px -webkit-gradient
(linear, left top, left bottom, from(transparent),
color-stop(0.52, transparent), to(white));
}
There is some debate around whether these types of effects should be done using CSS or not, so
it’s uncertain if they will ever make it into the official specification. Because of this and the lack of
cross-browser support, it would be unwise to use these techniques in a production environment.
However, that shouldn’t stop you from playing around with them on your personal sites just as
long as you realize that they’re invalid CSS and may get removed or changed in future versions
of the browser.
Pure CSS tooltips
Tooltips are the little yellow text boxes that pop up in some browsers when you hover over
elements with title tags. Several developers have created their own custom, stylized tooltips using
a combination of JavaScript and CSS. However, it is possible to create pure CSS tooltips by
using CSS positioning techniques. This technique requires a modern, standards-compliant
browser like Firefox to work properly. As such, it is not a technique you would add to your day-today
arsenal. However, it does demonstrate the power of advanced CSS and gives you a hint of
what will be possible when CSS is better supported.
As with all of the examples in this book, you need to start with well-structured and meaningful
HTML:
<p>
<a href="http://www.andybudd.com/" class="tooltip">
Andy Budd<span> (This website rocks) </span></a> is a web developer based in
Brighton England.
</p>
I have given the link a class of tooltip to differentiate it from other links. Inside the link, I have
added the text I wish to display as the link text, followed by the tooltip text enclosed in a span. I
have wrapped my tooltip text in brackets so that the sentence still makes sense with styles turned
off.
The first thing you need to do is set the position property of the anchor to relative. This allows
you to position the contents of the span absolutely, relative to the position of its parent anchor.
You do not want the tooltip text to display initially, so you should set its display property to none:
a.tooltip {
position: relative;
}
a.tooltip span {
display: none;
}
When the anchor is hovered over, you want the contents of the span to appear. This is done by
setting the display property of the span to block, but only when the link is hovered over. If you
were to test the code now, hovering over the link would simply make the span text appear next to
the link.
To position the contents of the span below and to the right of the anchor, you need to set the
position property of the span to absolute and position it 1 em from the top of the anchor and 2
ems from the left.
a.tooltip:hover span {
display: block;
position: absolute;
top: 1em;
left: 2em;
}
hint:Remember, an absolutely positioned element is positioned in relation to its
nearest positioned ancestor or, failing that, the root element. In this example,
we have positioned the anchor, so the span is positioned in relation to that.
And that’s the bulk of the technique. All that is left is to add some styling to make the span look
more like a tooltip. You can do this by giving the span some padding, a border, and a background
color:
a.tooltip:hover span, a.tooltip:focus span {
display:block;
position:absolute;
top:1em;
left:2em;
padding: 0.2em 0.6em;
border:1px solid #996633;
background-color:#FFFF66;
color:#000;
}
In Firefox, the applied technique should look something like Figure 5-15.
#Chapter 5 Styling Links
In this chapter you will learn about
• Ordering your link selectors based on the cascade
• Creating stylized link underlines
• Styling external links using attribute selectors
• Making links behave like buttons
• Creating visited-link styles
• Creating pure CSS tooltips
##Simple link styling
The easiest way to style a link is to use the anchor type selector. For instance, this rule will make
all anchors red:
a {color: red;}
The first anchor contains a fragment
identifier, and when the user clicks that anchor, the page will jump to the second named anchor:
<p><a href="#mainContent">Skip to main content</a></p>
...
<h1><a name="mainContent">Welcome</a></h1>
CSS has two special selectors called link pseudo-class selectors. The
:link pseudo-class selector is used to target links that have not been visited, and the :visited
pseudo-class selector is used to target visited links. In this example, all unvisited links will be
blue, and all visited links will be green:
a:link {color: blue;} /* Makes unvisited links blue */
a:visited {color: green;} /* Makes visited links green */
The other two selectors you can use for styling links are the :hover and :active dynamic pseudoclass
selectors. The :hover dynamic pseudo-class selector is used to target elements when they
are hovered over, and the :active dynamic pseudo-class selector targets elements when they
are activated. In the case of links, activation occurs when the link is clicked. In this example, links
will turn red when hovered over or clicked:
a:hover, a:active { color: red;}
To ensure your pages are as accessible as possible, it is always a good idea to add a :focus
pseudo-class to your links when defining hover states. This will allow your links to take on the
same styles when they are tabbed to using the keyboard as they have when hovered over using
the mouse.
a:hover, a:focus { color: red;}
Other elements can also use the :hover, :active, or :focus pseudo-class selectors. For
instance, you could add a :hover pseudo-class on your table rows, an :active pseudo-class on
your submit buttons, or a :focus pseudo-class on your input fields to highlight various forms of
interactivity. Unfortunately, IE 7 and below don’t support the use of pseudo-class selectors on
anything other than links, but all modern browsers do.
/* makes table rows yellow when hovered over */
tr:hover {
background: yellow;
}
/* makes submit buttons in some browsers yellow when pressed */
input[type="submit"]:active {
background:yellow;
}
/* makes inputs yellow when selected */
input:focus {
background:yellow;
}
One of the first things most people learn to use these selectors for is turning off the underline for
links, and then turning them back on when they are hovered over or clicked. This can be done by
setting the text-decoration property to none for unvisited and visited links and to underline for
hovered or active links:
a:link, a:visited {text-decoration: none;}
a:hover, a:focus, a:active {text-decoration: underline;}
In the previous example, the order of the selectors is very important. If the order is reversed, the
hover and active styles won’t work.
a:hover, a:focus, a:active {text-decoration: underline;}
a:link, a:visited {text-decoration: none;}
The reason for this is the cascade. In Chapter 1, you learned that when two rules have the same
specificity, the last rule to be defined wins out. In this situation, both rules have the same
specificity so the :link and :visited styles will override the :hover and :active styles. To make
sure this doesn’t happen, `it’s a good idea to apply your link styles in the following order:
a:link, a:visited, a:hover, a:focus, a:active
An easy way to remember this order is the phrase “Lord Vader Hates Furry Animals,” where L
stands for link, V stands for visited, H for hover, F for focus, and A for active.`
###Simple link embellishments
Designers tend to dislike link underlines, as they add too much weight and visual clutter to a
page. If you decide to remove link underlines, you could choose to make links bold instead. That
way, your page will look less cluttered, but the links will still stand out:
a:link, a:visited {
text-decoration: none;
font-weight: bold;
}
You can then reapply the underlines when the links are hovered over or activated, reinforcing
their interactive status:
a:hover, a:focus, a:active {
text-decoration: underline;
font-weight: bold;
}
However, it is possible to create a low-impact underline using borders instead. In the following
example, the default underline is removed and replaced with a less obtrusive dotted line. When
the link is hovered over or clicked, this line turns solid to provide the user with visual feedback
that something has happened:
a:link, a:visited {
text-decoration: none;
border-bottom: 1px dotted #000;
}
a:hover, a:focus, a:active {
border-bottom-style: solid;
}
###Fancy link underlines
You can create some very interesting effects by using images to create your link underlines.For
instance, I have created a very simple underline graphic comprised of diagonal lines (see Figure
5-1).
You can then apply this image to your links using the following code:
a:link, a:visited {
color:#666;
text-decoration: none;
background: url(/img/underline1.gif) repeat-x left bottom;
}
You do not have to stop with link and visited styles. In this example, I have created an animated
GIF for the hover and active states, which I apply using the following CSS:
a:hover, a:focus, a:active {
background-image: url(/img/underline1-hover.gif);
}
When you hover over or click the link, the diagonal lines appear to scroll from left to right, creating
an interesting pulsing or poling effect. Not all browsers support background image animations, but
those that do not will usually display the first frame of the animation, ensuring that the effect
degrades nicely in older browsers.
hint:Remember to use animation carefully, as it can cause accessibility problems
for some users. If in doubt, always remember to check the Web Content
Accessibility Guidelines (WCAG 1.0) at www.w3.org/TR/WAI-WEBCONTENT.
##Visited-link styles
Designers and developers often forget about the visited-link style and end up styling visited links
the same as unvisited ones. However, a separate visited-link style can help orientate users,
showing them which pages or sites they have already visited and avoiding unnecessary
backtracking.
You can create a very simple visited-link style by adding a check box to every visited link:
a:visited {
padding-right: 20px;
background: url(/img/check.gif) no-repeat right middle;
}
##Styling link targets
As well as linking to a specific document, you can use a link containing a fragment identifier to
point people to a particular part of a page.` You do this by adding a hash character, followed by
the ID of the element you want to link to, at the end of your href.` This can be extremely useful if
you want point to a specific comment in a long comment thread.For instance, say I wanted to link to the third comment on this page.
<a href="http://example.com/story.htm#comment3">
A great comment by Simon
</a>
When you click the preceding link, you will be taken to the appropriate document, and the page
will scroll down to the comment3 element. Unfortunately, if the page is quite busy, it is often
difficult to tell to which element the link has sent you. To get around this problem, `CSS 3 allows
you to style the target element using the :target pseudo-class. `In this next example, I am going
to highlight the target element by giving it a yellow background (see Figure 5-3).
.comment:target {
background-color: yellow;
}
If you wanted to be even cleverer, you could choose to give the element an animated background
image that fades from yellow to white, thus simulating the yellow fade technique popularized by
companies like 37 Signals.
.comment:target {
background-image: url(img/fade.gif);
}
The target selector is supported by all recent versions of Safari and Firefox, but isn’t supported
by Internet Explorer at the time of writing.
##Highlighting different types of links
On many sites, it is difficult to tell if a link points to another page on that site or to a different site
altogether. We have all clicked a link expecting it to go to another page in the current site, only to
be whisked away somewhere different and unexpected.
A better solution would be to indicate external links somehow and let the user decide to leave the
site, open the link in a new window, or more probably these days, open it in a new tab. You can
do this by adding a small icon next to any external links.
The easiest way to include an external link icon on your page is to add a class to any external
links and apply the icon as a background image. In this example, I have created space for the
icon by giving the link a small amount of right padding and then applied the icon as a background
image at the top right of the link (see Figure 5-5).it is not a particularly smart as you
have to manually add your class to each external link.
.external {
background: url(/img/externalLink.gif) no-repeat right top;
padding-right: 10px;
}
As you learned in Chapter 1, attribute selectors allow you to target an element based on the
existence or value of an attribute. CSS 3 extends the ability with substring matching. As the name
suggests, these selectors allow you to target an element by matching your chosen text to part of
the attribute’s value. CSS 3 is not an official specification yet, so using these advanced selectors
may invalidate your code. However, the majority of standards-compliant browsers support these
nifty CSS 3 selectors.
This technique works by first targeting any links that start with the text http: using the [att^=val]
attribute selector:
a[href^="http:"] {
background: url(/img/externalLink.gif) no-repeat right top;
padding-right: 10px;
}
This should highlight all external links. However, it will also pick up internal links using absolute
rather than relative URLs. To avoid this, you need to reset any links to your own site by removing
the external link icon. This is done by matching links that point to your domain name, removing
the external link icon, and resetting the right padding (see Figure 5-6).
a[href^="http://www.yoursite.com"],
a[href^="http://yoursite.com"] {
background-image: none;
padding-right: 0;
}
You could even highlight nonstandard protocols such as the AOL instant messaging protocol
(AIM), with a little AIM buddy icon (see Figure 5-7):
a[href^="aim:"] {
background: url(img/im.png) no-repeat right top;
padding-right: 10px;
}
<a href="aim:goim?screenname=andybudd">instant message</a>
###Highlighting downloadable documents and feeds
Another common frustration is clicking a link thinking it will take you to a page and discovering
that the site has started downloading a PDF or Microsoft Word document. Luckily, `CSS can help
us distinguish these types of links as well. This is done using the [att$=val] attribute selector,
which targets attributes that end in a particular value, such as .pdf or .doc`:
a[href$=".pdf"] {
background: url(img/pdfLink.gif) no-repeat right top;
padding-right: 10px;
}
a[href$=".doc"] {
background: url(img/wordLink.gif) no-repeat right top;
padding-right: 10px;
}
Last, many people have RSS feeds on their websites. The idea is for people to copy these links
into their feed readers. However, inadvertently clicking one of these links may take you to a page
of seemingly meaningless data. To avoid possible confusion, you could highlight RSS feeds using
a similar method, with your own RSS icon:
a[href$=".rss"], a[href$=".rdf"] {
background: url(img/feedLink.gif) no-repeat right top;
padding-right: 10px;
}
All these techniques can help to improve the user experience on your site.
hint:Unfortunately, IE 6 and below don’t support the attribute selector. Luckily, you
can create a similar effect by adding a class to each element using JavaScript
and the DOM. One of the best ways to do this is with Simon Willison’s excellent
getElementBySelector function; you can find more details at
http://simonwillison.net/2003/Mar/25/getElementsBySelector/.
Alternatively, jQuery allows you to do something very similar.
##Creating links that look like buttons
Anchors are inline elements, which means they only activate when you click the contents of the
link. However, there are instances when you may want to create more of a button-like effect with
a larger clickable area. You can do this by setting the display property of the anchor to block and
then changing the width, height, and other properties to create the style and hit area you desire.
a {
display: block;
width: 6.6em;
line-height: 1.4;
text-align: center;
text-decoration: none;
border: 1px solid #66a300;
background-color: #8cca12;
color: #fff;
}
The resulting link should now look like Figure 5-8.
With the link now displaying as a block-level element, clicking anywhere in the block will activate
the link.
If you look at the CSS, you’ll see that the width has been explicitly set in ems. By their nature,
block-level elements expand to fill the available width, so if the width of their parent elements
were greater than the required width of the link, you would need to apply the desired width to the
link. This would likely be the case if you wanted to use such a styled link in the main content area
of your page. However, if your styled links were going in a sidebar, for example, you would
probably just set the width of the sidebar and not worry about the width of the links.
You may wonder why I am using line-height to control the height of the button instead of
height. Well, this is actually a handy little trick for centering the text in the button vertically. If you
were to set a height, you would probably have to use padding to push the text down and fake
vertical centering. However, text is always vertically centered in a line box, so by using lineheight
instead, the text will always sit in the middle of the box. There is one downside, though. If
the text in your button wraps onto two lines, the button will be twice as tall as you want it to be.
The only way to avoid this is to size your buttons and text in such a way that the text won’t wrap,
or at least won’t wrap until your text size has been increased beyond a reasonable amount.
If you choose to use this technique, make sure that you only use it on things that are actually links
and don’t update the server. Otherwise, you may experience some undesirable results. When
Google accelerator launched, people found that content in their CMS or web application was
mysteriously disappearing. Sometimes, the entire contents of a site would vanish overnight. It
turns out that the authors of these tools had used anchor links rather than form elements for their
delete buttons. Google accelerator would spider these links in order to cache them and
inadvertently delete the content! Search engines spiders can have the same effect, recursively
deleting vast swathes of data. For that reason, you should never use links to make changes on
the server. Or to put it in technical terms, links should only ever be used for GET requests, and
never for POST requests.
###Simple rollovers
In the bad old days, people used large and overly complicated JavaScript functions to create
rollover effects. Thankfully, using the :hover pseudo-class allows us to create rollover effects
without the need of JavaScript. You can extend the previous example to include a very simple
rollover effect simply by setting the background and text color of the link when hovered over (see
Figure 5-9):
a:hover,
a:focus {
background-color: #f7a300;
border-color: #ff7400;
}
### Rollovers with images
for more complicated buttons, you
will probably want to use background images.I have created three button
images: one for the default state, one for the hover and focus states and one for the active state
(see Figure 5-10).
The code for this example is very similar to the preceding example. The main difference is that
background images are being used instead of borders and background colors.
a:link, a:visited {
display: block;
width: 203px;
height: 72px;
text-indent: -1000em;
background: url(/img/button.png) left top no-repeat;
}
a:hover, a:focus { background-image: url(/img/button-over.png);
}
a:active {
background-image: url(/img/button-active.png);
}
This example uses fixed-width and fixed-height buttons, which is why I have set explicit pixel
dimensions in the CSS. To get the exact text treatment I wanted, I have included the button text
on the graphic and then hidden the anchor text off the screen with a large negative text indent.
However, there is nothing to stop you from creating oversized button graphics or using a
combination of background colors and images to create a fluid or an elastic button.
###Pixy-style rollovers
there is another way. Instead of swapping in
multiple background images, use a single image and switch its background position instead.
Using a single image has the added benefit of reducing the number of server requests as well as
allowing you to keep all your button states in one place. This method is known as the Pixy
method after the nickname of its creator, Petr Staníček (you can find more information at his
website: http://wellstyled.com/css-nopreload-rollovers.html).
Begin by creating your combined button image (see Figure 5-11). In this case, I am limiting the
button to an up state, an over state, and an active state. However, you could also include a
visited state if you desired.
The code is almost identical to the previous example. However, this time, you align the
background image so the normal state is in the center and then shift the background to the right
or left for the hover and active states.
a:link, a:visited {
display: block;
width: 203px;
height: 72px;
text-indent: -1000em;
background: url(/img/buttons.png) -203px 0 no-repeat;
}
a:hover, a:focus {
background-position: right top;
}
a:active {
background-position: left top;
}
Unfortunately, Internet Explorer still makes a round-trip to the server to request a new image,
even though all you are doing is changing the alignment of the image. This causes a slight flicker,
which can be a little annoying. To avoid the flicker you need to apply the rollover state to the link’s
parent element, for example, its containing paragraph.
p {
background: url(/img/ buttons.png)
no-repeat right top;
}
The image will still disappear for an instant while it is being reloaded. However, during this time,
the same image will be revealed underneath, hiding the flicker.
An alternate way to remove the flicker is to include the following line of code in your Internet
Explorer specific CSS file, which turns background caching on.
html {
filter: expression(document.execCommand("BackgroundImageCache",
false, true));
}
###CSS sprites
Multiple requests to the server can have a dramatic effect on the performance of your site, so the
Pixy method aims to reduce the number of requests by including all your button states in a single
image. But why stop there? Why not go one step further and include all your icons or even your
site navigation in a single image? That way, you could reduce the number of calls to the server
from multiple figures to just two or three. This is exactly what CSS sprites are—a single image
containing a multitude of different icons, buttons, or other graphics. Many large websites use this
technique including the Yahoo! homepage. In fact, we use the same technique for the Clearleft
site navigation (see Figure 5-12).
#nav li a {
display: block;
text-indent: -9999px;
height: 119px;
width: 100px;
background-image: url('/img/nav.png');
background-repeat: no-repeat;
}
#nav li.home a,
#nav li.home a:link,
#nav li.home a:visited {
background-position: 0 0;
}
#nav li.home a:hover,
#nav li.home a:focus,
#nav li.home a:active {
background-position: 0 -119px;
}
#nav li.who-we-are a,
#nav li.who-we-are a:link,
#nav li.who-we-are a:visited {
background-position: -100px 0;
}
#nav li.who-we-are a:hover,
#nav li.who-we-are a:focus,
#nav li.who-we-are a:active {
background-position: -100px -119px;
}
By using this technique, you can cut down on the requests the web browser makes to your
server, considerably speeding up the download times. Furthermore, using sprites keeps all your
buttons, icons, and miscellaneous graphics in one location, improving maintainability. So it’s a
win-win situation.
###Rollovers with CSS 3
CSS 3 includes a number of properties like text-shadow, box-shadow, and border-radius that
make it possible to create heavily styled buttons that require no images whatsoever. To create
such a button, I will start with the code from our first example:
a {
display: block;
width: 6.6em;
height: 1.4em;
line-height: 1.4;
text-align: center;
text-decoration: none;
border: 1px solid #66a300;
background-color: #8cca12;
color: #fff;
}
Next, I’ll add curved borders and a drop shadow. I’m also going to give the button text a subtle
drop shadow (see Figure 5-13).
a {
display: block;
width: 6.6em;
height: 1.4em;
line-height: 1.4;
text-align: center;
text-decoration: none;
border: 1px solid #66a300;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;
background-color: #8cca12;
color: #fff;
text-shadow: 2px 2px 2px #66a300;
-moz-box-shadow: 2px 2px 2px #ccc;
-webkit-box-shadow: 2px 2px 2px #ccc;
box-shadow: 2px 2px 2px #ccc;
}
Figure 5-13. A rounded corner button using only CSS
To re-create the gradient, Safari 4 beta supports a proprietary value called -webkit-gradient.
While I would never normally recommend the use of proprietary code, this may provide a hint of
where CSS is heading in the future. This proprietary value takes a number of different arguments
including the type of gradient (liner or radial), the direction of the gradient (in this case, top-left to
bottom-left), a starting color, an end color, and any stops along the way. Obviously, if you didn’t
want to use this proprietary code, you could simply produce your own background image gradient
instead.
a {
display: block;
width: 6.6em;
height: 1.4em;
line-height: 1.4;
text-align: center;
text-decoration: none;
border: 1px solid #66a300;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;
background-image: -webkit-gradient(linear, left top, left bottom,
from(#abe142), to(#67a400));
background-color: #8cca12;
color: #fff;
text-shadow: 2px 2px 2px #66a300;
-moz-box-shadow: 2px 2px 2px #ccc;
-webkit-box-shadow: 2px 2px 2px #ccc;
box-shadow: 2px 2px 2px #ccc;
}
Last, Safari includes another proprietary property called box-reflect, which as the name
suggests, allows you to create reflections of an object. This property contains a number of
different arguments including the position and distance of the reflection along with a masking
image. Interestingly, you can use the –webkit-gradient value to automatically generate this
mask. In this instance, I’m positioning the reflection 2 pixels below the button and using a mask
that fades to white (see Figure 5-14).
a {
display: block;
width: 6.6em;
height: 1.4em;
line-height: 1.4;
text-align: center;
text-decoration: none;
border: 1px solid #66a300;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;
background-image: -webkit-gradient(linear, left top, left bottom,
from(#abe142), to(#67a400));
background-color: #8cca12;
color: #fff;
text-shadow: 2px 2px 2px #66a300;
-moz-box-shadow: 2px 2px 2px #ccc;
-webkit-box-shadow: 2px 2px 2px #ccc;
box-shadow: 2px 2px 2px #ccc;
-webkit-box-reflect: below 2px -webkit-gradient
(linear, left top, left bottom, from(transparent),
color-stop(0.52, transparent), to(white));
}
There is some debate around whether these types of effects should be done using CSS or not, so
it’s uncertain if they will ever make it into the official specification. Because of this and the lack of
cross-browser support, it would be unwise to use these techniques in a production environment.
However, that shouldn’t stop you from playing around with them on your personal sites just as
long as you realize that they’re invalid CSS and may get removed or changed in future versions
of the browser.
Pure CSS tooltips
Tooltips are the little yellow text boxes that pop up in some browsers when you hover over
elements with title tags. Several developers have created their own custom, stylized tooltips using
a combination of JavaScript and CSS. However, it is possible to create pure CSS tooltips by
using CSS positioning techniques. This technique requires a modern, standards-compliant
browser like Firefox to work properly. As such, it is not a technique you would add to your day-today
arsenal. However, it does demonstrate the power of advanced CSS and gives you a hint of
what will be possible when CSS is better supported.
As with all of the examples in this book, you need to start with well-structured and meaningful
HTML:
<p>
<a href="http://www.andybudd.com/" class="tooltip">
Andy Budd<span> (This website rocks) </span></a> is a web developer based in
Brighton England.
</p>
I have given the link a class of tooltip to differentiate it from other links. Inside the link, I have
added the text I wish to display as the link text, followed by the tooltip text enclosed in a span. I
have wrapped my tooltip text in brackets so that the sentence still makes sense with styles turned
off.
The first thing you need to do is set the position property of the anchor to relative. This allows
you to position the contents of the span absolutely, relative to the position of its parent anchor.
You do not want the tooltip text to display initially, so you should set its display property to none:
a.tooltip {
position: relative;
}
a.tooltip span {
display: none;
}
When the anchor is hovered over, you want the contents of the span to appear. This is done by
setting the display property of the span to block, but only when the link is hovered over. If you
were to test the code now, hovering over the link would simply make the span text appear next to
the link.
To position the contents of the span below and to the right of the anchor, you need to set the
position property of the span to absolute and position it 1 em from the top of the anchor and 2
ems from the left.
a.tooltip:hover span {
display: block;
position: absolute;
top: 1em;
left: 2em;
}
hint:Remember, an absolutely positioned element is positioned in relation to its
nearest positioned ancestor or, failing that, the root element. In this example,
we have positioned the anchor, so the span is positioned in relation to that.
And that’s the bulk of the technique. All that is left is to add some styling to make the span look
more like a tooltip. You can do this by giving the span some padding, a border, and a background
color:
a.tooltip:hover span, a.tooltip:focus span {
display:block;
position:absolute;
top:1em;
left:2em;
padding: 0.2em 0.6em;
border:1px solid #996633;
background-color:#FFFF66;
color:#000;
}
In Firefox, the applied technique should look something like Figure 5-15.