@studio_hungry Twitter@molebox GitHubRichard Haines LinkedIn

CSS grid with theme-ui

Author: Richard Haines

Posted: 25 Feb 2020

Before i knew how to do this i was using media queries....

When i started using theme-ui i was already an avid emotion user. I would splatter my files with styled components without really thinking about if they could (or should) be shared. It was a well drilled operation that i felt was giving me the results i wanted.

For example, i would generally use css grid for my sites base layout, this would be wrapped around the whole app using gatsby-plugin-layout. One such example:

1const Container = styled.div`
2 display: grid;
3 grid-template-columns: 1fr;
4 grid-template-areas:
5 "nav"
6 "main"
7 "footer";
8 height: 100%;
9 width: fit-content;
10
11 /* 48em = 768px */
12 @media (min-width: 48em) {
13 display: grid;
14 grid-template-columns: repeat(6, 1fr);
15 grid-template-rows: 0.5fr 4fr 0.5fr;
16 grid-template-areas:
17 "nav nav nav nav nav nav"
18 "main main main main main main"
19 "footer footer footer footer footer footer";
20 height: 100vh;
21 width: auto;
22 }
23`;
24
25const Layout = ({ children }) => {
26 return (
27 <>
28 <Global
29 styles={css`
30 * {
31 margin: 0;
32 padding: 0;
33 box-sizing: border-box;
34 }
35 body {
36 scroll-behavior: smooth;
37 overflow-y: scroll;
38 -webkit-overflow-scrolling: touch;
39 width: 100%;
40 overflow-x: hidden;
41 }
42 `}
43 />
44 <Container>
45 <Header>
46 <Nav />
47 </Header>
48 {children}
49 <Footer />
50 </Container>
51 </>
52 );
53};
54
55export default Layout;

This worked perfectly fine, but i had learned through discussions with other devs, and through seeing their work that mixing both emotion and theme-ui not only wasnt really neccesary but also a bit clunky to say the least. Thats without going into how theme-ui uses emotion under the hood (what was i thinking?)

When i decided to do a complete redesign of my website i wanted to try and use theme-ui only to style my site, and more specifically the sx prop. The problem i faced was not how to add the grid systme via the sx prop, but how to make it responsive, that is, how to do what i was doing with media queries but via the sx prop.

The solution was surprisingly simple. With css variables on the sx prop you can use an array format to give different values depending on the browser width. With this knowledge in hand i converted the above code to the following:

1const Layout = ({ children }) => {
2 return (
3 <>
4 <Global
5 styles={css`
6 * {
7 margin: 0;
8 padding: 0;
9 box-sizing: border-box;
10 }
11 body {
12 scroll-behavior: smooth;
13 overflow-y: scroll;
14 -webkit-overflow-scrolling: touch;
15 width: 100%;
16 overflow-x: hidden;
17 }
18 `}
19 />
20 <div
21 sx={{
22 display: "grid",
23 gridTemplateRows: "auto",
24 gridTemplateColumns: [
25 "repeat(4, 1fr)",
26 "repeat(6, 1fr)",
27 "repeat(8, 1fr)"
28 ],
29 gridTemplateAreas: [
30 `
31 'nav nav nav nav'
32 'main main main main'
33 'footer footer footer footer'
34 `,
35 `
36 'nav nav nav nav nav nav'
37 'main main main main main main'
38 'footer footer footer footer footer footer'
39 `,
40 `
41 '. nav nav nav nav nav nav .'
42 '. main main main main main main .'
43 '. footer footer footer footer footer footer .'
44 `
45 ],
46 padding: "0 1em"
47 }}
48 >
49 <Header>
50 <Nav />
51 </Header>
52 {children}
53 <Footer />
54 </div>
55 </>
56 );
57};
58
59export default Layout;

This was a great improvement and when looking at it with the understanding that the array notation works like so ['mobile', 'tablet', 'desktop'] it becomes really easy to read and understand what is going on. Having all those long strings in there was kinda messy though so i moved them out into another file and replaced them:

1<div
2 sx={{
3 display: "grid",
4 gridTemplateRows: "auto",
5 gridTemplateColumns: ["repeat(4, 1fr)", "repeat(6, 1fr)", "repeat(8, 1fr)"],
6 gridTemplateAreas: [
7 PhoneTemplateAreas,
8 TabletTemplateAreas,
9 DesktopTemplateAreas
10 ],
11 padding: "0 1em"
12 }}
13>
14 <Header>
15 <Nav />
16 </Header>
17 {children}
18 <Footer />
19</div>

Much better! 😎

Edit this post on GitHub.Next: How to make a gatsby ecommerce theme. Part 1