Inlining SVGs for Darkish Mode –
I’ll right here indulge within the conventional apply of utilizing my weblog to speak about how I’m utilizing my weblog.
This web page is constructed with the Hugo static website generator.
I just lately up to date it to make use of the newest model of the beautifulhugo theme, which unbeknownst to me included a darkish mode colorscheme.
Current browsers use the prefers-color-scheme choice to robotically select mild or darkish mode CSS kinds, if the web site helps it.
And my web site did assist it, not that I knew it till folks began commenting that my syntax-highlighted code blocks had been unreadable!
I found out the best way to toggle mild/darkish mode in Firefox (ctrl+shift+I
to open the inspector pane then click on the solar/moon icons), perused my web site, and located a fair larger drawback: my treasured vector diagrams that I put a lot time & effort into had been fully invisible in opposition to a darkish background!
Right here’s a fast publish about supporting darkish mode on my weblog by inlining SVGs and setting their shade with the currentColor
CSS variable.
My diagrams!
On a few of my posts I spent an alarming period of time creating lovely vector diagrams in TikZ.
You may see them on this post and this post.
They had been completely invisible on darkish mode!
My valuable diagrams!
Unacceptable.
I’ll exhibit the issue right here.
Attempt toggling mild & darkish mode whereas this diagram, which is embedded with the <img src=... />
HTML tag:
This diagram is a SVG (Scalable Vector Graphics) picture, the format of which is definitely human-readable!
If you happen to open this SVG file in an editor you’ll see a big XML doc that appears like:
<?xml model='1.0' encoding='UTF-8'?>
<!-- This file was generated by dvisvgm 2.8.2 -->
<svg model='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='auto' top='auto' viewBox='0 -169.028 193.633 169.028' model="stroke:currentColor; fill:currentColor; stroke-width:0" position="img">
<title>A state machine the place every transition is labeled with both H or T for heads or tails. The state machine followers out like a four-level full binary tree from the beginning state, aside from the paths solely flipping heads or solely flipping tails. Ranging from state 0 H goes to state 1, then H goes to state 3; nonetheless, from state 3 solely T goes to one of many six termination states whereas H goes again to state 1 to type an infinite loop. There's an identical loop on the T half of the tree.</title>
<g id='page1'>
<g remodel='matrix(1 0 0 -1 0 0)'>
<path d='M65.375 84.515625C65.375 91.39063 59.80078 96.9688 52.921875 96.9688C46.04687 96.9688 40.4687 91.39063 40.4687 84.515625C40.4687 77.63672 46.04687 72.0586 52.921875 72.0586C59.80078 72.0586 65.375 77.63672 65.375 84.515625Z' stroke='currentColor' fill='none' stroke-width='.3985' stroke-miterlimit='10'/>
<path d='M52.24766 86.84263C51.96891 86.83263 51.76953 86.61325 51.76953 86.39419C51.76953 86.25482 51.85922 86.10544 52.0786 86.10544C52.29766 86.10544 52.53672 86.27482 52.53672 86.66325C52.53672 87.11138 52.10828 87.51982 51.35141 87.51982C50.03641 87.51982 49.66797 86.50388 49.66797 86.06544C49.66797 85.28857 50.40485 85.13919 50.69391 85.0795C51.21172 84.97982 51.72985 84.87013 51.72985 84.32232C51.72985 84.063254 51.50078 83.226691 50.30547 83.226691C50.16578 83.226691 49.39891 83.226691 49.169846 83.754504C49.54828 83.704816 49.79735 84.003566 49.79735 84.28232C49.79735 84.51169 49.63797 84.63107 49.42891 84.63107C49.169846 84.63107 48.871096 84.422 48.871096 83.973566C48.871096 83.405754 49.4386 83.007316 50.29547 83.007316C51.90922 83.007316 52.29766 84.21263 52.29766 84.66107C52.29766 85.0195 52.10828 85.26857 51.98891 85.38825C51.71985 85.667 51.4311 85.717 50.99266 85.80638C50.63422 85.88638 50.23578 85.95607 50.23578 86.40419C50.23578 86.69294 50.47485 87.30075 51.35141 87.30075C51.60047 87.30075 52.09828 87.23107 52.24766 86.84263Z'/>
...
Each merchandise within the SVG (letters, arrows, circles, and many others.) is outlined by a <path>
merchandise plotting out a collection of factors alongside which a curve is interpolated.
Every of those <path>
objects has stroke
and fill
attributes controlling its shade.
The important thing factor to notice right here is SVG information are additionally legitimate HTML, so could be inlined in a bigger HTML doc.
Then, in the event you substitute the hardcoded black #000
shade worth within the stroke
and fill
attributes with the currentColor keyword, the paths will tackle the proper shade to be displayed in opposition to the background!
Right here’s the very same SVG file, however this time it’s inlined; see the way it modifications shade as you toggle mild & darkish mode!
If you happen to view the web page supply you’ll certainly see the total SVG current within the HTML.
The currentColor
key phrase doesn’t work on embedded SVGs, solely inlined SVGs.
If you wish to get even fancier you possibly can outline different shade values (just like the pink within the diagram above) as CSS variables whose worth will depend on the sunshine/darkish mode setting, however I haven’t gone there but.
In Hugo I used to be simply capable of inline the SVG utilizing the next customized shortcode, in layouts/shortcodes/inline-vector-figure.html
:
{{ $svgFile := (path.Be a part of (path.Dir .Web page.File.Path) (.Get 0)) }}
{ safeHTML }
Then on this publish I exploit the shortcode by specifying the relative path to the SVG:
{{< inline-vector-figure "../2020-09-11-probabilistic-distsys/knuth-yao.svg" >}}
There have been a couple of different issues to determine:
- Default Shade: These diagrams had been generated with TikZ, which outputs textual content as paths (though SVG does have a text element) that for some purpose should not have
stroke
orfill
attributes.
I may have painstakingly gone by way of my diagrams and added these attributes to all of the related paths, however SVG additionally helps setting default values for these within the top-level<svg>
tag with the attributemodel="stroke:currentColor; fill:currentColor; stroke-width:0"
. - Scaling: there’s an extremely detailed publish about scaling SVGs here, however I simply modified the
width
andtop
attribute values within the top-level<svg>
tag toauto
and it appears to work: the displayed SVG scales to the width of the textual content field.
Presumably this solely works on newer browsers, however I’m extra involved with my posts being readable sooner or later than previously; that’s why I made vector diagrams within the first place, so that they’d keep lovely as display screen decision elevated over time! - Accessibility: there’s at the moment no standardized technique of including alt-text to inlined SVGs, so I adopted the suggestions in this post and added the alt-text as a
<title>
ingredient within the SVG as a greatest effort; you possibly can see it by hovering over the inlined SVG up above.
I additionally added theposition="img"
attribute to the top-level<svg>
tag.
With that I declared victory.
Oddly this entire course of took me little or no time; I can see why folks take pleasure in net improvement, browsers are wonderful!
In all different fields of software program improvement nothing simply works; there are at all times tiny particulars that journey you up and take hours to work round.
I suppose that wasn’t the case right here as a result of browsers have had an unfathomable amount of labor put into them and are very permissive in what they settle for whereas nonetheless producing handsome paperwork.
One very last thing, Hugo really has native assist for ASCII diagrams so in the event you’re studying this and occupied with making your personal diagrams that may very well be a less complicated choice for you:
Syntax Highlighting
The basis reason for the unreadable syntax highlighting situation is a bug within the theme I’m utilizing.
Hugo helps syntax highlighting for a huge list of languages, however neither TLA⁺ nor Lean are amongst them.
My present answer is to modify between utilizing Haskell, Idris, or (oddly) Julia highlighting as good-enough stand-ins for these languages.
I may whip up a regex-based highlighting file for TLA⁺ to get it supported by Hugo (it doesn’t appear too difficult, it even has obscure languages like Whiley!) however after spending a lot time writing a TLA⁺ tree-sitter grammar it appears a betrayal of that work to regress from grammar-based highlighting to atypical regexes.
I spent a while what it will take so as to add tree-sitter highlighting to Hugo.
Andrew T. Biehl managed to do it for Jekyll.
So far as I can inform I must write an extension for goldmark, the markdown parser Hugo makes use of.
That is how ASCII diagrams are applied.
I took a couple of steps on this course however the estimated effort appeared to quickly exceed how a lot I cared.
So, a undertaking for one more time!
Conclusion
Thanks to everyone who messaged or commented in regards to the darkish mode rendering issues, and particularly to lobste.rs customers predrag and mk12 for explaining dark mode and how to handle it!
Additionally, if you recognize a greater technique for creating lovely SVG diagrams than TikZ please let me know.