Website style guide
In the beginning, there was complexity
Years ago, when I set out to create my own website, I did not, as I was overwhelmed with possibilities. I thought about complex, intriguing designs with the highest technical fidelity, amazing Easter eggs, and a mind-blowing user experience. Creating a mountain in front of myself, unable to climb, ever-growing.
Back then, when I was creating websites professionally, of course I wanted to have the best of the best of the best. I did 26 design iterations, from pure Sketch to full-fledged designs, complete with pattern libraries and code. Every new prototype was more complex than the one before.
I also went through a lot of technologies I could use — from the well-known to the never-heard-of, including the (in)famous "I will build my own X". Creating holistic testing strategies, code guidelines, documentation, … you name it. "Everything a professional does", so I convinced myself.
Simplicity
I deleted it all. What if: just HTML and CSS, no fancy technologies, no pop-ups, no content jumps? I'm not saying there is a relationship between "fancy technologies to "negatives", just stating what I wanted to reduce. I was creative my whole youth; I learned to be a designer and even worked as one for a while. But I am no designer, not anymore, and I did not love the time I was, or at least what I was doing back then.
I started working on something I thought would be a WIP (work in progress), a simple website with no extras and nothing fancy. After getting something I started to like, I removed everything not necessary. I had a cookie banner because everyone had one — but why? Do I have cookies? Do I need them? I mean, realistically, cookies are amazing, the ones to eat, but I had none on my website, so gone with the cookie banner.
Looking at what I had, I realized I did like it. It was simple but functional, covering all my needs for a small website. What was previously meant to be a WIP became the final result — no build system, no JavaScript, just plain CSS and HTML.
This is not true anymore. While my site grew, I switched to 11ty, a static site generator that did not lock me into a specific framework. I was able to gradually streamline some parts of maintaining my website, but that was all. Just a bit of help managing the blog, creating a feed, and the sitemap. Everything else still holds true, including simplicity.
The style guide
The following content is a living document of defined styles and components, how to use them, and how they are created. "Components" refers to the combination of HTML and CSS to create a logical unit for my website.
Theming
The site does support light and dark mode. This is also represented in this style-guide. There are multiple options to switch between those themes.
- When supported, switch themes via the operating system.
- Use the theme toggle button at the end of the page.
- Use the shortcut Shift+T anywhere on the page.
Any of those options is valid and can be used to view elements in different themes.
Variables
Not having any build system, I still wanted to have some kind of variables for my CSS — custom properties to the rescue. With very good browser support I hesitated not, using custom properties for fonts, sizes, and colors.
Because I did not want to include custom fonts I use a standard set of
sans-serif font families. The variables, defined inside the pseudo-class
:root
, look as follows.
:root {
--base-font: "HelveticaNeue-Light",
"Helvetica Neue Light", "Helvetica Neue",
Helvetica, Arial, "Lucida Grande", sans-serif;
--font-weight-normal: 300;
--font-weight-bold: 700;
}
For consistency of e.g. paddings and margins I define a set of reusable sizes.
:root {
/* Other variables ... */
--size-100: 1px;
--size-300: 5px;
--size-400: 10px;
--size-500: 20px;
--size-600: 30px;
--size-700: 40px;
}
And at last, a set of colors.
:root {
/* Other variables ... */
--color-blue-100: #f5f1ff;
--color-blue-200: #b392f7;
--color-blue-300: #7232ff;
--color-blue-500: #6200ee;
--color-blue-700: #5200ac;
--color-blue-800: #3b2e4d;
--color-blue-900: #191223;
--color-grey-200: #f1f1f1;
--color-grey-300: #dcdcdc;
--color-grey-500: #aaaaaa;
--color-grey-700: #767676;
--color-grey-800: #595959;
--color-grey-900: #0f0f0f;
}
Here how they look like:
-
--color-blue-100
-
--color-blue-200
-
--color-blue-300
-
--color-blue-500
-
--color-blue-700
-
--color-blue-800
-
--color-blue-900
-
--color-grey-200
-
--color-grey-300
-
--color-grey-500
-
--color-grey-700
-
--color-grey-800
-
--color-grey-900
Headlines
There are five headlines defined, where h1
is reserved for the
website title. There is a base set of styles all headings inherit.
h1,
h2,
h3,
h4,
h5 {
font-family: var(--base-font);
font-weight: var(--font-weight-bold);
line-height: 1.65;
color: var(--color-grey-900);
padding: 0;
}
The font size and margin for headings are defined per heading.
h1 {
font-size: 2rem;
margin: 0;
}
h2,
h3,
h4,
h5 {
margin: 0 0 var(--size-500) 0;
}
h2 {
font-size: 1.5rem;
}
h3 {
font-size: 1.4rem;
}
h4 {
font-size: 1.17em;
}
h5 {
font-size: 1rem;
}
.h1 Website title
Only used once per page as website title.
<h1>.h1 Website title</h1>
.h2 Page title
This heading size is used for page titles or to separate larger content areas.
<h2>.h2 Page title</h2>
.h3 Section title
Used in an article or page.
<h3>.h3 Section title</h3>
.h4 Sub-section title
Further divide content in articles or pages.
<h4>.h4 Sub-section title</h4>
.h5 Paragraph heading
Small additional heading for paragraphs.
<h5>.h5 Paragraph heading</h5>
Text
Text styles are kept minimal. What you see all the time here, and right now, is a paragraph.
Paragraphs
Seven lines of style declarations are all for paragraphs.
p {
font-family: var(--base-font);
font-size: 1.3rem;
font-weight: var(--font-weight-normal);
color: var(--color-grey-900);
line-height: 1.65;
margin: 0 0 var(--size-500) 0;
padding: 0;
}
This is a simple paragraph.
<p>This is a simple paragraph.</p>
Blockquote
Blockquote components will inherit all paragraph styles, besides defining own unique styles. There is also some extras for paragraphs inside blockquote elements. All blockquote elements will be inside a figure element.
p,
blockquote {
/* paragraph styles ... */
}
blockquote {
font-style: italic;
margin: 0;
border-left: var(--size-300) solid var(--color-grey-300);
}
blockquote p {
margin: 0 0 0 var(--size-500);
}
blockquote + figcaption {
text-align: right;
}
A technological aesthetic reminiscent of late 1960s to early 1980s tech (regardless of the real time setting of the media) as codified by early microcomputers …
<figure>
<blockquote cite="https://link.to/source">
<p>
A technological aesthetic reminiscent
of late 1960s to early 1980s tech
(regardless of the real time setting
of the media) …
</p>
</blockquote>
<figcaption>
—TV Tropes, <cite>Cassette Futurism</cite>
</figcaption>
</figure>
Strong
The CSS for the strong
element is just making it
bold.
strong {
font-weight: var(--font-weight-bold);
}
This is very strong text.
<p>This is <strong>very strong text</strong>.</p>
Emphasis
Emphasising text comes in two "flavours"; one is the semantic version, the other is a visual representation only.
em {
font-style: italic;
}
.emphasize {
font-style: normal;
font-weight: var(--font-weight-normal);
text-transform: uppercase;
}
This is emphasised.
<p>This is <em>emphasised</em>.</p>
This is also emphasised, but only visually.
<p>This is also <b class="emphasize">emphasised</b>, ...</p>
Links
Links are represented by color and a simple hover effect. There is also a
separate style when a definition element dfn
is used inside.
a {
color: var(--color-blue-500);
cursor: pointer;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
a > dfn {
font-style: normal;
}
Here is a link.
<p>Here is a <a href="#links" title="A link to this section.">link</a>.</p>
Including a definition element.
<p>Including a <a href="..." title="..."><dfn>definition element</dfn></a>.</p>
Don't forget, every link needs a title.
Shortcuts
The kbd
element represents a shortcut, whereas a nested
kbd
element will represent a sequence of keystrokes.
kbd > kbd {
background-color: var(--color-grey-200);
border-radius: 3px;
border: 1px solid var(--color-grey-500);
box-shadow:
0 1px 1px rgba(0, 0, 0, 0.2),
0 2px 0 0 rgba(255, 255, 255, 0.7) inset;
color: var(--color-grey-900);
display: inline-block;
font-size: 0.8em;
font-weight: var(--font-weight-bold);
line-height: 1;
padding: 2px 4px;
white-space: nowrap;
}
To toggle the theme, use the shortcut Shift+T.
<p>
To toggle the theme, use the shortcut
<kbd><kbd>Shift</kbd>+<kbd>T</kbd></kbd>.
</p>
Address
Address elements get some original italic style.
address {
font-style: italic;
}
La Taverna del Brigante
Via Aldo Manuzio, 82
04010 Bassiano LT
Italy
<address>
<p>
La Taverna del Brigante
<br />
Via Aldo Manuzio, 82
<br />
04010 Bassiano LT
<br />
Italy
</p>
</address>
Callout
The callout is used to bring focus to important information, most often used in a tutorial or similar knowledge focused articles.
.callout {
border: 1px solid var(--color-blue-500);
border-radius: var(--size-300);
background: var(--color-blue-100);
margin-bottom: var(--size-500);
padding: var(--size-400);
}
.callout h4,
.callout h5 {
font-size: 1rem;
color: var(--color-blue-500);
margin-bottom: var(--size-300);
}
.callout h4::before,
.callout h5::before {
content: "\024D8";
margin-right: var(--size-300);
}
.callout p {
color: var(--color-grey-800);
font-family: var(--base-font);
font-size: 1rem;
font-weight: var(--font-weight-normal);
line-height: 1.65;
margin: 0;
padding: 0;
}
<aside class="callout">
<h4>This is a callout</h4>
<p>And this is the content of the callout.</p>
</aside>
Flag object
The "flag object" is a combination of a fixed size media element with dynamic content to the side. The media element can be located left or right.
.flag {
display: flex;
align-items: flex-start;
}
.flag-media {
padding-top: var(--size-300);
}
.flag-media img {
border: 1px solid var(--color-grey-500);
border-radius: var(--size-400);
}
.flag-media + .flag-content {
margin-left: var(--size-400);
}
.flag-content + .flag-media {
margin-right: var(--size-400);
}

This is a headline
<div class="flag">
<div class="flag-media">
<img
src="/assets/placeholder_60x60.png"
alt="..."
width="60"
height="60"
/>
</div>
<div class="flag-content">
<h3>This is a headline</h3>
<footer>
<p>And how about some text?</p>
</footer>
</div>
</div>
Lists
There are three types of lists. Ordered, unordered, and horizontal text lists.
Order and Unordered list
ul,
ol {
margin: 0 0 0 var(--size-500);
padding: 0;
}
ul li,
ol li {
font-family: var(--base-font);
font-size: 1.3rem;
font-weight: var(--font-weight-normal);
color: var(--color-grey-900);
line-height: 1.65;
margin: 0;
padding: 0;
}
ul li:last-child,
ol li:last-child {
margin: 0 0 var(--size-500) 0;
}
ul ul li:last-child,
ul ol li:last-child,
ol ul li:last-child,
ol ol li:last-child {
margin: 0;
}
- This is
- an unordered list
- This is
- an ordered list
<ul>
<li>This is</li>
<li>an unordered list</li>
</ul>
<ol>
<li>This is</li>
<li>an ordered list</li>
</ol>
Horizontal text list
A simple list with a title to show items horizontally.
.list figcaption {
font-size: 1.3rem;
font-weight: var(--font-weight-bold);
color: var(--color-grey-900);
display: inline-block;
}
.list ul,
.list ul li,
.list ul li:last-child {
display: inline-block;
padding: 0;
margin: 0 0 0 var(--size-300);
}
- One item,
- Another item,
- Last item
<figure class="list">
<figcaption>Title:</figcaption>
<ul>
<li>One item,</li>
<li>Another item,</li>
<li>Last item</li>
</ul>
</figure>
Side notes
To show additional information aside I was under the impression I will need
JavaScript for proper placement or at least a rather complex structure.
Happily this was not the case, all it needed was a container wrapping what
will be referenced and the aside
absolute placed in relation to
it.
.side-note-ref {
position: relative;
}
.side-note {
border-top: solid 1px var(--color-grey-300);
border-bottom: solid 1px var(--color-grey-300);
margin-bottom: var(--size-500);
padding: var(--size-400) 0;
}
.side-note p {
color: var(--color-grey-800);
font-family: var(--base-font);
font-size: 1rem;
font-weight: var(--font-weight-normal);
line-height: 1.65;
margin: 0;
padding: 0;
}
/**
* The min-width is calculated by the page width (660px)
* plus twice the amount of the side note width (240px), as
* the page is not centered and the side note "reaches" out
* of the page on the right.
* There are also 20px added (on both sides) to give the
* whole some space. In short: `660 + (20 + 240) * 2`.
*/
@media (min-width: 1180px) {
.side-note {
--side-note-width: 240px;
top: var(--size-400);
position: absolute;
right: calc(
-1 * (var(--side-note-width) + var(--size-500))
);
width: var(--side-note-width);
border-bottom: none;
}
}
Show the aside and how to make that happen. This will only show on the right side of the content on larger screens. Otherwise, it will be part of the content flow.
<div class="side-note-ref">
<p>Show the aside and how to make that happen.</p>
<aside class="side-note"><p>Extra info</p></aside>
</div>
Media
Media on this site are images and video, but can also be other
rich‑content like code blocks. It is placed inside a
figure
element with caption. Every image will have a
webp version, every video a webm.
The basic media content style is for the figure
and
figcaption
element.
figure {
margin: 0 0 var(--size-500) 0;
padding: 0;
}
figcaption {
color: var(--color-grey-800);
font-family: var(--base-font);
font-size: 1rem;
font-weight: var(--font-weight-normal);
line-height: 1.65;
margin: 0;
padding: 0;
}
Images
Images will always have a webp version and a caption. They are
placed inside the picture
element, and will show up larger on
mobile devices by using the full device width.
img + figcaption,
picture + figcaption {
text-align: center;
}
picture {
/*
* Show pictures in full width by negating the page
* margin left and right.
*/
margin: 0 calc(-1 * var(--size-500));
display: block;
}
@media (min-width: 660px) {
picture {
margin: 0;
}
}
img,
video {
display: block;
margin: 0 auto;
height: auto;
max-width: 100%;
}

The loading="lazy"
is only used for images below the initial
viewport.
<figure>
<picture>
<source
type="image/webp"
srcset="/assets/blog/style-guide/example.webp"
/>
<img
src="/assets/blog/style-guide/example.jpeg"
alt="Image showing a close up of a hand ..."
loading="lazy"
width="1280"
height="524"
/>
</picture>
<figcaption>
Picture of the movie Alien ...
</figcaption>
</figure>
Video
Similar to webp for images, video will always have a webm version and a caption. A "poster" will be used to show a preview image of the video.
video {
height: auto;
max-width: 100%;
}
video + figcaption {
text-align: center;
}
<figure>
<video
controls
width="1008"
height="720"
poster="/path/to/poster.png"
>
<source
src="/path/to/video.webm"
type="video/webm"
/>
<source
src="/path/to/video.mp4"
type="video/mp4"
/>
It appears your browser doesn't support embedded videos.
</video>
<figcaption>
Example video caption ...
</figcaption>
</figure>
Code
Code can be used inside paragraphs and as standalone code blocks with syntax highlighting.
Inline code
Inside text the code
element is used.
p code {
font-size: 1rem;
padding: 0.05rem;
vertical-align: middle;
background-color: var(--color-grey-200);
}
<p>Inside text the <code>code</code> element is used.</p>
Code blocks
Code blocks are placed inside figure
elements and can have
optionally a figcaption
. Syntax highlighting is
supported through
highlight.js
Besides some custom styling, styles are taken from a highlight.js theme
represented by CSS classes prefixed with hljs-
.
pre code.hljs {
font-family: monospace;
font-size: 0.8rem;
display: block;
overflow-x: auto;
white-space: pre-wrap;
padding: 1rem 0;
color: var(--color-grey-900);
border-top: 1px solid var(--color-grey-500);
border-bottom: 1px solid var(--color-grey-500);
}
@media (min-width: 660px) {
pre code.hljs {
padding: 1rem;
font-size: 1rem;
}
}
/*
* Syntax styles are from one of the many styles
* provided here:
*
* github.com/highlightjs/highlight.js/tree/main/src/styles
*/
There is a range of supported languages, those are: Bash, C, C++, CSS, Diff, HTML, XML, JSON, JavaScript, Lua, Markdown, Python, Rust, SQL, Shell, TOML, INI, TypeScript, YAML, .properties, Augmented Backus-Naur Form, Backus–Naur Form and CMake.
A different set of supported languages, or even more, can be set up on the highlight.js configuration page.
// code example
const a = 1;
<figure>
<pre><code class="language-js hljs">// code example
const a = 1;</code></pre>
<figcaption>Optional caption</figcaption>
</figure>
Epilogue
This concludes the set of noteworthy components styled through the style.css file. Over time this will expand and cover whatever new components I will add. For now, that was it.