How to use CSS instead of JavaScript for external link icons
Written by Richard Heyes, RGraph author, on 26th November 2022- Introduction
- The previous JavaScript version
- The new CSS version
- Using an SVG image instead of a PNG
- Conclusion
Introduction
Here's a little snippet that I recently had the
fortune of learning. The thing that I found out
was how to use images with the css
content property. Now, if you just specify
the path, obviously it would use that as the text
and if you give the whole tag (ie
content: '<img src="/images/myImage.png" />'
) it just prints the tag out verbatim. So what to do?!
Well that's where the url() function
comes in to save the day. Consider:
Instead of doing this:
content: '<img src="/images/myImage.png" />'
You would do this:
content: url('/images/myImage.png');
The previous JavaScript version
So this is the previous code that I was employing,
making use of
jquery, to get all of the links on the
page, check if they're external links and then
replace the text [icon] (if it's
present) with the
<img> tag for the image.
(function ()
{
// Get all of the links (using jQuery - feel free to get the links however you please)
$links = $('a');
// Loop through all of the links
for (var i=0; i<$links.length; ++i) {
// Get the href attribute from the current link
var href = $links.eq(i).attr('href');
// Get the rel attribute from the current link
var rel = $links.eq(i).attr('rel');
// If this link:
// 1. Has href and rel attributes
// 2. Starts with http:// or https://
// 3. Isn't linking to a page on this website
// 4. The rel attribute has the word external in it
if (href && rel
&& href.match(/^https?:\/\//)
&& !href.match(/https?:\/\/(www\.)?rgraph\.net/)
&& rel.match(/external/)) {
// Set the HTML inside the link to whatever is there currently
// whilst replacing the text "[icon]" with the
tag for the
// icon.
$links.eq(i).html(
$links.eq(i).html().replace(/\[icon\]/,'<img src="/images/external-link.png" width="12" height="12" style="margin-left: 5px" alt="This is an external link" />')
);
}
}
})();
The new CSS version
So that was not an inconsiderable amount of JavaScript
to use to add the image to links and now here's an
alternative css version that's far
more concise. It uses a few css
operators that you may not have seen or used before -
the square brackets make the browser look for
<a> tags that have the rel attribute
set to external (the *=
operator instead
of just = denotes that the word
external can appear anywhere within
the rel attributes value. And the ::after
selects a pseudo-element that is added just after the
element (the <a> tag in this case).
The content property specifies what goes inside the
::after pseudo-element). Normally this might be a
bit of text but
here we've used the url() function
to give the location of the image to use.
/* Select the ::after peudo-element that appears after the a tag */ a[rel*="external"]::after { /* Specify the URL of the image to appear */ content: url('/images/external-link.png'); /* Add a bit of spacing */ padding-left: 5px; }
Using an SVG image instead of a PNG
Additionally, instead of using an external png
image file as the image here's a version that
uses an embedded svg file. It's a bit more css
code but does mean that no image file is
necessary. Thanks to Christian Oliff
for this alternative.
a[rel*="external"]::after {
content: "";
width: 13px;
height: 13px;
margin-left: 4px;
margin-bottom: 2px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='13' height='13' fill='currentColor' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z'/%3E%3Cpath fill-rule='evenodd' d='M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z'/%3E%3C/svg%3E");
background-position: center;
background-repeat: no-repeat;
background-size: contain;
display: inline-block;
}
Conclusion
So a total of 3 lines of css compared to
roughly 15 lines of javascript. Far
shorter and easier to understand. You could add a
comment explaining the css selector
- especially if you're working in a team environment
because it's not overly common so it might not be
familiar to everyone.
Thanks go to
Kevin Powell on YouTube without whom (and
his videos) I wouldn't have learnt this technique.
He makes a large amount of css and
javascript videos
- ideal if you're a budding or existing front-end
developer.
Cheers!