![]() |
| Simple Russian barn, but will do for pretty much anywhere |
![]() |
| Pigs..... Couldn't resist this...the little pigsty base is from TFTB, pigs from Pegasus |
![]() |
| Smaller cabin and woodshed by Charlie Foxtrot, Everything else from TFTB. Love the well. |
![]() |
| Simple Russian barn, but will do for pretty much anywhere |
![]() |
| Pigs..... Couldn't resist this...the little pigsty base is from TFTB, pigs from Pegasus |
![]() |
| Smaller cabin and woodshed by Charlie Foxtrot, Everything else from TFTB. Love the well. |
![]() |
| Mind Sports South Africa |
Occasionally someone will want to print one of my web pages, even though it means losing access to all the interactive parts. There are a few things I do to make this work better:
I use this CSS for printing:
@media print { @page { margin: 1in; } body { font-size: 13pt; font-family: "Book Antiqua", "Times New Roman", serif; } header, footer, h2 { text-shadow: none; color: #000; background-image: unset; background-color: unset; } h2, h3 { page-break-after: avoid; } figure { page-break-inside: avoid; } }
I think it might be simpler to use @media screen { } to set some of the colors instead of trying to undo them with @media print { }.
To display URLs, I first tried this CSS rule:
@media print { a:before { content: "["; } a:after { content: "] (" attr(href) ")"; } }
This makes the links display in Markdown format, as [text](url).
Unfortunately, many URLs are quite long. Markdown has a footnote/endnote-style format which works better for long links: [text][1] followed by [1]: url. It's not something I can do in pure CSS. I would have to edit the HTML to make this work. But I'm not actually writing HTML directly. I write XHTML that is transformed into HTML using XSLT. Can XSLT do this transformation for me? Yes! I was able to adapt this XSLT technique to work on my pages.
First, create an XSLT rule that applies to all links:
<xsl:template match="//a"> <xsl:copy> <xsl:apply-templates select="node() | @*"/> </xsl:copy> <sup class="print-endnote"> <xsl:number level="any" count="//a" format="[1]"/> </sup> </xsl:template>
This will find links of the form <a href="url">test</a> and turn them into <a href="url">test</a><sup class="print-endnote">[3]</sup>. The count="//a" parameter to xsl:number will generate a counter for all <a> elements, and format it with brackets: the third link will be [3].
Then, at the bottom of the page, make a list of all the links:
<ul class="print-endnote"> <xsl:apply-templates select="//a" mode="endnote"/> </ul>
This will loop over all elements that match //a, and then apply this template to them:
<xsl:template match="a" mode="endnote"> <li> <xsl:number level="any" count="//a" format="[1]"/>: <xsl:value-of select="@href"/> </li> </xsl:template>
The output will look like this:
<ul class="print-endnote"> <li>[1]: https://…</li> <li>[2]: http://…</li> <li>[3]: http2://…</li> … </ul>
I don't want these to show up when viewing the page on the screen, so I use CSS to hide them by default, and then show them again when printing:
.print-endnote { display: none; } @media print { .print-endnote { display: unset; } }
This works! Throughout the page, links are annotated with a number like link[3]. Then at the bottom, it displays [3]: url.
However, as usual, there are details that make things more complicated in practice.
<section> element, so I changed a to section//a. Combined with the previous rule, it's now the ugly pattern //x:section//a[starts-with(@href,'http')].<section> on some of my pages. I did this by adding a test, <xsl:if test="count(ancestor::x:footer) = 0"> for both the endnote marker and the list of urls. These links still receive a number with xsl:number though; I wasn't able to find a way to avoid that. However, since they're at the end of the page, it's not a problem in practice.link [3] instead of link[3]. [Update 2019-01-01: I was able to fix this.]I'm a newbie with XSLT so there's some cargo cult involved. I'm simultaneously impressed that XSLT is able to do this, and horrified by how ugly it is. Someday I hope to revisit all of this, either improving the XSLT or moving away from it, but for now, it works reasonably well, and I'm happy with it.
See screenshots I posted on twitter, or try printing one of my pages to see how it looks. If you run into glitches, please let me know!
Update Here's a slightly different implementation:
Instead of adding a new element in XSLT, add an attribute:
<xsl:template match="//a"> <xsl:copy> <xsl:attribute name="data-endnote"> <xsl:number level="any" count="//a" format="1"/> </xsl:attribute> <xsl:apply-templates select="node() | @*"/> </xsl:copy> </xsl:template>
Then during printing, display that attribute using CSS:
*[data-endnote]:after { color: #000; content: "[" attr(data-endnote) "]"; text-decoration: none; font-size: 75%; position: relative; top: -0.5em; vertical-align: baseline; }
The advantage of this approach is that I don't have to add a new element. The downside is that the underlining of links will apply to the :after element so these superscripts will be underlined. Another downside is that the superscript is purely visual instead of using a semantic tag like <sup>. More CSS, less HTML.