I’m currently looking for a job, so I have some free time. I decided to use it to work on the look and feel of this website some more, adding small design touches for a nicer, more accessible reading experience. I’ll share the highlights in this article!

Excuse this lil’ ad!
It helps me pay the bills and keep the site running. 😊

Working theme switcher

There were a few minor issues with the theme switcher (in the corner of your screen).

  • For starters, it didn’t work when the operating system was set to dark mode. The website would be correctly rendered in dark mode, but the theme switcher would simply not work.
  • Also Giscus (my comment system) wouldn’t adapt to the theme, so you’d have a bright section when using dark mode.

I’ve reworked theme-related code a lot. On the CSS side, I’ve leveraged the color-scheme property, and started using the light-dark(..) function pretty much all over the place.

:root {
  color-scheme: light dark;
}

body {
  color: light-dark(#444, #eee);
  background-color: light-dark(#fff, #222);
}

I’ve improved the control itself to be a tri-state button to support dark, light and automatic modes. I wasn’t super sure what would be the best markup for this, so I decided to leverage the mixed state from aria-pressed.

<!-- Button currently in light mode -->
<button
  type="button"
  aria-pressed="false"
  class="ThemeButton no-print" 
  title="Theme: light"
>
  <span class="visually-hidden">Dark mode</span>
  <!-- Appropriate icon for current mode here -->
</button>

Semantically, this is a button to control the dark mode specifically (not exactly the theme per se). The aria-pressed attribute determines whether the dark mode is enabled: true for yes, false for no, mixed for automatic (according to the operating system preference).

The JavaScript code just rotates between the 3 states, and backs up the preference in the local storage of the browser. When you interact with the button, it computes the next state, updates the aria-pressed and title attributes, and stores the new value in local storage.

I’ve also added a playful little hover animation for that button, making it wiggle. Try it here:

.ThemeButton:hover {
  animation: wiggle 500ms ease-out;
}

@keyframes wiggle {
  from { transform: rotate(10deg) }
  25% { transform: rotate(-10deg) }
  50% { transform: rotate(20deg) }
  75% { transform: rotate(-5deg) }
  to { transform: rotate(0deg) }
}

Fluid typography

Fluid typography is not new. Geoff Graham, among others, was already writing about it in 2017. Somehow, I never really bothered to look into it. I always found it to be an unnecessary trick. But I decided to come back to it and actually try it out, since this seems like the right place for that.

I’m not smart enough to really make sense of the math behind it, but this declaration essentially allows for variable font size between 1.25rem and 1.4rem. CSS-Tricks has a good article about fluid typography to dive deep into the concept.

body {
  font-size: min(max(1.25rem, 4vw), 1.4rem);
}

Creative embeds

Historically, blockquotes and informative callouts were rendered exactly the same on this website. This came from a time where I used to write content in pure Markdown with no HTML access, and used the blockquote syntax (>) to create callouts. It’s of course not great for semantics, so I eventually had 2 different components, and it was time to style them differently.

Let’s see them in action:

This is a blockquote. It is meant to represent a citation — from someone or somewhere, and renders a <blockquote> element.
— Kitty Giraudel

And:

They still do look similar! They bear the same pale blue background color, and the blue to pink gradient border. Speaking of which, for some reason it does not seem to be possible to render a gradient border using border-image with rounded corners. I have resorted to using this solution from StackOverflow:

blockquote {
  --background-color: light-dark(#f3f8fc, #303132);
  padding: 0.75em 1.5em;
  background-color: var(--background-color);
  border: 2px solid transparent;
  background-image:
    linear-gradient(var(--background-color), var(--background-color)),
    linear-gradient(to right, var(--blue), var(--pink));
  background-origin: border-box;
  background-clip: padding-box, border-box;
}

It’s a very clever approach: it uses a flat gradient (with no color change) applied all the way through the padding box, and the actual gradient applied to the border box, created by a transparent border.

Now, for the floating typographic marks, I’ve used absolutely positioned pseudo-elements: a curious interrobang for callouts, and curly quotation marks for blockquotes. For instance, here is the code for the callout:

.Info::before {
  content: '‽';

  opacity: 0.2;
  font: 1000% / 1 Baskerville, serif;
  color: var(--blue);

  position: absolute;
  bottom: 100%;
  left: 0;
  z-index: 1;

  transform: translate(-10%, 69%) rotate(-30deg);
}

It’s worth pointing out that the transform value for the pseudo-element is totally arbitrary. I just played with the values until I reached something I was happy with. It would need different values for a different font family or size.

To ensure the content within the callout sits on top of the decorative character (even though the latter is semi-transparent), we bump its z-index:

.Info > * { position: relative; z-index: 2; }

I have used the same design pattern for footnotes, and the editorial changes (see this article for an example). I really like the juxtaposition of a neatly bordered box, and a decorative element breaking out of it, bringing some dynamism!

Fleurons

I am fascinated by obscure typographic features. One of my recent reads is Shady Characters by Keith Houston a fabulous walk through a dozen or so typographic characters, such as &, and #, and †.

The other day, I stumbled upon this delightful website by Henry Desroches. Just before the footer stands this gorgeous little guy: ❦. Would you just look at it? It turns out that it has a name: the fleuron. Quoting Wikipedia:

A fleuron (/ˈflʊərɒn, -ən, ˈflɜːrɒn, -ən/), also known as a printers’ flower, is a typographical symbol, or glyph, used either as a punctuation mark or as an ornament for typographic compositions. Fleurons are stylized forms of flowers or leaves; the term derives from the Old French: floron (“flower”). Robert Bringhurst in The Elements of Typographic Style calls the forms “horticultural dingbats”. A commonly encountered fleuron is the ❦, the floral heart or hedera (ivy leaf), also known as an aldus leaf after Italian Renaissance printer Aldus Manutius.

I couldn’t resist inserting this “horticultural dingbat” in a few places, least of all between the post date and the expected reading time in the header of the article layout. Another tiny flourish that makes the layout feel more considered.

Squircle corners

I have recently (re)discovered squircle corners, and the fact that they are getting native support in CSS via the corner-shape property.

.box {
  border-radius: 1em;
  corner-shape: squircle;
}

I’ve switched most boxes to use squircle corners because I find them more aesthetically pleasing. So code blocks, blockquotes, callouts, outlines and more now use this new shape (provided your browser supports it).

Clearer focus styles

I’ve had these gradient links for a long time now. And I still like them a lot, but the effect can be quite subtle, especially on low resolution screens. So I’ve decided to make the focus styles more obvious by adding a proper pink outline:

a:focus-visible {
  outline: 2px solid var(--pink);
  outline-offset: 2px;
  border-radius: 0.25em;
  corner-shape: squircle;
}

Speaking of links, I’ve also added a little bit of spacing at the top of the page when linking to a heading so that it doesn’t lick the top of the window.

h2 {
  scroll-margin-top: 0.5rem;
}

Better ad placement

For some reason, I am still running ads on this website. It’s not like I make a lot of money from it though. I’ve been with CarbonAds for over 10 years, and probably haven’t made more than a few hundred bucks from them in all that time. But still, it pays for the occasional cup of coffee, so it’s kind of nice I guess.

Carbon requires the ad (which is ~330 × 114px) to be placed above the fold — for obvious reasons. I didn’t really know what to do with it, so I had placed it right below the title, centered. It didn’t look too great. Even worse, when running an ad-blocker (something I obviously also do), there would be this massive blank space under the page title for where the ad was supposed to show up. It would look awkward.

I had limited that problem a little by placing the ad in the bottom right corner of the screen for large viewports. But that wouldn’t happen before 1556-pixel-wide viewports.

So I’ve implemented a few changes. First, I’ve moved the ad a little lower in the page, while still living above the fold. When possible, I injected it after the first paragraph. This wasn’t too obvious in Liquid:

{% assign parts = content | split: "</p>" %}
{{ parts | first }}</p>

{% include "ad.html" %}

{% for part in parts offset: 1 %}
  {{ part }}{% unless forloop.last %}</p>{% endunless %}
{% endfor %}

And for it to fit better within the flow of the article, I’ve wrapped the ad in a visible container, with a dedicated slot and some text to explicitly mention that this callout is for an ad display.

Finally, I’ve made it so that if the ad couldn’t be loaded (because of an ad-blocker or any other reason), the ad container would be hidden entirely:

.Ad:not(:has(#carbonads)) { display: none }

@media screen and (min-width: 1556px) {
  .Ad          { display: contents }
  .Ad__text    { display: none }
  .Ad__carbon  { position: fixed; bottom: 0.5em; right: 1em }
}

Wrapping up

I think I covered the most important things! I’ve also cleaned up a lot of the code, particularly on the CSS side, but it’s not particularly interesting. Overall, I’m very happy with the design, and it’s been very fulfilling getting to work on it calmly and peacefully. I hope you like it!

Pssst! I am currently looking for my next job opportunity from March! Read more on LinkedIn.

Footnotes

  1. I have since decided to use the <aside> element for callouts. I think it is semantically appropriate, according to the MDN page on this element.
  2. I understand the emdash has been co-opted by LLMs, and using it is discouraged to avoid looking like an AI, but the fact is I truly love the emdash — you will never take it away from me!

Read next post: Six months of Rust