CSS Tips

Functional

These CSS rules are almost exclusively functional and will provide a better experience for your visitors.

Font Size

Use a conservative font size and adjust fonts proportionally, at least this is how I think it works more intuitively. I generally do not enlarge fonts but you can set larger variables for headings and things of the sort.

:root {
  --font-size: 1rem;
  --font-size-small: calc(0.9 * var(--font-size));
  --font-size-smaller: calc(0.8 * var(--font-size));
  --line-height: 1.5;
  --regular-font:
    OpenDyslexic,
    "Atkinson Hyperlegible",
    Lexend,
    system-ui,
    sans-serif;
  --mono-font:
    "Jet Brains Mono",
    "Fira Code Mono",
     monospace;
}

body {
  font: var(--font-size) / var(--line-height) var(--regular-font);
}

pre, code {
  font: var(--font-size-small) var(--mono-font); /* we ignore line height here */
}

Indicate External Links

Indicating links from other websites is more important than you think, even more so when using descriptive links. But do not take my word for it.

We make use of the non breaking white space before the arrow symbol so that the browser does not break the link from the symbol when wrapping text in paragraphs. We also make sure to exclude links that contain images inside them because it looks ugly.

a[rel="external"]:not(:has(img))::after {
  content: "\00A0↗";
}

If you are not marking your external links with rel="external" then you could do the following:

a[href]:not([href*="domain.tld"], [href^="/"], [href^="#"])::after {
  content: "\00A0↗" / "External";
}
External links in Hugo

Use the following template in your layouts/_markup/render-link.html to automatically assign the external value to the rel attribute.

{{- $u := urls.Parse .Destination -}}
<a href="{{ .Destination | safeURL }}"
 {{- with .Title }} title="{{ . }}"{{ end -}}
 {{- if $u.IsAbs }} rel="external"{{ end -}}
>
 {{- with .Text }}{{ . }}{{ end -}}
</a>
{{- /* chomp trailing newline */ -}}
External links in Zine
&[target="_blank"]:not(:has(img))::after { content: "\00A0↗"; }

Zine automatically sets target="_blank" for every external link.

Specifying a Uniform Size for h1

<h1> headings withing sections should be rendered as <h2> in size. Mozilla show how and why to fix this

h1 {
  margin-block: 0.67em;
  font-size: 2em;
}

Nested Lists with Decimals

ol > li::marker { content: counters(list-item,'.') ''; }
ol > li { padding-left: 0.5em; }

Example:

  1. First Section
  2. Second Section
    1. First Article from Second Section
    2. Second Article from Second Section
      1. First Item from Second Article
      2. Second Item from Second Article
      3. Third Item from Second Article
    3. Hi Mom!
  3. Third Section

Found this solution in a stackoverflow question. It did not get much attention but it is the simplest of all. One has to add the “>” combinator otherwise this rule will target unordered lists nested inside ordered ones.

Hugo Footnotes

One thing to do if you are using Hugo you will want to avoid targeting the footnotes’s list:

:not(.footnotes, ul li) > ol > li::marker { content: counters(list-item,'.') ''; }
:not(.footnotes, ul li) > ol > li { padding-left: 0.5em; }

If for some reason you would like to target specific lists within your markdown in Hugo you can do so by tagging your list with a class of your choosing:

1. First Section
1. Second Section
   1. First Article from Second Section
   1. Second Article from Second Section
       1. First Item from Second Article
       1. Second Item from Second Article
       1. Third Item from Second Article
   1. Hi Mom!
1. Third Section
{ .class-of-your-choosing }

and then in your CSS:

.class-of-your-choosing:not(.footnotes) > ol > li {
   padding-left: 0.5em;
   &::marker { content: counters(list-item,'.') ''; }
}

Automatic Heading Numbering

body {counter-reset: h2}
h2 {counter-reset: h3}
h3 {counter-reset: h4}
h4 {counter-reset: h5}
h5 {counter-reset: h6}
h2:before {counter-increment: h2; content: counter(h2) ". "}
h3:before {counter-increment: h3; content: counter(h2) "." counter(h3) ". "}
h4:before {counter-increment: h4; content: counter(h2) "." counter(h3) "." counter(h4) ". "}
h5:before {counter-increment: h5; content: counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) ". "}
h6:before {counter-increment: h6; content: counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) "." counter(h6) ". "}
h2.nocount:before, h3.nocount:before, h4.nocount:before, h5.nocount:before, h6.nocount:before {content: ""; counter-increment: none}

Taken from philarcher.org.

Sticky Header

Make sure to put a background so that is not see through.

header {
  position: sticky;
  top: 0;
  z-index:1;
  background: var(--bg);
  height: 4rem;
}
Targeted heading scroll under sticky header

To prevent headings scrolling under the header when they are targeted(anchor links) add the scroll-padding-top rule:

Use at least as much padding as height you have in your header.

html { scroll-padding-top: 4rem; }

Tweak the amount to your need/liking.

Paragraph Indentation

/* Indend every paragraph */
article p { text-indent: 1.5em; }

/* Indent every consecutive paragraph */
article p + p { text-indent: 1.5em; }

Aesthetic Only

These rules are mostly irrevelevant to funcionality but they look nice.

Grayscale Image Hover Animation

img {
  filter: grayscale(100%);
  transition: 1s;
}
img:hover, img:focus { filter: none; }

Mark First Letter Of Article

article p:first-of-type::first-letter {
  font-size: 1.5rem;
  font-weight: bold;
  color: var(--red);
}

Scroll Progress Bar

@supports (animation-timeline: scroll(root)) {
  :root {
    container-type: scroll-state;
    container-name: my-container;
  }
  .progress { display: none }
  @container my-container scroll-state(scrollable: y) {
    .progress {
      height: 2px;
      background: var(--fg);
      position: absolute;
      left: 0;
      top: 0;

      /* for progress bar at the bottom and inside of a sticky header */
      /* bottom: -2px; */

      width: 100%;
      transform-origin: 0 50%;
      animation: scaleProgress auto linear;
      animation-timeline: scroll(root);
      display: flex;
    }

    @keyframes scaleProgress {
      0% { transform: scaleX(0); }
      100% { transform: scaleX(1); }
    }
  }
}

Then in your html:

<html>
  <head>
    <!-- … -->
  </head>
  <header>
    <!-- … -->
  </header>
  <body>
    <div class="progress"> </div>

    <!-- … -->
  </body>
</html>

Or inside the header:

<html>
  <head>
    <!-- … -->
  </head>
  <header>
    <!-- … -->
    <div class="progress"> </div>
  </header>
  <body>
    <!-- … -->
  </body>
</html>

User has to enable option for Firefox based browsers:

layout.css.scroll-driven-animations.enabled⁩⁨ ⁩

Animate Details

Slick <details> animation that only work on every browser but Firefox:

/* :root, html or body */
body { interpolate-size: allow-keywords; }

details::details-content {
  block-size: 0;
  display: block;
  transition: block-size 0.5s, content-visibility 0.5s;
  transition-behavior: allow-discrete;
  overflow: hidden;
}

details[open]::details-content {
  block-size: auto;
  block-size: calc-size(auto);
}
#css#web
Fonts OpenSearch Protocol