Digging around in the cascades

A warning :: I haven’t done all my homework. Most of the following is based on trial-and-error hacking on this code, a little bit of research, and a lot of reading this one stylesheet. Errors are likely to abound. I’ll continue to improve this as the mistakes become apparent.

I’ve been looking at how to better structure a website visually. One of my favourite websites visually is gwern.net for its minimalist design and functional and (in my opinion) appealing use of sidenotes/footnotes which give it its almost newspaper feel.

The attention to detail and the responsive design mean that it looks good regardless of the your screen size and it gracefully adapts to screen size and and bandwidth. An unprettified skeleton, the simplest version of the site is rendered first which, due to the minimalist design, does not look much different from the final version. What I find interesting are the crafted details that make the design work visually, regardless of screen size.

I’ve had a look at how Gwern’s page is built and I’ve broken down some of how the site handles just one aspect of the visual experience.

Drop Caps

For the uninitiated, these are the large often decorated first letter that begin chapters and some paragraphs in most illuminated manuscripts. A relic of illustrated manuscripts, even modern paperbacks have dropped the use of drop caps in favour of a more casual or vulgar cold open.

What follows is a breakdown of how gwern.net does drop caps; for reference, the full code is reproduced at the bottom the page :

A simplified approach

Here’s an example stylesheet for the drop-cap class.1

  .drop-cap + .drop-cap::first-letter  {
      font-size: 6.125em;
      margin: 3px 1px -0.25em 1px; }

  .drop-cap::first-letter {
      font-family: Goudy Initialen;
      font-size: 8em;
      float: left;
      clear: left;
      line-height: 1;
      margin: -1px -1px -0.25em 1px; }
Code Snippet 1: Above: an example of how drop caps can be done.

So the basic idea is that one uses the ::first-letter selector to pick out the first letter from a some text — usually in a <p>‌aragraph but it could be any text. We then apply the CSS rules to make it larger and then give it some space; this is what the font-size and margin: 3px 1px 0.25em 1px; rules do.

Responsive design and smart fallbacks :: lines 1-73

If we just used the above rules we’d end up enlarging the first letter of any HTML element with the drop-cap class; what more could you want?

The style sheet we will be studying below takes this and several other considerations in hand and builds a responsive site that handles most edge cases without losing legibility.

Responsive design is all about intelligently making use of the space available. This responsive design starts by knowing when to leave the fancy stuff behind. it may be best to leave off a fancy feature if it would sacrifice screen space that could be better served by making content easily accessible. He starts by checking screen size with @media only screen and (min-width: 65ch). This rule matches any device that is wide enough to show at least 65 characters2 at the current font size and tells the browser to continue reading the stylesheet. Any devices which do not meet this minimum criteria skip the drop caps section of the stylesheet and they do not appear on those device. We do not want to waste screen space or bandwidth on downloading and presenting the drop caps fonts to users who will not benefit from their presence.

Ah, yes, fonts.

Typography is an important part of the æsthetics of gwern.net and the choice of drop caps typeface is no small part of that. Not satisfied with simply enlarging the body typeface3, Gwern uses an initials typeface for all instances of drop caps throughout the site. In fact, he uses three different fonts, each of which he has customised to avoid the end user loading or downloading large font files4 when only one or two letters per page which will be actually be shown to the reader. The css margin rules are carefully customised5 to fit around the letters of a each font individually. To keep the parts of the site visually distinct, he has chosen to use three separate typefaces which help differentiate the matière when it might be useful:

Goudy
literary/historical/humanities
yinit
technical/scientific
De-Zs
everything else

Much of the code is repeated to handle each of these font-family’s independently of the rest as they each have unique sizes, weights, and proportions.

There is also code for another two fonts: cheshire and kanzlei which use the Cheshire Intitialen and Kanzlei Initialen font-family respectively — though they do not seem to be used currently.

Responsive design :: lines 77-150

