I’ve recently been working on making this site lighter. Most of that time was spent obsessing over streamlining CSS. This post details various optimisations I’ve used
reset
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-style: normal
}
This is a simple reset. There’s the usual margin and padding resets. Box sizing is set to border-box
so that borders and paddings are taken into account when defining elements’ widths and heights
The font style is reset because I use the dfn
and cite
tags, which are italicised by default. Italics more apropros for serifs
body
body {
margin: 0 auto;
padding: 3.3em 1.6em 3.3em 1.6em;
max-width: 64ch;
background-color: #e3dbc3;
font-size: 20px;
line-height: 1.6;
font-family: sans-serif
}
The site features a simple central column for content. The body is set to a maximum width of 64 ch. The ch
unit is defined by the width of the numeral “0”
The font size is set to 20 px and a line height of 1.6. The font is set to the browser’s default sans-serif. These can be reduced to a single property
font: 20px/1.6 sans-serif
The body is divided into four sections: header, aside, main, and footer.
aside, header, main { margin: 0 0 2.6rem 0 }
scale
The values used in margins, paddings, and the type scale are derived from the golden ratio (φ). I round these values to the nearest tenths to trim off a few bytes
0.78, 1.00, 1.27, 1.62, 2.06, 2.59, 2.62, 3.33, …
aside
The aside
section appears in project pages and contains links and time-tracker summaries. It’s a simple 3-column grid
aside {
display: grid;
grid-template-columns: 3fr 3fr 3fr;
grid-gap: 1.3em
}
Using the grid shorthand property and the repeat function, this can be shortened
grid: auto / repeat(3, 3fr)
The links appear in a list with disabled bullets
nav ul { list-style: none }
main
The main section contains various elements like paragraphs, images, and blockquotes, which are evenly spaced apart
main p, main blockquote,
main img, main code:not(.inline), main h2 {
margin: 0 0 1.3rem 0
}
However, this takes up way too much space. But since only direct children of the element are being targeted, the child combinator selector can be used:
main > 1 { margin: 0 0 1.3rem 0 }
hyperlinks
Hyperlinks are set to match to the body text colour. To avoid duplicated declarations, I combined the two into a separate block:
a, body { color: #222 }
I set the links’ focus and hover states to the inverse of the background and foreground colours. This was also applied to text selection and inline code
and kbd
elements
::selection, a:focus, a:hover, code.inline, kbd {
background-color: #222;
color: #e3dbc3
}
I didn’t style links any further. I used to dislike how underlined text was rendered because lines went through descenders but this is no longer the case in modern browsers
blocks
As demonstrated on this page, code blocks are a big part of the site. Code blocks are set to horizontally scroll when text overflows. Wrapping of the blocks’ contents is disabled
code:not(.inline) {
display: block;
padding: 0 1.6em 0 1.6em 0;
overflow-x: auto;
white-space: nowrap
}
Like the code blocks, blockquotes are padded to visually separate them from the rest of the content. The .q
class targets the paragraph element housing the quote itself; its only function is to provide a bit of space between the quote and the attribution
blockquote { padding: 0.8em 1.3em 0.8em 1.3em }
.q { margin: 0 0 .8rem 0 }
“Trifles make perfection and perfection is no trifle”
— Michelangelo
Images are housed in figure
blocks as they may have captions. The figure blocks aren’t modified, but the captions are center-aligned
figcaption { text-align: center }
Images are set to a width of 100% to make them responsive. The .p
class uses the image-rendering
property to scale pixel-art images. This enables me to host smaller images, effectively improving page load times
img { width: 100% }
.p { image-rendering: crisp-edges }
This is a 93-byte 16×10 image.Note: If you’re using Chrome, the image above may be blurry. For Chrome, image-rendering
must be set to pixelated
. I purposefully omitted this as I don’t care about Chrome
trifles
Here are some additional tricks I used for further reductions. I don’t necessarily recommend these practices as the savings they provide are somewhat trivial. That and you may be sacrificing some degree of stylesheet readability. However, for this endeavour, those savings are quite substantial
Remove units for zero values. If a value is a decimal below one, the zero can be omitted
kbd { padding: 0px 5px 0px 0px }
kbd { padding: 0 5px 0 0 }
Use IDs or class names in lieu of tag names, where appropriate
figcaption { text-align: center }
.f { text-align: center }
aside, header, main { margin: 0 0 2.6rem 0 }
.m { margin: 0 0 2.6rem 0; }
Make use of shorthand properties. Margins, for example, can be shortened like so:
body {
margin-top: 3.3em;
margin-right: 1.6em;
margin-bottom: 3.3em;
margin-left: 1.6em
}
body { margin: 3.3em 1.6em 3.3em 1.6em }
body { margin: 3.3em 1.6em }
Remove spaces around curly brackets and after semicolons and the last semicolon of each block
body { margin: 0 auto; padding: 3.3em 1.6em; }
body{margin:0 auto;padding:3.3em 1.6em}
Optional: Forget vendor prefixes. Forget IE. Forget Chrome.
results
I ended up with 609 bytes. According to CSS Stats, there are a total of 18 rules, 23 selectors, 30 declarations (all unique, no repetitions), and 19 properties
That’s all. Thanks for reading and I hope you learned something. If you have any suggestions for further optimisations, send me a message on the Fediverse or Twitter
Update: As of , the stylesheet has been reduced to 489 bytes
Update: 461 bytes as of