In the world of print stylesheets, there’s long been a fairly well-established technique for expanding link URLs inline in body text, and printing them inline. The result works, but it breaks the reading flow of the text. A better solution has been around for at least a century in typesetting: the footnote. The challenge is creating and inserting the footnotes, which must be done with JavaScript.
This short tutorial will show how to capture print events with JavaScript and insert dynamic content exclusively for printers, while being invisible in the browser window.
Seeding The Page
Let’s assume that our page content is inside an <article>
tag:
<article>
<p>Prairie dogging. <a href="http://thenewcode.com">Table the discussion</a> pull
in ten extra bodies to help roll the tortoise win-win-win data-point we want to
see more charts we need a <a href="http://codepen.io">paradigm shift</a>…
</article>
To this I’ll add some fairly standard CSS:
article {
max-width: 40rem;
margin: 3rem auto 0;
}
article p {
font-size: 1.4rem;
line-height: 1.5;
}
article a {
color: #000;
text-decoration: none;
border-bottom: 1px solid #000;
}
The footnotes will be added inline with the <sup>
element, and their explanations added below the article inside a footer
. Both of these are set up in the CSS, and made invisible by default:
article sup {
line-height: 0;
padding-left: .2rem;
font-size: 1rem;
}
sup, footer {
display: none;
}
They are visible in a print event, written in a @media
query:
@media print {
sup { display: inline; }
footer { display: block; }
}
The first goal of our JavaScript, added below the HTML content, is to select that element:
let article = document.querySelector("article");
Then we need to detect a print event. To do so, we’ll use JavaScript’s equivalent to CSS’s @media
, matchMedia
:
let printEvent = window.matchMedia("print");
Below that, we’ll add an event listener that listens for a print event, adds a printed
class to the <body>
, goes through the links in the <article>
, adds incremental numbers after each link, and adds the same number in the <footer>
, with the expanded link:
printEvent.addListener(function(mql) {
if (mql.matches && !document.body.matches(".printed")) {
document.body.classList.add("printed");
let articleLinks = article.getElementsByTagName("a");
if (articleLinks.length > 0) {
var footer = document.createElement("footer");
article.appendChild(footer);
var footnotes = document.createElement("ol");
for (let i = 0; i < articleLinks.length; i++) {
articleLinks[i].innerHTML += "<sup>"+(i + 1)+"</sup>";
var footnote = document.createElement("li");
footnote.innerText = articleLinks[i].href;
footnotes.appendChild(footnote);
}
footer.appendChild(footnotes);
}
}
});
Testing The Result
There’s an obvious problem with the script, in the sense that it appears it can only be tested by printing the web page. That’s not actually true; there’s several possible ways of testing the result without killing trees:
- Change the event or CSS: you could change the initiating event to almost anything, and comment out the CSS media query, to make the result visible in the browser, as I did in the example at the top of this article.
- Without changing anything, test the result in a browser that provides a print preview, such as Chrome.
- In Chrome’s Developer Tools, use More Tools / Rendering from the side menu and place the page to emulate CSS print media.
Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/bByBRJ