Here follows a set of @media only screen and (max-width: ###ch) drawers6 which adapt the font-size of the dropcaps for each font-family individually for each of two larger sizes. Since these two are subordinate to the earlier (min-width: 65ch) drawer that gives four different settings.

Table 1: These are often almost imperceptible changes, but they make a difference visually and contribute to the typographical cohesiveness of the site.

the drawers the contents (CSS rules)
0ch - 65ch do not show drop caps
120ch + the largest font size
101ch - 120ch slightly smaller size
66ch - 100ch yet smaller font size

The latter two rulesets function to ‘compensat[e] for responsive line-height reduction’, presumably found elsewhere in the CSS.

Special case of @support… :: lines 154-191

In addition to all these he adds at the end a set of ‘[s]pecial styles for special browsers.’ Comments he leaves in the /default.css style sheets lead me to believe he intends us to understand that as Firefox. This is supported by the code which follows: @supports (-moz-user-focus: normal).

Whereas all by the first of the previous (i.e. the @media drawers changed the font size, this one (@supports) changes the margins at all sizes if the browser supports the non-standard -moz-user-focus property, which defines focus behaviour (for example when TAB is pressed). Naturally, support for it exists only on Firefox (and Firefox for Android) according to mdn/browser-compat-data.

the Take-Away

If this CSS is to be taken as suggestion — not simply as one among may implementations7 — it looks like there is to be a great deal of trial and error, to be followed by bespoke preferences for varying forms of consumption. There’s no use in providing a bunch of server rendered animations, fonts or images if the end user has a slow connection or limited bandwidth; and it makes as little sense to run miles of JavaScript or jQuery code if the end user has limited rendering capacity.

This does not however limit the possibilities for those who do have larger screens, unlimited 4g, and 64-gigabytes of RAM downloaded. So, the first notes to be taken from this are I) to build for the least-common-denominator, then II) use a set of exclusionary rules for base content rendering, and III) add the final doo-dahs and bell-whistles afterwards.

Maybe.

