What does any blog author with two posts need? "More content!" I hear you shout, to which I say - not today! I have decided to add - drum roll, please - some anchor links to the headings! Okay, I lied, I did indeed decide to make some content around it, since the last time I posted a blog post... Well, let's just say it's been a long time to avoid embarrassment.
So what are anchor links, anyway? If you're unfamiliar, anchor links are basically links to specific sections of a page.
Try hovering over one of the headings in this page, and clicking on the icon next to it - it will append a #
with the heading
(e.g. #adding-the-anchor
) and will scroll the page so that it focuses on the heading. If you navigate to this URL, it will also focus on the heading.
How this works is not magic - the ID of the heading should match the heading "slug"; In this example, the "Adding the Anchor" <h2>
heading has an ID of adding-the-anchor
.
Try inspecting the HTML and seeing for yourself!
Note: If you link to a page's heading (for example, in technical documentation), bear in mind that the heading can change (which may "break" your link and lead folks to the top of the page rather than a specific section) but web developers are aware of this functionality and may not change the ID to avoid that.
Text Fragments are also useful for this kind of stuff (but are much more prone to breaking).
So, let's begin with the simplest heading and see how you would go about doing something like this:
1<h2>Adding the Anchor</h2>
html
The actual code I use to render headings is omitted for simplicity (and accounts for various level of heading tags).
Let's break this down into three parts:
- Add the anchor to the heading
- Display it only on hover
- Add the actual anchor link functionality
Adding the Anchor
First, let's style the heading a bit (I will not be assuming any predefined styles):
1h2 { 2 font-weight: bold; 3 font-size: 40px; 4 font-weight: bold; 5}
css
This should look something like this:
Let's wrap the heading in a <div>
with a class of container
(we'll style that soon) and add a link icon from heroicons with a class of icon
(also to be styled later):
1<div class="container"> 2 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" 3 stroke="currentColor" class="icon"> 4 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" /> 5 </svg> 6 <h2>Adding the Anchor</h2> 7</div>
html
Now, let's style the icon a bit:
1.icon { 2 color: #9ca3af; 3 width: 18px; 4 height: 18px; 5}
css
Note: By setting the SVG's
stroke
property tocurrentColor
(that is also how it's copied from Heroicons), we can change the text color and it will control the SVG's stroke. This technique is particularly useful in CSS utility libraries like Tailwind, in which you have special classes for the setting the text color.
At this point we should have something like this:
Instead, what we want to do is have them on the same line - we'll use Flexbox for that.
We'll also want to align them both to the bottom, so an items-end
class should take care of that:
1.container { 2 display: flex; 3 align-items: flex-end; 4} 5 6.icon { 7 color: #9CA3AF; 8 width: 18px; 9 height: 18px; 10} 11 12h2 { 13 font-weight: bold; 14 font-size: 40px; 15 font-weight: bold; 16}
css
Another important thing we'll want to do, in my case, is have the heading stay put, and move the anchor link to the left of it.
The way to achieve is adding a wrapper with a position: relative
, and adding a wrapper over the SVG with a position: absolute
, thus detaching it from the document flow.
We'll also move it up a bit, so that its bottom end aligns with the text's baseline (there are better ways to achieve this, but this will be do for our purposes).
1.container { 2 position: relative; 3 display: flex; 4 align-items: flex-end; 5} 6 7.icon { 8 position: absolute; 9 left: -36px; 10 bottom: 4px; 11 color: #9CA3AF; 12 width: 18px; 13 height: 18px; 14} 15 16h2 { 17 font-weight: bold; 18 font-size: 40px; 19 font-weight: bold; 20}
css
Displaying on Hover
Alright, let's say that we're content with this. Now how do we only show it on hover?
Doing this in JavaScript would be very simple; however, I always tend to try and make things work using only HTML and CSS, before asking JS for help.
So, let's set the icon to display: none
and when the container is hovered, let's change it to display: block
.
No sweat, right?
1.container { 2 position: relative; 3 display: flex; 4 align-items: flex-end; 5} 6 7.container:hover .icon { 8 display: block; 9} 10 11.icon { 12 display: none; 13 position: absolute; 14 left: -36px; 15 vertical-align: text-bottom; 16 bottom: 4px; 17 color: #9CA3AF; 18 width: 18px; 19 height: 18px; 20} 21 22h2 { 23 font-weight: bold; 24 font-size: 40px; 25 font-weight: bold; 26}
css
Now we get to the tricky part, however. Do you notice the issue? When we hover over the title, and then move our mouse to the anchor - it disappears!
How I solved this (and I am sure that there are other, possibly better approaches out there) is by essentially expanding the "hit box" of the heading
with a neat hack - I added padding-left: 36px
(which gave the text left padding, thus moving it to the right) and "corrected" it by moving it back left with a left: 36px
(the class is already position: relative
so no need to set it).
This alone would work, except it would also move the icon left by 36px
, so I set the icon to left: 0
.
1.container { 2 position: relative; 3 display: flex; 4 align-items: flex-end; 5 padding-left: 36px; 6 right: 36px; 7} 8 9.container:hover .icon { 10 display: block; 11} 12 13.icon { 14 display: none; 15 position: absolute; 16 left: 0; 17 vertical-align: text-bottom; 18 bottom: 4px; 19 color: #9CA3AF; 20 width: 18px; 21 height: 18px; 22} 23 24h2 { 25 font-weight: bold; 26 font-size: 40px; 27 font-weight: bold; 28}
css
Adding the Functionality
To make this into a working anchor link, we need to make sure of two things:
- Add an ID to the heading (its "slug", e.g. for "Adding the Anchor" we could use
adding-the-anchor
) - Make the anchor icon a link to the same page, with an added
#adding-the-anchor
The HTML would look something like this:
1<div class="container"> 2 <a href="#adding-the-anchor"> 3 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" 4 stroke="currentColor" class="icon"> 5 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" /> 6 </svg> 7 </a> 8 <h2 id="adding-the-anchor">Adding the Anchor</h2> 9</div>
html
This concludes this post! I hope it proved useful to at least some of you.
If it helps, here is a Codesandbox which demonstrates this in action: https://codesandbox.io/s/anchor-link-demo-nk9ez