Anchor links are cool. They make it easy to get the link to a specific section in webpage to share with others. Just hover over a heading and get the clickable link with the URL of the heading. This page lists my experiments with adding Anchor links to this blog.
I used AnchorJS in my first attempt to add anchor links. It was very easy to integrate.
Include
anchor.js
script in the html page.
<script src="/js/jquery-3.4.1.min.js"></script>
<script src="js/apply-styles.js"></script>
<!-- For anchor links -->
<script src="js/anchor-4.2.0.min.js"></script>
and call anchors.add()
in the $(document).ready
call back. This was the
location I used for the other style updates.
/* apply-styles.js */
$(document).ready(function() {
.add();
anchors }
AnchorJS worked splendidly for my blog (for the audience of 1 😃). However
the anchorJS website includes an explicit warning against calling
anchors.add()
in the $(document).ready
call back.
https://www.bryanbraun.com/anchorjs/#dont-run-it-too-late
Don’t add anchors on later events, like
$(document).ready()
orwindow.onload
as some browsers will attempt to jump to your ID before AnchorJS can add it to the page. For more details, see github issue #69.
This got me thinking. As my blog is static website, I figured I can add the anchors when building the website and remove the runtime component.
This blog is built using Hakyll which uses Pandoc to convert from Markdown to HTML. I implemented a Pandoc filter to add anchors to headers
-- Create an anchor based on the string
-- add anchorjs-link class for CSS manipulations
-- Use "#" as the display for the anchor
-- Append linkId to "#" to create the link target
addAnchor :: String -> Inline
= Link ("", ["anchorjs-link"], []) [Str " #"] ("#" ++ linkId, "")
addAnchor linkId
-- Add a anchor link to each html header
-- Leave everything else as is
modHeader :: Block -> Block
-- We are matching against the header pattern from pandoc-types
-- We take the linkId and use it to add anchor links
-- Header Int Attr [Inline]
Header n y@(linkId, _, _) xs) = (Header n y (xs ++ [(addAnchor linkId)]))
modHeader (-- fallback for all others
= x
modHeader x
-- Walk the Pandoc AST and apply modHeader on each node
anchorLinks :: Pandoc -> Pandoc
= walk modHeader anchorLinks
This script also needs CSS changes to hide the anchors by default and reveal them on hover.
/* Make the anchor transparent by default */
.anchorjs-link {
opacity: 0;
text-decoration: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* Make the anchor opaque on hover */
*:hover > .anchorjs-link,
.anchorjs-link:focus {
opacity: 1;
}
Here are the links to haskell source and css file.