genehenson.com
← Back to blog

Build a Blog: Part 2 - The Styles

©genehenson8 Feb 20213 minute read

If you caught my last post you know that we decided on GatsbyJS as our framework. After getting a new project setup using their CLI, I had some Hello World code working. Before going much farther, I really wanted to step back and figure out how to handle our CSS/Styles.

Gatsby has a bunch of starter guides on styling in their documentation. There's a lot to choose from, so, as always, I tested a few to see what I liked.

Tailwind CSS

If you don't know about Tailwind, it's a really cool utility-first CSS framework. Once it's installed, you just apply utility classes to your HTML elements to make them look and behave how you want. In principle, it's a great approach, but I've never really liked using it. Nevertheless, I gave it another shot with this project.

In the end, I found I still had the same problems that I've always had with it.

First you end up with a ton of classes for each element because you need to apply a class for every behavior. This of coarse leads to ugly, unmanageable code that just isn't fun to write. Now, you can get around by "extracting components" (essentially creating base components using various utility classes.) While this helps, it always feels like extra work to me.

Second, while the utility options in Tailwind are numerous, I always run into situations where I can't style something based on the utility classes. For instance, the Grid utilities only allow you to create columns/rows with minmax(0, 1fr). That works a lot of the time, but I usually end up wanting to size things a bit more precisely. You can get around this by adding your own utilities to Tailwind, but, again, it just feels like more work.

To be fair, I think if I worked solely with Tailwind 100% of the time, I'd eventually get better with it and it wouldn't feel so clunky, but it just doesn't work for me right now.

Styled Components

In principle, Styled Components and Emotion are very similar. I decided to try Styled Component really just because I hear more people talking about it, but it was kind of a role of the dice.

Styled Components let you create CSS-in-JS which scopes your styles at the component level. I quite like this approach as it seems to fit nicely with React. It also allows me to pass props to the components which makes it easy to create reusable components that fit multiple jobs. For instance, I have a "Container" component that accepts arguments for things like max-width and alignment allowing me to use it wherever I need a container.

You can also extend components to create a scoped version of a generic component. So I could create a version of the Container component with a red background and it stays scoped.

Gatsby has an official plugin for Styled Components that make setup a breeze. I decided I wanted to stick with Styled Components for all of my component level styles.

CSS

I still wanted to have some base css that would apply to the entire site. I usually use normalize.css and I generally like to work with css custom properties to hold all my colors, font sizes, etc. I know that I will also want to implement a dark mode so I want to be able to be able to add theming easily.

While this can be done in Styled Components using global styles, I decided to use regular css for this since I'm used it it and it makes it easier to move away from Styled Components, should the need arise. My usual approach is to separate concerns by creating several css files and importing them into a master file.

Here's what I normally create:

normalize.css

This is just a regular normalize css file. I import this first to get everything to standard level for cross-browser behavior.

variables.css

This holds all my custom properties for colors and font sizes.

/* src/styles/variables.css */

/* Colors */
:root {
  --white: #fff;
  --black: #000;
  --light: #f7f7f7;
  --dark: #252627;
  --dark-grey: #414141;
  --grey: #333;
  --light-grey: #e4e6eb;
  --pink: #e865a7;
  --yellow: #ffff00;
  --blue: #33d0ff;
  --green: #d8ffc1;
  --orange: #d80000;
}

/* Sizes */
:root {
  --page-width: 1170px;
  --text-width: 600px;
  --font-size-4xl: 3.052rem;
  --font-size-3xl: 2.441rem;
  --font-size-2xl: 1.953rem;
  --font-size-xl: 1.563rem;
  --font-size-l: 1.25rem;
  --font-size-m: 1rem;
  --font-size-s: 0.8rem;
  --font-size-xs: 0.64rem;
  --font-size-2xs: 0.512rem;
}

theming.css

These use the variables to create specific themes that we can apply through the project.

/* src/styles/theming.css */

:root {
  --primary: var(--pink);
  --secondary: var(--blue);
  --text-color: var(--white);
}

typography.css

As the name implies, this sets our typography rules.

/* src/styles/typography.css */

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
    Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
  font-weight: 400;
  line-height: 1.5;
}

p {
  margin-bottom: 1.5rem;
  line-height: 1.625;
}

h1,
h2,
h3,
h4,
h5,
h6 {
  margin: 0;
  margin-top: 1rem;
  margin-bottom: 1rem;
  line-height: 1.5;
  font-weight: 400;
}

h1,
.h1 {
  font-size: var(--font-size-4xl);
}
h2,
.h2 {
  font-size: var(--font-size-3xl);
}
h3,
.h3 {
  font-size: var(--font-size-2xl);
}
h4,
.h4 {
  font-size: var(--font-size-xl);
}
h5,
.h5 {
  font-size: var(--font-size-l);
  font-weight: 600;
}
h6,
.h6 {
  font-size: var(--font-size-m);
  font-weight: 600;
}

.post > h1 {
  font-size: var(--font-size-3xl);
}
.post > h2 {
  font-size: var(--font-size-xl);
  margin-top: 3rem;
}
.post > h3 {
  font-size: var(--font-size-l);
  margin-top: 1.5rem;
}
.post > h4 {
  font-size: var(--font-size-m);
  margin-top: 1rem;
}
.post > p {
  margin: 0;
  margin-bottom: 1.25rem;
  font-size: 1.15rem;
}

global.css

This sets any global rules that we need.

/* src/styles/global.css */

nothing here yet

master.css

Here I just pull in all of the previous files (order matters) and import this into my Gatsby layout file.

/* src/styles/master.css */

@import './normalize.css';
@import './variables.css';
@import './mixins.css';
@import './typography.css';
@import './global.css';

Bringing it all together

Now whenever I create individual components, I can use css custom properties to easily change colors sizes, etc. For instance, this is my basic Container.tsx component.

// src/components/styled/Container.tsx

import styled from 'styled-components';

enum WidthValues {
  'fluid',
  'page',
  'text',
}

enum AlignValues {
  'left',
  'center',
  'right',
}

interface Props {
  width?: keyof typeof WidthValues;
  align?: keyof typeof AlignValues;
}

const makeWidth = (width: keyof typeof WidthValues) => {
  if (width === 'text') {
    return 'var(--text-width)';
  }
  if (width === 'page') {
    return 'var(--page-width)';
  }
  return '100%';
};

const makeAlign = (align: keyof typeof AlignValues) => {
  if (align === 'center') {
    return '0 auto';
  }
  if (align === 'right') {
    return '0 auto';
  }
  return '';
};

export const Container = styled.div`
  padding: 0 1rem;
  max-width: ${({ width }: Props) => makeWidth(width)};
  margin: ${({ align }: Props) => makeAlign(align)};
`;

Here is how I would use this container:

// src/pages/index.tsx

<Container width='text' align='center'>
  ...
</Container>

Conclusion

Because I'm using Typescript, everything is typed and I get nice autocomplete within VSCode. We'll see how it all works out, but I'm pretty happy with the approach right now.

Share this

You think I got something wrong or missed the point entirely? You're probably right. Hit me up on Twitter and let me know.