<!DOCTYPE html>
<!-- ========================================== kroc camen of camen design ============================================= -->
<title>code · Under the Hood #2:  Internal / External Links, the CSS3 Way</title>
<link rel="stylesheet" type="text/css" href="/design/design.css" />
<meta name="viewport" content="width=device-width, maximum-scale=1.0, user-scalable=no" />
<link rel="alternate" type="application/rss+xml" href="/code/rss" title="Just code" />
<link rel="canonical" href="/code/uth2_css3-hyperlinks" />
<!-- =================================================================================================================== -->
<header>
	<h1><a href="/" rel="index">
		Camen Design
	</a></h1>
	<nav><ul>
		<li><a href="/">all</a></li>
		<li><a href="/projects">projects</a></li>
		<li><a href="http://forum.camendesign.com">forum</a></li>
	</ul><ul>
		<li><a href="/quote/">quote</a></li>
		<li><a href="/writing/">writing</a></li>
		<li><a href="/blog/">blog</a></li>
		<li><a href="/photo/">photo</a></li>
		<li><a href="/code/" rel="tag">code</a></li>
		<li><a href="/art/">art</a></li>
		<li><a href="/link/">link</a></li>
		<li><a href="/poem/">poem</a></li>
		<li><a href="/audio/">audio</a></li>
	</ul><ul>
		<li><a href="/web-dev/">web-dev</a></li>
		<li><a href="/annoyances/">annoyances</a></li>
		<li><a href="/eve/">eve</a></li>
		<li><a href="/code-is-art/">code-is-art</a></li>
		<li><a href="/inspiration/">inspiration</a></li>
		<li><a href="/windows/">windows</a></li>
		<li><a href="/gift/">gift</a></li>
		<li><a href="/gaming/">gaming</a></li>
		<li><a href="/mac/">mac</a></li>
		<li><a href="/osnews/">osnews</a></li>
		<li><a href="/c64/">c64</a></li>
		<li><a href="/linux/">linux</a></li>
	</ul>
	<a rel="previous" href="/code/uth1_is-png-32bit">
		older article →
	</a><a rel="next" href="/code/uth3_sqlite">
		← newer article
	</a></nav>
</header>
<!-- =================================================================================================================== -->
<article><header>
	<!-- date published or updated -->
	<time pubdate datetime="2008-07-08T13:23:00+01:00">
		<sup>1:23<abbr>pm</abbr> • 2008</sup>
		<abbr title="July">Jul</abbr> 8
	</time>
	<!-- categories -->
	<ul>
		<li><a href="/code/uth2_css3-hyperlinks" rel="bookmark tag">code</a></li>
		<li><a href="/code-is-art/uth2_css3-hyperlinks">code-is-art</a></li>
		<li><a href="/web-dev/uth2_css3-hyperlinks">web-dev</a></li>
	</ul>
	<!-- licence -->
	<small>
		<a rel="license" href="http://creativecommons.org/licenses/by/3.0/deed.en_GB">c</a>
		share + remix
	</small>
	<!-- enclosure -->
	<a type="text/css" href="/code/uth2_css3-hyperlinks/css3-hyperlinks.css">
		css3-hyperlinks <em>3.5 KB</em>
	</a>
</header>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<section>
<h1>Under the Hood #2: <br />Internal / External Links, the CSS3 Way</h1>
<aside>
	<strong>Note:</strong><br />
	This article is out of date now after the redesign of the website, so the example links will not match the actions
	described in the text.
</aside>
<p>
	<strong>If, unlike me,</strong> you don’t have a sixth-sense that means you <em>know</em> 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.
	<br /><br />
	For example, external links in Wikipedia:
</p>
<img src="/code/uth2_css3-hyperlinks/external-links-wikipediaexample.png" alt="A screenshot of links on a Wikipedia article. image from welie.com/patterns/showPattern.php?patternID=outgoing-links" width="416" height="241" />

<hr />

<p>
	<strong>There are</strong> a number of things I wish to alert my users to on this website through the link
	scheme.<br />
	Float over each of the example links for a demonstration.
</p>
<dl>
	<dt>An <a href="/design/">internal link</a>, to another page on this site</dt>
	<dd>
		The dotted-line is used to signify a weaker hyperlink that does not break the boundary of this website.
	</dd>
	<dt>A link to an <a href="http://dowebsitesneedtolookexactlythesameineverybrowser.com/" rel="external">external website</a></dt>
	<dd>
		A normal hyperlink is used to represent the interlinked ’Web, going from one site to another.<br />
		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.
	</dd>
	<dt>Some <a href="http://wikipedia.org" rel="external">links</a> to <a href="http://youtube.com" rel="external">popular</a> <a href="http://php.net" rel="external">websites</a>, and a <a href="http://tinyurl.com/6heoky" rel="external">redirect</a></dt>
	<dd>
		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.
	</dd>
	<dt>A link to an <a href="mailto:kroc@camendesign.com">email address</a>, and an <a href="itms://ax.phobos.apple.com.edgesuite.net/WebObjects/MZStore.woa/wa/viewPodcast?i=26502001&amp;id=73799858&amp;ign-mscache=1" rel="external">application protocol</a></dt>
	<dd>
		Links to other protocols may cause programs on the user’s computer to launch, or may require them to copy
		&amp; paste the link into a piece of software.
	</dd>
	<dt>A direct link to <a href="http://webtypography.net/sxsw2007/webtypography-sxsw2007-notes.pdf" rel="external" type="application/pdf">a file</a>, rather than a webpage</dt>
	<dd>
		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.
	</dd>
