Under the Hood #2:
Internal / External Links, the CSS3 Way
Edit #4: Added TinyURL to favicon list.Edit #3: Added “mailto:” and “itms:” to scheme. Bug fixes.
Edit #2: External icon overriding file icon on external files. Opera fixes.
Edit #1: Updated CSS to prevent Safari preloading all the favicons.
If, unlike me, you don’t have a sixth-sense that means you know when a link will be internal / external,
or will open in a new window, it is increasingly common practice to add little images to links to show that they lead
to external websites. The benefit is that one can queue up external links in background-tabs, or avoid things not
interested in.
For example, external links in Wikipedia:
There are a number of things I wish to alert my users to on this website through the link scheme.
Float over each of the example links for a demonstration.
- An internal link, to another page on this site
- The dotted-line is used to signify a weaker hyperlink that does not break the boundary of this website.
- A link to an external website
-
A normal hyperlink is used to represent the interlinked web, going from one site to another.
The image is not shown until the mouse is placed over the link so as to reduce visual clutter and to not add stutter to the reading rhythm. The image juts out to the left, so as to not cause the text to spasm about and break the reading flow, nor is it placed to the right where it may cover up the next word, and thus also break the reading flow. - Some links to popular websites, and a redirect
- Adding the favicon to external links to some sites will help the user recognise what sort of content they will be lead to. In some cases this will better help them decide if the link is useful or a waste of time, and what sort of context is meant when the link text is not descriptive of what it is.
- A link to an email address, and an application protocol
- Links to other protocols may cause programs on the user’s computer to launch, or may require them to copy & paste the link into a piece of software.
- A direct link to a file, rather than a webpage
- Links will behave differently when leading directly to a file. Users need to be made aware of this, especially if they want to avoid PDF links, or to proceed with due caution. A link to a file is a lot like an enclosure in an email; it should be distinctly marked with some icon to show its type. As a bonus, if you’re using Firefox, that icon above will be the one from your computer for that filetype.
Beginning With Good Markup
Although all of this can be done without any additional markup than just the href, the CSS would be
10× larger. It could be done with a set of CSS classes, but then this website has
no classes, and ultimately these link effects should be
zero-maintenance and automatic.
We can reduce the length of selectors needed by using a few HTML attributes that have been around for ages.
<a href="http://…" rel="external" />-
The
relattribute defines the relationship between this page and the linked page.
In this case we are stating that the page linked to is external. <a href="a.pdf" type="application/pdf" />-
The same as when specifying a stylesheet or javascript file in the
<head>, you can provide the mime-type of the content being linked to.
These are both clean and meaningful ways to markup links in a way that robots can understand, and doesn’t rely upon class names that tie you to your design, and won’t work interchangeably with syndicated content on other people’s sites.
I could type these extra attributes manually as I write my articles, but I knew that I’d miss one or two here and there, and I’d prefer something a bit more automatic.
Automatic Markup With PHP
Here is some code that searches for links starting with “http” and adds “rel="external"” to the
tag. Internal links are relative, (e.g. “href="?blog"” and don’t contain my domain name, but the
code can be easily modified to look for links that don’t start with your own domain name if your CMS always writes
full URLs - even to internal pages)
//add `rel="external"` to outside links:$content = preg_replace_callback (//this finds links that begin with a protocol, e.g. "http"'/<a[^>]*href="(?:[a-z]+):[^"]+"[^>]*>/',//this does the substitution, either adding a rel attribute, or appending "external" to an existing onecreate_function ('$m','return (strpos($m[0],"rel=\"")!==false)'. //does 'rel="..."' already exist?'?str_replace("rel=\"","rel=\"external ",$m[0])'. //insert "external" into `rel`':str_replace("<a ","<a rel=\"external\" ",$m[0]);' //add `rel="external"`), $content);
The second example here, is finding links that lead directly to a file, rather than a page:
//add 'type="mime/type"' to links in the content:$content = preg_replace_callback (//this regex finds links to the listed file types, and adds 'type="mime/type"''/<a([^>]*)href="([^"]+)\.(gif|jpg|png|pdf|zip|exe)"([^>]*)>/',//this does the insertion, recreating the link, with the added attributecreate_function ('$m','return "<a type=\"".mimeType($m[3])."\"${m[1]}href=\"${m[2]}.${m[3]}\"${m[4]}>";'), $content);//the "mimeType" function called above, which returns a mime-type from a file-extensionfunction mimeType ($extension) {switch ($extension) {case 'gif': return 'image/gif'; break;case 'jpg': return 'image/jpeg'; break;case 'png': return 'image/png'; break;case 'pdf': return 'application/pdf'; break;case 'zip': return 'application/zip'; break;case 'exe': return 'application/octet-stream'; break;}}
The CSS
Internal Links
For links that are not external… which is easy now that they are automatically marked up by the PHP.
(A description of the CSS3 selectors used can be found
here)
a:not([rel~="external"]) {text-decoration: none; border-bottom: dotted 1px;}
A colour is not given on the border-bottom attribute so as to keep the existing link colour - even the
user’s chosen browser link colour if the link colour has not been overridden anywhere.
Links to Files
We will cover these next, as the CSS for external links makes reference to these.
a[type] {padding: 0 5px 0 25px; text-decoration: none;/* start with the default "unknown file-type" icon */background: #dedede url("/design/icons/page_white.png") no-repeat 5px 50%;/* rounded, borders. the bottom border is removed for if the link is internal */-moz-border-radius: 4px; -webkit-border-radius: 4px; border-bottom: 0 !important;}a[type]:hover {background-color: #eea;}/* these icons © Mark James, <famfamfam.com/lab/icons/silk> */a[href$=".gif"], a[href$=".jpg"], a[href$=".png"]{background-image: url("/design/icons/page_white_picture.png");}a[href$=".pdf"] {background-image: url("/design/icons/page_white_acrobat.png");}a[href$=".zip"] {background-image: url("/design/icons/page_white_zip.png");}a[href$=".exe"] {background-image: url("/design/icons/application_xp_terminal.png");}/* Firefox users will get their own native icons from their OS.I’m sure this can be done in Safari, but I don’t know how */@-moz-document url-prefix() {/* `@moz-document` isolates the following CSS for Firefox (gecko) only *//* get the "unknown file-type" icon from the OS */a[type] {background-image: url("moz-icon://.?size=16");}/* and the other file type icons */a[href$=".gif"] {background-image: url("moz-icon://.GIF?size=16");}a[href$=".jpg"] {background-image: url("moz-icon://.JPG?size=16");}a[href$=".png"] {background-image: url("moz-icon://.PNG?size=16");}a[href$=".pdf"] {background-image: url("moz-icon://.PDF?size=16");}a[href$=".zip"] {background-image: url("moz-icon://.ZIP?size=16");}a[href$=".exe"] {background-image: url("moz-icon://.EXE?size=16");}}
External Links
External links already have the underline as part of the defaults.
/* set the default external-link icon (this icon taken from Wikipedia) */a[rel~="external"]:not([type]) {background: url('/design/icons/external.png') no-repeat 0 50%;}/* hide the icon when not hovering on the link (whilst keeping the icon on standby)`:not([type])` is needed to not break the file-links which already have an image */a[rel~="external"]:not([type]):not(:hover) {background-image: none;}/* when you hover over the link, jut the favicon over the left side */a[rel~="external"]:not([type]):hover {/* `background-color` is set to prevent text clashing with heavily transparent favicons, like Google’s */margin-left: -18px; padding-left: 18px; background-color: #fcfcfc;}/* some favicons for common websites I link to.the `:hover` is only required by Safari to prevent it from preloading these */a[href*="apple."]:hover {background-image: url('http://apple.com/favicon.ico');}a[href*="archive.org"]:hover {background-image: url('http://web.archive.org/favicon.ico');}a[href*="deviantart."]:hover {background-image: url('http://i.deviantart.com/icons/favicon.png');}a[href*="google."]:hover {background-image: url('http://google.com/favicon.ico');}a[href*="osnews."]:hover {background-image: url('http://osnews.com/favicon.ico');}a[href*="php.net"]:hover {background-image: url('http://static.php.net/www.php.net/favicon.ico');}a[href*="slashdot."]:hover {background-image: url('http://slashdot.org/favicon.ico');}a[href*="tinyurl."]:hover {background-image: url('http://tinyurl.com/favicon.ico');}a[href*="wikipedia."]:hover {background-image: url('http://en.wikipedia.org/favicon.ico');}a[href*="youtube."]:hover {background-image: url('http://s.ytimg.com/yt/favicon-vfl1123.ico');}/* icons for other protocols */a[href^="mailto:"]:hover {background-image: url('/design/icons/email.png');}a[href^="itms:"]:hover {background-image: url('/design/icons/itms.png');}
Enjoy.
Limitations
Requires the :not CSS3 selector, available in Firefox, Safari
& Opera 9.5.
As you can imagine, this does not work in IE. But then as you
know, I don’t care.