The whole thing, for those interested:

  @media only screen and (min-width: 65ch) {
      body[class*='drop-caps-'] #markdownBody > p:first-child::first-letter,
      body[class*='drop-caps-'] #abstract + p::first-letter,
      body[class*='drop-caps-'] #markdownBody > .epigraph:first-child + p::first-letter,
      #markdownBody *[class*='drop-cap-']::first-letter,
      #markdownBody *[class*='drop-cap-'] > p::first-letter {
          font-style: normal;
          font-weight: normal;
          float: left;
      }

      /*  All of these numbers are magic.
          */
      body.drop-caps-goudy #markdownBody > p:first-child::first-letter,
      body.drop-caps-goudy #abstract + p::first-letter,
      body.drop-caps-goudy #markdownBody > .epigraph:first-child + p::first-letter,
      #markdownBody .drop-cap-goudy::first-letter,
      #markdownBody .drop-cap-goudy > p::first-letter {
          font-family: "Goudy Initialen";
          font-size: 7em;
          line-height: 1;
          margin: 0 0.02em -0.25em 0;
      }
      body.drop-caps-yinit #markdownBody > p:first-child::first-letter,
      body.drop-caps-yinit #abstract + p::first-letter,
      body.drop-caps-yinit #markdownBody > .epigraph:first-child + p::first-letter,
      #markdownBody .drop-cap-yinit::first-letter,
      #markdownBody .drop-cap-yinit > p::first-letter {
          font-family: Yinit;
          font-size: 5.625em;
          line-height: 1.35;
          margin: 0.015em 0.04em -0.5em 0.01em;
          text-shadow: 0 0 0 #777;
          opacity: 0.95;
      }
      body.drop-caps-de-zs #markdownBody > p:first-child::first-letter,
      body.drop-caps-de-zs #abstract + p::first-letter,
      body.drop-caps-de-zs #markdownBody > .epigraph:first-child + p::first-letter,
      #markdownBody .drop-cap-de-zs::first-letter,
      #markdownBody .drop-cap-de-zs > p::first-letter {
          font-family: "Deutsche Zierschrift";
          font-size: 6.5em;
          line-height: 1.1;
          margin: 0.01em 0.03em -0.25em 0;
          text-shadow:
               0px 2.5px 0 #fff,
              -4px   4px 0 #fff,
               4px   4px 0 #fff;
          color: #191919;
          opacity: 0.99;
      }
      body.drop-caps-cheshire #markdownBody > p:first-child::first-letter,
      body.drop-caps-cheshire #abstract + p::first-letter,
      body.drop-caps-cheshire #markdownBody > .epigraph:first-child + p::first-letter,
      #markdownBody .drop-cap-cheshire::first-letter,
      #markdownBody .drop-cap-cheshire > p::first-letter {
          font-family: "Cheshire Initials";
          font-size: 6.75em;
          line-height: 1;
          margin: 0.02em 0.04em -0.25em 0;
          opacity: 0.9;
      }
      body.drop-caps-kanzlei #markdownBody > p:first-child::first-letter,
      body.drop-caps-kanzlei #abstract + p::first-letter,
      body.drop-caps-kanzlei #markdownBody > .epigraph:first-child + p::first-letter,
      #markdownBody .drop-cap-kanzlei::first-letter,
      #markdownBody .drop-cap-kanzlei > p::first-letter {
          font-family: "Kanzlei Initialen";
          font-size: 7em;
          line-height: 1;
          margin: 0 0.01em -0.25em -0.03em;
          opacity: 0.9;
      }

      /*  Compensating for responsive line-height reduction.
          */
      @media only screen and (max-width: 120ch) {
          body.drop-caps-goudy #markdownBody > p:first-child::first-letter,
          body.drop-caps-goudy #abstract + p::first-letter,
          body.drop-caps-goudy #markdownBody > .epigraph:first-child + p::first-letter,
          #markdownBody .drop-cap-goudy::first-letter,
          #markdownBody .drop-cap-goudy > p::first-letter {
              font-size: 6.875em;
          }
          body.drop-caps-yinit #markdownBody > p:first-child::first-letter,
          body.drop-caps-yinit #abstract + p::first-letter,
          body.drop-caps-yinit #markdownBody > .epigraph:first-child + p::first-letter,
          #markdownBody .drop-cap-yinit::first-letter,
          #markdownBody .drop-cap-yinit > p::first-letter {
              font-size: 5.375em;
          }
          body.drop-caps-de-zs #markdownBody > p:first-child::first-letter,
          body.drop-caps-de-zs #abstract + p::first-letter,
          body.drop-caps-de-zs #markdownBody > .epigraph:first-child + p::first-letter,
          #markdownBody .drop-cap-de-zs::first-letter,
          #markdownBody .drop-cap-de-zs > p::first-letter {
              font-size: 6.375em;
          }
          body.drop-caps-cheshire #markdownBody > p:first-child::first-letter,
          body.drop-caps-cheshire #abstract + p::first-letter,
          body.drop-caps-cheshire #markdownBody > .epigraph:first-child + p::first-letter,
          #markdownBody .drop-cap-cheshire::first-letter,
          #markdownBody .drop-cap-cheshire > p::first-letter {
              font-size: 6.625em;
          }
          body.drop-caps-kanzlei #markdownBody > p:first-child::first-letter,
          body.drop-caps-kanzlei #abstract + p::first-letter,
          body.drop-caps-kanzlei #markdownBody > .epigraph:first-child + p::first-letter,
          #markdownBody .drop-cap-kanzlei::first-letter,
          #markdownBody .drop-cap-kanzlei > p::first-letter {
              font-size: 6.875em;
          }
      }
      @media only screen and (max-width: 100ch) {
          body.drop-caps-goudy #markdownBody > p:first-child::first-letter,
          body.drop-caps-goudy #abstract + p::first-letter,
          body.drop-caps-goudy #markdownBody > .epigraph:first-child + p::first-letter,
          #markdownBody .drop-cap-goudy::first-letter,
          #markdownBody .drop-cap-goudy > p::first-letter {
              font-size: 6.625em;
          }
          body.drop-caps-yinit #markdownBody > p:first-child::first-letter,
          body.drop-caps-yinit #abstract + p::first-letter,
          body.drop-caps-yinit #markdownBody > .epigraph:first-child + p::first-letter,
          #markdownBody .drop-cap-yinit::first-letter,
          #markdownBody .drop-cap-yinit > p::first-letter {
              font-size: 5.25em;
          }
          body.drop-caps-de-zs #markdownBody > p:first-child::first-letter,
          body.drop-caps-de-zs #abstract + p::first-letter,
          body.drop-caps-de-zs #markdownBody > .epigraph:first-child + p::first-letter,
          #markdownBody .drop-cap-de-zs::first-letter,
          #markdownBody .drop-cap-de-zs > p::first-letter {
              font-size: 6.125em;
          }
          body.drop-caps-cheshire #markdownBody > p:first-child::first-letter,
          body.drop-caps-cheshire #abstract + p::first-letter,
          body.drop-caps-cheshire #markdownBody > .epigraph:first-child + p::first-letter,
          #markdownBody .drop-cap-cheshire::first-letter,
          #markdownBody .drop-cap-cheshire > p::first-letter {
              font-size: 6.3125em;
          }
          body.drop-caps-kanzlei #markdownBody > p:first-child::first-letter,
          body.drop-caps-kanzlei #abstract + p::first-letter,
          body.drop-caps-kanzlei #markdownBody > .epigraph:first-child + p::first-letter,
          #markdownBody .drop-cap-kanzlei::first-letter,
          #markdownBody .drop-cap-kanzlei > p::first-letter {
              font-size: 6.6875em;
          }
      }

      /*  Special styles for special browsers.
          */
      @supports (-moz-user-focus: normal) {
          body.drop-caps-goudy #markdownBody > p:first-child::first-letter,
          body.drop-caps-goudy #abstract + p::first-letter,
          body.drop-caps-goudy #markdownBody > .epigraph:first-child + p::first-letter,
          #markdownBody .drop-cap-goudy::first-letter,
          #markdownBody .drop-cap-goudy > p::first-letter {
              margin: 0.045em 0.02em 0 0;
          }
          body.drop-caps-yinit #markdownBody > p:first-child::first-letter,
          body.drop-caps-yinit #abstract + p::first-letter,
          body.drop-caps-yinit #markdownBody > .epigraph:first-child + p::first-letter,
          #markdownBody .drop-cap-yinit::first-letter,
          #markdownBody .drop-cap-yinit > p::first-letter {
              margin: 0.065em 0.04em 0 0.01em;
          }
          body.drop-caps-de-zs #markdownBody > p:first-child::first-letter,
          body.drop-caps-de-zs #abstract + p::first-letter,
          body.drop-caps-de-zs #markdownBody > .epigraph:first-child + p::first-letter,
          #markdownBody .drop-cap-de-zs::first-letter,
          #markdownBody .drop-cap-de-zs > p::first-letter {
              margin: 0.06em 0.04em 0 0;
          }
          body.drop-caps-cheshire #markdownBody > p:first-child::first-letter,
          body.drop-caps-cheshire #abstract + p::first-letter,
          body.drop-caps-cheshire #markdownBody > .epigraph:first-child + p::first-letter,
          #markdownBody .drop-cap-cheshire::first-letter,
          #markdownBody .drop-cap-cheshire > p::first-letter {
              margin: 0.06em 0.04em 0 0.01em;
          }
          body.drop-caps-kanzlei #markdownBody > p:first-child::first-letter,
          body.drop-caps-kanzlei #abstract + p::first-letter,
          body.drop-caps-kanzlei #markdownBody > .epigraph:first-child + p::first-letter,
          #markdownBody .drop-cap-kanzlei::first-letter,
          #markdownBody .drop-cap-kanzlei > p::first-letter {
              margin: 0.05em 0.02em 0 -0.04em;
          }
      }
  }
Code Snippet 2: The css rules used to render Drop Caps at gwern.net

  1. HTML and CSS are a bit like drawing and then colouring a colouring book. One can use the HTML to define the lines and the CSS to choose where and how to colour it in. A class in HTML is basically a label that identifies parts of the page that are going to receive the same treatment (colour, border size or style, font family and size, &c). What exactly that treatment is will be decided in the CSS, which is done by writing the name of the class preceded by a . as in our example .drop-cap. White space is often important when writing in HTML and CSS, so we can use a hyphen to keep our code readable. [^ back]
  2. Is that what 65ch means — should probably check that detail. [^ back]
  3. Which is an atrocious, if much simpler, method. It is also the method used in example in Snippet 1. [^ back]
  4. And these are relatively large font files; the initials that will be rendered are decorated and have to look god at relatively large size. [^ back]
  5. Hence the margin: ‘numbers are magic’ comment. [^ back]
  6. Yeah, I know that grammatically it should be « whose », but I don’t like it — so there ! [^ back]
  7. J’ignore si le plus gros du travail a été fait par Gwern lui-même ou par Said Achmiz auquil celui-là attribu le design du site. [^ back]