CSS was originally created to style entire web pages. But, over time the complexity of websites has grown, which makes it very difficult to manage designs. CSS doesn’t have any concept of modules through which we could divide the code into separate chunks.
Even JavaScript doesn’t have the modules initially. But, with the passing of time, web development has significantly evolved. We now use component-based libraries like React and Vue.js to design the frontend of web apps. It highlighted the need for a similar solution for CSS. But, the standard CSS doesn’t provide any programming concepts. So, we use a solution called CSS-in-JS.
There are some popular CSS-in-JS libraries like emotion and styled-components. But, their main issue is that they take around 10KB to 20KB of space. As you probably know that heavy files make a significant impact on the page load time and therefore on the ranking of a website in search engines. So, Cristian Bote created a lightweight alternative, goober. It takes less than 1KB of space which makes it a preferred choice for high-performance sites.
Features of goober
- The major feature that attracts developers to goober is its size. Its lightweight footprint of less than 1KB makes it stand out from other CSS-in-JS solutions
- It is designed to work with vanilla JavaScript as well as its frontend libraries/frameworks like React, Vue.js, Angular, Svelte, etc.
- Support for server-side rendering
- Growing community size with around 24 active contributors
- Different ways to customize CSS properties. For example, by providing props to CSS tagged templates or by using CSS with JSON. Here, an important thing to note is that using JSON/Object to write CSS code significantly reduces the bundle size
- Ability to specify a target node to append the style tag
- It allows us to separate code for the entire document and specific sections
- Reuse code with ease
- goober has a method called
keyframes
that enables us to reuse animations across components - It has a babel plugin to transform codes like
styled.tag
to a goober’s understandable format, something like styled(“tag”) - Integrate goober with Gatsby using an official plugin
- Ability to parse CSS code
- goober has nested rules with pseudo selectors. It even has nested styled-components
- It enables us to extend styles. For example, we can either overwrite with another set of CSS rules or use “as” prop
- Support for media queries (@media) and keyframes (@keyframes)
- An interesting feature of goober is that it comes with smart(lazy) client-side hydration
- Helpful autoprefixer that makes sure the CSS code will work on all web browsers. This functionality is also known as vendor prefixing. The team behind goober has created a separate package to handle auto prefixing
Benchmarks
Since its inception, goober has seen significant adaptation from the developer community. It encouraged the contributors behind goober to make a performance comparison between its popular competitors.
So, they selected goober, emotion, and styled-components. Then, executed 85 samples with each library to find out how much time on average it takes to complete the task.
The benchmark results were quite phenomenal:
- styled-components processed 21,469 ops/sec
- goober processed 39,348 ops/sec
- emotion processed 46,504 ops/sec
Clearly, the winner here is the emotion library. But, the point to be noted is that emotion and styled-components have well-established APIs and both have 200+ contributors. Whereas, goober is a new contender among CSS-in-JS libraries. Still, it beats the styled-components in speed and gives a close run compared to the emotion library.
Comparison between goober, emotion, and styled-components
Before writing any code for goober, let’s compare it with its popular competitors (i.e. emotion and styled-components). It will answer your question, “why should I use goober?”
Features | goober | emotion | styled-components |
---|---|---|---|
Tagged template literals | Yes | Yes | Yes |
Composition | Yes | Yes | Yes |
Global styles | Yes | Yes | Yes |
Theming support | Yes | Yes | Yes |
Media queries | Yes | Yes | Yes |
Nested selectors | Yes | Yes | Yes |
Attaching props | Yes | Yes | Yes |
Server-side rendering | Yes | Yes | Yes |
Average number of operations per second | 39,348 | 46,504 | 21,469 |
Library size | Less than 1kB | ~11kB | ~12kB |
Number of contributors | 24 | 211 | 283 |
In the above table, you can see that all three CSS-in-JS libraries have common features. But, the way they are implemented decides the performance of the library. emotion is faster than both but the small footprint of goober could give an advantage to its users.
Getting started with goober
Let’s quickly set up a React app using Facebook’s create-react-app project. To do so, follow the below steps.
At first, create the project inside the “my-app” folder:
npx create-react-app my-app
And then move inside the folder:
cd my-app
Now, we need to install the goober library:
npm install goober
At this point, we are ready to write the code to integrate goober with React. We will start by creating a simple web page that contains one heading and three paragraphs.
The heading style is very straightforward as we directly target the <h1>
tag. Whereas, for paragraphs, we’ll define all the common code once. And then, extend it separately for each paragraph. Paste the below code inside src/index.js:
import React from "react"; import ReactDOM from "react-dom"; import { styled, setup } from "goober"; setup(React.createElement); const Title = styled("h1")` font-weight: bold; color: #00f; `; const P = styled("p")` font-weight: bold; `; const P1 = styled(P)` color: #f00; font-style: italic; font-weight: normal; `; const P2 = styled(P)` color: pink; text-decoration: underline; `; const P3 = styled(P)` color: #bb0276; `; function App() { return ( <div className="App"> <Title>Hello World</Title> <P1>This is paragraph # 1 that is designed with goober.</P1> <P2>This is paragraph # 2 that is designed with goober.</P2> <P3>This is paragraph # 3 that is designed with goober.</P3> </div> ); } const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement);
You may now test this code by executing the below command in the console window:
npm start
It will look something like this:
Explanation of above code
First of all, we imported the required packages React
, ReactDOM
, and goober
to make everything work correctly. We then have to call the setup()
method once in the beginning. It is important to note that setup()
must be called before using the styled()
function.
After that, we will create different CSS rules for headings and paragraphs using tagged template literals.
Customize the style with props
There are different ways to customize the style in goober. One of them is to use props. Basically, we set the desired values using props and access them inside the template literals of the desired styled()
function.
For example:
const Title = styled('h1')` color: ${props => props.textColor}; font-size: 3rem; `; function App() { return ( <div className="App"> <Title textColor="red">Hello World</Title> </div> ); }
Explanation of above code
Here, you can see that we added props called textColor
and assign it a value “red”. We then used the props inside the template literals of styled() function to assign the value to the “color” property of CSS.
Global styles
goober is packed with a function called glob
. It is used to specify global styles that will be applied to the entire document. It is pretty useful in web design there is a lot of code that is common between different elements.
For example, the glob function is very suitable to include any external fonts that will be used on the whole web page. Most people even use it to write the “CSS Reset” rules. To get started, we first need to import glob
from goober. Like this:
glob` body { margin: 0; } `;
Missing styled.tag
If you ever worked with styled-components library then you might be familiar with its styled.tag
functionality. It is very popular among developers who work with CSS-in-JS solutions.
goober doesn’t support this format by default. But, the contributors and the team have developed a babel plugin. This plugin is used to convert all styled.tag references into a format that is understandable by goober.
Conclusion
The main idea behind the development of goober was to introduce a lightweight alternative for popular CSS-in-JS libraries like emotion and styled-components. So, you should use it in scenarios:
- When you want your web pages to load faster
- Your website receives heavy traffic (i.e. millions of users every month). Such as a news website, blog, SaaS application, or a social media network, etc. It is because goober has less than 1 kB size so it will not eat up much bandwidth as compared to its competitors
I didn’t find any significant disadvantages of goober because the team has really done well to offer almost all the features that its competitors have. And all using a very small codebase.
Get set up with LogRocket's modern error tracking in minutes:
- Visit https://logrocket.com/signup/ to get an app ID
- Install LogRocket via npm or script tag.
LogRocket.init()
must be called client-side, not server-side - (Optional) Install plugins for deeper integrations with your stack:
- Redux middleware
- NgRx middleware
- Vuex plugin
$ npm i --save logrocket
// Code:
import LogRocket from 'logrocket';
LogRocket.init('app/id');
Add to your HTML:
<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>
I think the main issue with CSS-in-JS solutions so far isn’t the bundle size, but rather…. That they’re CSS in JS. In a few years we’ll look back at this trend and shudder!
“they’re CSS in JS” <- What that is an issue?
Awesome article, thanks! Just an FYI, the benchmarks for Goober have been updated. It is now performing ~2x ops/sec than emotion.