</dl>


<h2>Beginning With Good Markup</h2>
<p>
	Although all of this can be done without any additional markup than just the <code>href</code>, the CSS would be
	10× larger. It could be done with a set of CSS classes, but then this website has
	<a href="/code/uth2_css3-hyperlinks.html5">no classes</a>, and ultimately these link effects should be
	zero-maintenance and automatic.
</p><p>
	We can reduce the length of selectors needed by using a few HTML attributes that have been around for ages.
</p>
<dl>
	<dt><code>&lt;a href="http://…" rel="external" /&gt;</code></dt>
	<dd>
		The <code>rel</code> attribute defines the relationship between this page and the linked page.<br />
		In this case we are stating that the page linked to is external.
	</dd>
	<dt><code>&lt;a href="a.pdf" type="application/pdf" /&gt;</code></dt>
	<dd>
		The same as when specifying a stylesheet or javascript file in the <code>&lt;head&gt;</code>, you can
		provide the mime-type of the content being linked to.
	</dd>
</dl>
<p>
	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.
</p><p>
	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.
</p>


<h2>Automatic Markup With PHP</h2>
<p>
	Here is some code that searches for links starting with “http” and adds “<code>rel="external"</code>” to
	the tag. Internal links are relative, (e.g. “<code>href="?blog"</code>” 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)
</p>

<pre><code>//add `rel="external"` to outside links:
$content = preg_replace_callback (
	//this finds links that begin with a protocol, e.g. "http"
	'/&lt;a[^&gt;]*href="(?:[a-z]+):[^"]+"[^&gt;]*&gt;/',
	//this does the substitution, either adding a rel attribute, or appending "external" to an existing one
	create_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("&lt;a ","&lt;a rel=\"external\" ",$m[0]);'	//add `rel="external"`
	), $content
);</code></pre>

<p>
	The second example here, is finding links that lead directly to a file, rather than a page:
</p>

<pre><code>//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"'
	'/&lt;a([^&gt;]*)href="([^"]+)\.(gif|jpg|png|pdf|zip|exe)"([^&gt;]*)&gt;/',
	//this does the insertion, recreating the link, with the added attribute
	create_function ('$m',
		'return "&lt;a type=\"".mimeType($m[3])."\"${m[1]}href=\"${m[2]}.${m[3]}\"${m[4]}&gt;";'
	), $content
);

//the "mimeType" function called above, which returns a mime-type from a file-extension
function 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;
	}
}</code></pre>


<h2>The CSS</h2>
<h3>Internal Links</h3>
<p>
	For links that are not external… which is easy now that they are automatically marked up by the PHP.<br />
	(A description of the CSS3 selectors used can be found
	<a href="http://www.456bereastreet.com/archive/200601/css_3_selectors_explained/" rel="external">here</a>)
</p>

<pre><code>a:not([rel~="external"]) {
	text-decoration: none; border-bottom: dotted 1px;
}</code></pre>

<p>
	A colour is not given on the <code>border-bottom</code> 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.
</p>


<h3>Links to Files</h3>
<p>
	We will cover these next, as the CSS for external links makes reference to these.
</p>

<pre><code>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, &lt;famfamfam.com/lab/icons/silk&gt; */
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");}
}</code></pre>


<h3>External Links</h3>
<p>
	External links already have the underline as part of the defaults.
</p>

<pre><code>/* 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');}</code></pre>

<p>
	Enjoy.
</p>


<h2>Limitations</h2>
<p>
	Requires the <code>:not</code> CSS3 selector, available in Firefox, Safari &amp; Opera 9.5.<br />
	As you can imagine, this does not work in Internet Explorer. But then as you know, <a href="/blog/hello">I don’t
	care</a>.
</p>
</section>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
</article>
<footer>
	<nav><a href="http://forum.camendesign.com">‹ Discuss this in the Forum ›</a></nav>
		
	<a href="mailto:kroc@camendesign.com">kroc@camendesign.com</a>
	<nav>view-source:
		<a href="/code/uth2_css3-hyperlinks.rem">Rem</a> •
		<a href="/code/uth2_css3-hyperlinks.html">HTML</a> •
		<a href="/design/">CSS</a> •
		<a href="/.system/">PHP</a> •
		<a href="/.htaccess">.htaccess</a>
	</nav>
	<form method="get" action="https://duckduckgo.com">
		<input type="hidden" name="sites" value="camendesign.com" />
		<input type="search" name="q" placeholder="search…" />
		<input type="submit" value="Go" />
	</form>
</footer>
<!-- =================================================================================================== code is art === -->