Skip to content

Daniel Lamb Byte–size Bits & Bobs

Article Deep Linking Revisited

3 minute read.

The Problems

In this post I want to address two issues I noticed with the script and css I created in my last blog post.

The first issue I noticed is that sometimes there was a flash of unstyled heading anchors. This happened between the time that JavaScript injects the links and the CSS was downloaded an applied. It was especially noticeable since I inline the critical1 path css and asynchronously load the rest.

It doesn’t happen all the time, but this type race condition really annoys me! Now, I could quickly fix this by adding the heading anchor styles into the critical CSS that gets inlined. But that feels like a hack, since it isn’t critical to initial page layout and only applies once the user interacts with the headings.

Secondly, I noticed on my mobile phone that when I use the “Reader View” in Safari the injected links are visible.

This looks cluttered and unprofessional at best and could make the headings heard to read. For example, the next to an uppercase I letter can be confusing depending on the font.

The Fix

For my initial implementation I used JavaScript for just about everything and CSS to make it look a bit better. By breaking down the responsibilities differently I could address these problems.

To do this I changed the script to only inject the HTML structure (an empty anchor tag) like so.

var headings = document.querySelectorAll('h2,h3,h4,h5,h6');
[].forEach.call(headings, function(heading) {
  if (heading.id) {
    var anchor = '<a href="#' + heading.id + '" class="anchor"></a>';
    heading.innerHTML = anchor + heading.innerHTML;
  }
});

Then I used the CSS content property with the :before pseudo-element to insert the charactor.

// unobtrusively style heading anchors
.anchor {
  top: 0;
  opacity: 0;
  color: #ccc;
  left: -1rem;
  position: absolute;  
  padding-right: 0.5rem;
  transition: opacity 0.2s ease-in-out 0.1s;
  &:before {
    content: '¶';
  }
}
h2, h3, h4, h5, h6 {
  position: relative;
  &:hover .anchor {
    opacity: 1;
    color: #ccc;
    text-decoration: none;
  }
}

The minor refactoring above fixed both issues by removing the race between markup and styling, and having CSS inject the link contents.

  1. External stylesheets (included via <link> tags) are render-blocking. Meaning the browser can’t paint content to the screen until the CSS is downloaded.


Give Feedback via my AMA (ask me anything) project on GitHub. Published on by Daniel Lamb.
You may also enjoy these posts