Styling Gatsby Site

Styling is an integral part to static sites. While Gatsby allows us to get our sites up and running fast, it is best if we can style them efficiently and beautifully too.

Resources


This page is playable as slides!

Press p to play as slides, then j and k to page. Press s for speaker notes, and yes you may give my talk.

Recap

For a recap what we went through today:

Background

What's there about styling a Gatsby site?

  • Gatsby gives us access to content development fast
  • React changes the way we think about styling, specifically:

    • we're writing way more components than pages, creating a greater need for namespaced CSS
    • parent - child > sibling relationship
    • components need to live in different contexts, and contexts need to preserve possibilities for unknowns

The nature of the problem

Looking at the nature of this problem in a spectrum of globalness v.s. component:

Tasks

  • spacing between site's H2 tags and the paragraphs next to it: global
  • styling a header: component
  • layout that adapts to viewports: rely on global information, but exports a styling to a specific component (layout is just another component)
  • dark toggle: by itself a component, but creates styling information that affects a layer very high up on the global scale

Tools

  • vanilla CSS: global – putting down styling information on the floor
  • CSS modules: towards component, but may put down styling that affects global scope as well
  • CSS-in-JS: it's a way to write CSS, there are libraries (typographyJS) that writes global styles, but more CSS-in-JS libraries are designed for component styling, and it may go towards the very end allowing us to write styling + DOM + logic in one file

This article A Conceptual Look at Theming shares a similar mind model.

Some history

  • roots in typography and printing
  • presenting information logically and aesthetically

A lot of the things we do on the web has roots in typography and printing. If there's only one thing you want to check out, absolutely the historical Byrn's Euclid and its faithful reproduction on the web.

The root cause also stays the same: we need to present information logically and aesthetically.

A practice + demo

