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!