Martin Helmut Fieber

Website style guide

Posted on

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, 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 designs to full-fledged, complete with pattern libraries and code. Every new prototype 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. Not saying there is a relation between "fancy technologies to "negatives", just stating what I wanted to reduce. I was creative my whole youth, 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 will be a WIP (work in progress), a simple website, no extras, nothing fancy. Getting something I started to like, I removed everything not necessary. I had a cookie banner, because everyone does — 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 realised I do 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, plain CSS and HTML.

This is not true anymore today. 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; 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. With "components" I refer to the combination of HTML and CSS to create a logical unit for my website.

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-300: #7232ff;
  --color-blue-500: #6200ee;
  --color-blue-700: #5200ac;

  --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-300
  • --color-blue-500
  • --color-blue-700
  • --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 …

—TV Tropes, Cassette Futurism
<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 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.

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>

List

So far there is only one type of list, an unordered list.

ul {
  margin: 0 0 0 var(--size-500);
  padding: 0;
}

ul 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 {
  margin: 0 0 var(--size-500) 0;
}
  • This is
  • an unordered list
<ul>
  <li>This is</li>
  <li>an unordered list</li>
</ul>

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.

.aside-ref {
  position: relative;
}

aside {
  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;
}

aside 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 aside width (240px), as
 * the page is not centered and the aside "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) {
  aside {
    --aside-width: 240px;

    top: var(--size-400);
    position: absolute;
    right: calc(-1 * (var(--aside-width) + var(--size-500)));
    width: var(--aside-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="aside-ref">
  <p>Show the aside and how to make that happen.</p>
  <aside><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%;
}
Image showing a close up of a hand in shadow typing on a retro-futuristic keyboard with thick key caps, a scene from the movie Alien.
Picture of the movie Alien (1979), copyright by Twentieth Century Fox Home Entertainment, LLC.

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;
}
Example video from the blog post about GUI development with C++ and ImGui.
<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;
Optional caption, JavaScript example.
<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.

← Show all blog posts