Like anything React, there are a bunch of options for styling in Gatsby: inine styling, global SCSS imports, CSS Modules, CSS-in-JS components, and then some. Here’s my exploration into some.
1NOTES (2021-08-22)2---3When I first wrote this, I wanted to keep as much of existing SCSS/CSS4as possible since I was converting an existing Jekyll repo into Gatsby.5While the post content is still relevant, I’ve since rewritten significant6portions of this site and kept only to `css-in-js` approaches.
Global (S)CSS and Variables
As I’m keeping most of pre-existing UI styles from the previous site written SCSS
, I wanted to reuse as much of the existing code as possible.
So, in my gatsby-browser.js
I imported the global base styles from base.scss
, which contains bare minimum of global styling and imports _variables.scss
for certain values.
You’ll notice the duplicated hex values in SCSS variables and CSS custom properties. I almost wanted to ditch SCSS variables and keep everything only to CSS custom properties, and there was just one reason why: Color Functions. SCSS offers built-in color functions such as lighten()
, complement()
. While they can easily be accomplished by packages like this one, I didn’t want an extra dependency just for a simple task like this.
jsgatsby-browser.js1import "./src/styles/base.scss";23// ... and other stuff
scssbase.scss1@import url("//path.to/webfonts");2@import "./variables";34html,5body {6 font-family: Raleway, Helvetica, Arial, sans-serif;7 font-size: 10px;8 margin: 0;9}1011body {12 padding-top: 4.5rem;13}
scss_variables.scss1// Colors2$cyan: #00a2d9;3$berry: #b7295a;4$green: #7ab800;5$yellow: #f2af00;6$accentColor: $green;7$bgColor: #fff;89:root {10 --cyan: #00a2d9;11 --berry: #b7295a;12 --green: #7ab800;13 --yellow: #f2af00;14}1516// ... and other stuff
(S)CSS Modules
Then importing a clean scss
into a component felt natural. I like how style definitions are separated from the markup, so I could organize code neatly with no concerns for accidental overriding .
I started the site Header component with this approach.
scssHeader.module.scss1header {2 background: var(--berry);3 position: fixed;4 // ... stuff56 .BigB {7 // ... stuff8 }910 ul.bigNav {11 // ... stuff12 a {13 color: lighten($berry, 25%);14 // ... stuff15 &:hover {16 transform: translateY(-0.25rem);17 color: #fff;18 }19 &.active {20 color: #fff;21 }22 }23 }24}
jsxHeader.JS1import styles from "./Header.module.scss";23const Header = () => (4 <>5 <header className={styles.Header}>6 <div className={styles.BigB}>7 <Link to="/">B</Link>8 </div>9 <ul className={styles.bigNav}>10 <li>11 <Link activeClassName={styles.active} to="/">12 About13 </Link>14 </li>15 <li>16 <Link activeClassName={styles.active} to="/portfolio">17 Portfolio18 </Link>19 </li>20 </ul>21 </header>22 </>23);
Styled-Components
Everything else is a styled-component
, which provides most of Sass conventions and enables far more dynamic styling via JavaScript. On the home page, IntroBox.js
component that takes a few props and styles itself accordingly.
jsxIntroBox.js1import React from "react";2import styled from "styled-components";3// ... and other import statements45const IntroBox = (props) => {6 const { iconName, width, back, color, order, mobileOrder, label } = props;7 const IntroBoxDiv = styled.div`8 flex-basis: ${width === "1" ? "25%" : "50%"};9 &:hover .flipper {10 transform: ${width === "1" ? "rotateY(180deg)" : "rotateX(180deg)"};11 }12 span {13 ${flexUnit(1.3, 13, 26, "vw", "font-size")}14 color: ${color || "#ffffff"};15 }16 // ... and other styling stuff17 `;18 return (19 <IntroBoxDiv>20 <div className="flipper">21 <div className="front">22 <Icon iconName={iconName} />23 <span>{label}</span>24 </div>25 <div className="back">{props.children}</div>26 </div>27 </IntroBoxDiv>28 );29};
jsxindex.js1import React, { useState } from "react";2import styled from "styled-components";3import Layout from "../components/layout";4import IntroBox from "../components/IntroBox/IntroBox";5// ... and other import statements67const IntroBoxContainer = styled.section`8 background: #282828;9 display: flex;10 flex-wrap: wrap;11`;1213const IndexPage = () => {14 // ... other stuff...1516 return (17 <Layout>18 <IntroBoxContainer>19 <IntroBox20 iconName="IntroShoes"21 width="2"22 order="0"23 back="#475F7D"24 mobileOrder="5"25 label="Industry Experience"26 >27 .... content ....28 </IntroBox>29 <IntroBox30 iconName="IntroEducation"31 width="1"32 order="1"33 back="#334d5c"34 label="Education"35 >36 .... content ....37 </IntroBox>38 </IntroBoxContainer>39 </Layout>40 );41};
While I do love the convenience of having style declarations and markup in the same file which eliminates the need for constantly jumping between files when debugging, I found myself having to constantly jump up and down between sections within a component file as the styling blocks become larger.
Why multiple approaches — what next
I’m still figuring out what works for me and how best to approach styling. Certainly I won’t need global SCSS
import and perhaps won’t need SCSS modules either, as there are other JS
-ways to solve the problem. Just for the sake of getting more procifient, I’m likely to proceed with styled-components only for the most part, and maybe even attempt to get rid of other external (S)CSS
files in general, but this has been a practical exercise to build something in different ways in any case.
if you liked it