Implementing user experience improvements on my blog, including dark mode and a reading progress bar.
Reading on dev.to? See the actual effects here: hambly.dev/style-updates.html
Flashing cursor
I thought it would be cool to make the link in the header look like it has a flashing cursor. So I slapped a <blink>
tag on it! Just kidding, the blink tag is obsolete, so I found a CSS animation and tweaked it as required. Simply animate the text color to transparent and back each second, infinitely.
// SCSS
.blink {
color: $grey-color;
animation: 1s blink step-end infinite;
}
@keyframes blink {
from,
to {
color: transparent;
}
50% {
color: $grey-color;
}
}
Reading time estimate
I added a reading time estimate next to the published date, with the following Liquid include. It works by counting the number of words in the content, and dividing it by an average reading speed. I had to wrap the snippet below in raw tags so that it isn’t evaluated by Jekyll at build time!
{{
content
| number_of_words
| plus: 200
| divided_by: 200
| prepend: "⏱️ "
| append: " min read"
}}
Reading progress bar
I like the cosmetic effect of an animated progress bar while reading, enough to sacrifice my “Javascript only for analytics” rule. The site still works perfectly with Javascript disabled, which is what really matters - to the tech crowd anyway. Minimizing Javascript is good for mobile sites in general, as it all needs to be downloaded, parsed, and compiled. This increases CPU load and uses more energy from your precious battery.
The progress bar works by adding a <progress>
element to the page, and updating its value
attribute when scrolling. An event listener is added to the scroll
event, but we decouple the animation from the input events by using requestAnimationFrame
to cue the animation for the next browser repaint.
// add a <progress> element to the page, style and position it to taste
// <progress id="progress" max="100" value="0"></progress>
window.addEventListener("load", setup);
window.addEventListener("resize", setup);
var listening = false;
function setup() {
var scrollPosition = 0,
ticking = false,
progress = document.getElementById("progress"),
body = document.body,
html = document.documentElement,
width = 0;
var height = Math.max(
body.scrollHeight,
body.offsetHeight,
html.clientHeight,
html.scrollHeight,
html.offsetHeight
);
var maxScroll = height - html.clientHeight;
function update() {
scrollPosition = window.scrollY || window.pageYOffset;
if (!ticking) {
window.requestAnimationFrame(function() {
progress.value = (100 * scrollPosition) / maxScroll;
ticking = false;
});
ticking = true;
}
}
update();
if (!listening) {
// only add the scrolling event listener once!
window.addEventListener("scroll", update);
listening = true;
}
}
Dark mode
I recently found out about the prefers-color-scheme CSS media feature after seeing this post by Tom Brow, and I had to have it. Something about great artists stealing, and all that. 🔪
Initially I was looking for a dark mode option in browser settings, before finding out it’s an operating system wide setting. Here’s what it looks like on Windows 10.
This is nice and easy to do, just add another @media
declaration to your css, and then overwrite your styling as required. A really nice tidbit from Tom’s article is to apply a slight grayscale filter
to the images in dark mode, so they are subtly less bright.
// SCSS
@media (prefers-color-scheme: dark) {
body {
background-color: #222;
color: #eee;
}
pre,
code {
background-color: #444;
}
img {
filter: grayscale(20%);
}
a {
color: #fff;
text-decoration: none;
border-bottom: 2px $orange-color solid;
transition: color 1s;
&:hover {
color: $orange-color;
}
}
p {
color: #ddd;
}
}
Here’s how to enable dark mode on MacOS, iOS, and Android.
With style updates done, for now, I can concentrate on writing something a bit more technical. Until next time!
Top comments (0)