New May 11, 2026

Nerdy Design Details

More Front-end Bloggers All from Kitty Giraudel View Nerdy Design Details on kittygiraudel.com

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!

Working theme switcher

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

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 NoPrint"
	title="Theme: light"
>
	<span class="VisuallyHidden">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:

.Callout::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:

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

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

Heading anchors

I have had a love-hate relationship with heading anchors over the years. I’ve had them, removed them, had them again, removed them again. Well guess what? They’re back! I was seduced by Zach Leat’s elegant heading-anchors web component. It’s very light, accessible, and easy to use.

<heading-anchors selector="h2,h3,h4" content="§">
	<!-- Page content -->
</heading-anchors>

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.liquid" %}

{% 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!

Scroll to top