web
tutorial
css

Building anchor links

Guy Waldman

Guy Waldman

1 minute, 3 seconds

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! And then I decided 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!

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>

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:

  1. Add the anchor to the heading
  2. Display it only on hover
  3. 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}

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>

Now, let's style the icon a bit:

1.icon {
2  color: #9ca3af;
3  width: 18px;
4  height: 18px;
5}

Note: By setting the SVG's stroke property to currentColor (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 want to 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}

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 having 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}

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}

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 issue (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}

Adding the Functionality

To make this into a working anchor link, we need to make sure of two things:

  1. Add an ID to the heading (its "slug", e.g. for "Adding the Anchor" we could use adding-the-anchor)
  2. 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>

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


Like this post? Have any comments? Tweet at me!