Finally, sharing my practice on how I think about Gatsby site:

  • typography – maintains all typesetting information with TypographyJS, handy util funciton rhythm that gives you one line of height
  • layout – keeps all page structure information, creates contexts for components, handles responsivity
  • component – very scoped, many CSS-in-JS libraries give quick access from logic -> style (sometimes don't even need to create classes)

It's not three layer, gula melaka tea, it's 2.5 layers, because layout is in-between.

Demo

Once again ran over time. Apparently I have no respect to time :(((( I'll do better next time

The goal was to live code this no style starter to have some basic styles with the mindset above and using

Finally (for real)

  • Is this the only way? No. The key is to find the solution that fits your needs.
  • Universal CSS is not a joke
  • Use a style guide
  • We're still writing CSS
  • It's your Gatsby site, come up with your own styles :)))))

Slides

Styling Gatsby Site

  • WomenWhoCode Connect 2019

I'm Wei,

  • @wgao19 everywhere
  • React developer at Shopee
  • maintains Docusaurus
  • creates many websites

Agenda

this workshop is not about

  • designs of Gatsby sites
  • which css framework is better

past talks / workshops on Gatsby

this workshop is about

  • a mind model to think about styling a Gatsby site
  • one practical method that works for me

Gatsby

And here's Gatsby's slogan:

Fast in every way that matters

Gatsby is a free and open source framework based on React that helps developers build blazing fast websites and apps

To me that every way includes one aspect – it gets us to content development really fast.

#30DaysOfCSSGirls


Gatsby brings us quick access to content development, your site is literally an npm install away

By building a Gatsby site, we are very much free from all the messiness setting a site up and running. However, the work does not go away. Things like setting up the site, code splitting, fetching and loading logic, service workers, even image optimizations, all of those work did not go away. But rather, it is well encapsulated in Gatsby's implementation including its core packages and the plugins system. Thanks to all of those encapsulation well taken care of, we can put most of our time into working on the content of our sites.


Practically every Gatsby site is a starter no? 🤯

Powered by React

React is changing the way we think about styles



We moved from page- and template-based to component-based mindset

🧩 We're writing many more components than pages

namespaced CSS

First of all, because we're making each of our components responsible for a very atomic functionality, we're writing way more components than we used to write pages. It's not on the same scale. And so there comes a strong need for namespaced CSS.

👩‍👧‍👦 Parent – child relationships > sibling relationships

We're also letting parent – child relationships dominate over sibling relationships. In our React world, siblings don't communicate very well. Much information is passed down via parent to children.

🗺 We need to think in terms of context – component

Also, since we may easily reuse components, a component must handle styles that fit different contexts, and the contexts must preserve possibilities for unknowns such as third party components.

🤔 Global = hacky?

Global things feel "hacky". This tiny night toggle, albeit very simple by itself, assumes certain specific global DOM structure to work. So it's very fragile if we have to think in terms of components.

Would like to point out again that global styling is not a problem. It only starts to feel hacky since we're now thinking in terms of components.

All in all, it can be quite deceptive that we're still writing CSS and something that feels like HTML, but we're not thinking the same way anymore.


So how 😳 to also style our Gatsby site fast?

Spectrum of styling

Today in this workshop I invite you to think about styling in a spectrum.

A Conceptual look at theming

Brent Jackson, creator of MDX Deck and many more cool things, happens to share a similar mind and has written a brief article that discusses this.


global 🐶🐱🐭🐹🐰🦊🐮🐵 component

  • tasks
  • tools

Tasks

  • styling of headers?
  • dark toggle?
  • spacing between an h2 and the paragraph next to it?
  • layout that adapts to different viewports?

global 🐶🐱🐭🐹🐰🦊🐮🐵 component

Tools

  • vanilla css?
  • css modules?
  • css-in-js?

global 🐶🐱🐭🐹🐰🦊🐮🐵 component

Layers in a Gatsby site's styling

To me, styling a Gatsby site boils down to the following three aspects:

  • Typography
  • Layout
  • Components

Typography

I think of creating websites just another way of presenting information, in addition to putting things on newspaper, books, and magazines. The origin goes very easily in to printing.


Historically, typesetting is a printing process where printers set the content of a page when printing a book.

These are movable types. Each letters are called a "type" – that's where the word typography came from. And when you print a book, you pick the types you need and set them in words, add spaces, then into sentences, paragraphs, until you have a page. Then you brush some ink and press your paper against this thing.


When you type set a book, which types you pick is only part of the problem. You also need to decide the horizontal and vertical spacing, maximum widths, and their relations to each other.

Typography is the subject about this whole process.


And there is a faithful reproduction of the original book on the web:

Likewise, typesetting is in essence a transported concept. We're doing the same thing – picking a font, deciding the vertical and horizontal spacing, and their relations with each other – to help present our information well.

Web typography

font faces + sizes + scales

Once again let's look at one example of typography.

... I'd like to think of typography as font faces + sizes + scales. Some would add vertical spacing...


... All in all, typography is in the fundation section in almost all design systems. There's one more reason why we both talk about and work on typography first – the font sizes we set will we set the HTML's root font-size that will be used as the base font size for rem values.

global 🐶🐱🐭...

Layout


Layout, once again, has a root in printing.


Many books or magazines follow a columnar layout.


I think the root cause stays the same – the need to present information both logically and aesthetically.


in our terms...


On the other hand, layout is also just another component

Gatsby after v2 also no longer gives Layout component the magical auto wrapping behavior.


...🐭🐹🐰...

Components

It's a CS thing


...🦊🐮🐵 component

Components mostly stay towards the right end of our spectrum. Some components can be slightly towards the center, such as the <Layout /> components, or page components.

Ready to get hands dirty? 🙌🏻


$ gatsby new my-blog https://github.com/wgao19/gatsby-starter-no-style

Typography

  • Typography
  • Layout
  • Components

TypographyJS

We are going to use TypographyJS. This is a CSS-in-JS library that focuses on dealing with the site's typography. And it is created by Kyle Matthews, also the creator of Gatsby.

Installation

To use TypographyJS in Gatsby, first we need to add the library and its corresponding Gatsby plugin to our package:

$ yarn add gatsby-plugin-typography react-typography typography
# or
$ npm install --save gatsby-plugin-typography react-typography typography

Then, we'll need to specify in gatsby-config.js that we are using this library and the plugin, and we'll specify a file in which we'll write the typography related CSS in a JS object.

// gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-plugin-typography`,
      options: {
        pathToConfigModule: `src/utils/typography`
      }
    }
  ]
};

Basic usage

We'll also need to create the typography.js file. Then, we'll need to restart the dev server. Nothing will change yet. Now let's work on the typography.js file.

// src/utils/typography.js
import T from 'typography';

export default = new T({
  baseFontSize: '18px',
  baseLineHeight: 1.7
});

Google fonts

Typography provides a quick API to load google fonts. Let's pick a Google font.

// src/utils/typogrpahy.js
import T from 'typography';

export default new T({
  // ...
  googleFonts: [
    {
      name: 'Nunito',
      styles: ['800']
    },
    {
      name: 'IBM Plex Sans',
      styles: ['400', '400i']
    }
  ],
  headerFontFamily: ['Nunito', 'sans-serif'],
  bodyFontFamily: ['IBM Plex Sans', 'monospace'],
});

"Typesetting"

  • overrideStyles
  • vertical rhythm

Next, we want to specify some more detailed adjustments to the typography, we're "typesetting" the page!!

The TypographyJS API has a special field called overrideStyles which is supposed to be a function. If you initialize the typography object with this function provided, it will be called with a few util functions for you to use, and the objects you return in this function will be injected to your site.

The util function we are going to use today is rhythm.

rhythm stands for vertical rhythm. This is another library created (transported) by Kyle. You can read more about it in its separate repo.

What it does intuitively is that gives you 1 line of height. But why can't you just use, say, pixel numbers? This is because, the font sizes are different in headings and body texts. And sometimes you may adjust the line height as well, resulting yet another different final line height. So what rhythm gives you is the actual one line of height in the text's context. And we can use the number at margins, paddings, etc.

// src/utils/typography.js
import T from 'typography';

export default new T({
  // ...
  overrideStyles: ({ rhythm }) => {
    return {
      h1: {
        paddingTop: rhythm(1.2),
        paddingBottom: rhythm(1.2),
        lineHeight: 1.8,
        fontStyle: 'italic'
      },
      h2: {
        paddingTop: rhythm(1),
        paddingBottom: rhythm(0.8)
      },
    };
  }
});

The return object keys are simply CSS selectors, and you can put media queries here too.

// src/utils/typography.js
import T from 'typography';

const typography = new T({
  // ...
  overrideStyles: ({ rhythm }) => {
    return {
      // ...
      a: {
        color: '#222',
        textDecoration: 'none',
        borderBottom: '3px solid gold',
        paddingBottom: '2px',
        transition: 'all .2s ease'
      },
      'a:hover, a:active, a:focus': {
        borderBottom: '1.5px solid gold'
      }
    };
  }
});

Wrapping up

  • typography.js theme picker
  • vertical rhythm
  • object keys are css selectors
  • all typography related information will be kept here

The TypographyJS library contains a list of styles where you may use directly to your Gatsby site. You can even play around with it, tweak the numbers of the prepackaged styles to fit your own needs. Demo and full API docs at https://kyleamathews.github.io/typography.js/.

Before we move on to the next section, I'd like to point out that with TypographyJS you can actually write media queries exactly like how we put the relatively more complex selectors in the object key. And as a matter of fact, TypographyJS has a package that includes all the common media query strings. But we're not going to use that part of the library because we'll move on to consider our site's layout separately.

We keep all typography related styling information here. Later on we will work on layout, and then components. But we will see that they won't interfere with what we do here.

Layout

  • Typography
  • Layout
  • Components

emotion

My own words: composable css + modules in one step.

Base layout

// src/components/Layout/index.jsx
import * as React from 'react';
import { Link } from 'gatsby';

export default ({ children, currentPage, className }) => (
  <div>
    <nav>
      {[
        {
          path: '/',
          title: 'Home'
        },
        {
          path: '/blog',
          title: 'Blog'
        }
      ].map(({ path, title }) => (
        <Link
          to={path}
          key={path}
          className={currentPage === path ? 'active' : 'normal'}
        >
          {title}
        </Link>
      ))}
    </nav>
    <main className={className}>{children}</main>
    <footer>
      Built with{' '}
      <span role="img" aria-label="heart">
        💛
      </span>
    </footer>
  </div>
);

-

// layout styles
<div
  className={css`
    background: #efefef;
  `}
>
  {/**
    *layout component
    */}
</div>

-

// nav styles
<nav className={css`
  height: var(--navbar-height, 96px);
  line-height: var(--navbar-height, 96px);
  background: white;
  padding: 0 var(--spacing, 2rem);
`} />

-

// Put variables to typography.js
// src/utils/typography.js
import T from 'typography';

export default new T({
  // ...
  overrideStyles: ({ rhythm }) => {
    return {
      //...
      ':root': {
        '--spacing': '2rem',
        '--round-corner': '2px',
        '--footer-height': '72px',
        '--navbar-height': '96px'
      },
    };
  }
});

-

// footer styles
<footer
  className={css`
    height: var(--footer-height);
    line-height: var(--footer-height);
    background: #1e1e1e;
    color: #777;
    text-align: center;
  `} />

-

// main chunk styles
<main
  className={cx(
    css`
      min-height: calc(100vh - var(--footer-height) - var(--navbar-height));
      padding: 0 var(--spacing, 2rem);
    `,
    className
  )}
>

Because we use css variables such as --spacing, personally prefer to add the spacing to each individual blocks instead of giving the spacing to the outer playout.

Adapting to viewports:

// layout component
<div
  className={css`
    background: #efefef;
    @media (max-width: 979px) {
      --spacing: 1rem;
    }
  `}
>

Page (very in-between layout and component)

Post listing *css variables will work just fine (since its global mah)**

<section
  className={css`
    margin: var(--spacing) auto;
    border-radius: 2px;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-column-gap: calc(100% / 15);
    grid-auto-flow: dense;

    @media (max-width: 979px) {
      display: block;
    }
  `}
/>

Post briefing you can nest class name and use it in its nesting component

<article
  className={css`
    &:first-child {
      grid-column: 1 / -1;
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      grid-gap: 100px calc(100% / 15);
      grid-auto-flow: dense;
      margin-bottom: calc(2 * var(--spacing));
      .image {
        grid-column: span 2;
      }
    }
  `}
/>

Post briefing image you can combine class names

<Image
  fluid={fluid}
  className={cx(
    'image',
    css`
      background: white;
      border-radius: var(--round-corner);
      box-shadow: #efefef 2px 2px 1px 0;
    `
  )}
/>

Component

apply styles without having to go through separating them by class names – it's in build step

// src/components/Navbar.js
import * as React from 'react';
import { css, cx } from 'emotion';
// ...

export default ({ currentPage }) => {
  return (
    <nav
      className={css`
        height: var(--navbar-height);
        padding: 0 var(--spacing);
        background: white;
        display: flex;
        align-items: center;
      `}
    >
      {items.map(({ path, title }) => (
        <Link
          to={path}
          key={path}
          className={css`
            border-radius: var(--round-corner);
            margin-right: calc(var(--spacing) / 4);
            border-bottom: 3px solid
              ${path === currentPage ? 'gold' : 'transparent'};
            &:hover {
              border-bottom: 3px solid lightgoldenrodyellow;
            }
          `}
        >
          {title}
        </Link>
      ))}
    </nav>
  );
};

Had fun?

🤞 this is not the only way

Universal CSS 😅


is there a real world example using this?

yes there is lol

Theme UI

map theme info to styles


the key is to fit your very needs

for example, emotion may no longer be preferrable to myself if my components are getting bigger, because in that case I'll prefer to have a cleaner file for rendering logic, and styles in their own files.

☝️ Use a style guide

mainly to save the time wasted in constantly tweaking styles

✌️ We're still writing CSS

And I think it implies a greater challenge on our understanding of CSS because we now need to incorporate where and how we write CSS, and how it is built, together with CSS's intrinsic logic.

...before we go home


It's your Gatsby sites, come up with your own styles :)

http://bit.ly/wwc-styling-gatsby