Thoughts on Linaria CSS-in-JS library
A look at Linaria, a CSS-in-JS library with zero runtime.
Linaria is a CSS-in-JS library with zero runtime. At the end of the day it generates static CSS from your code.
The Good
Linaria is a good option for building static sites. Some of the places where it shines are:
Performance
Since Linaria has zero runtime, it means that nothing will run on the main thread and your UI will feel snappier. Also, it won't be included in your JavaScript bundle. Usually less JavaScript equals faster webpage loads and less time required by the browser to process your code (better TTI).
CSS Variables
Don't let the words "static" and "zero runtime" fool you. Linaria comes with a very powerful system to dynamically style components with the help of CSS Variables or CSS Custom Properties. So you could easily create a Button
component which expects a color
prop which could be dynamically updated at runtime.
let Button = styled.button`
color: ${props => props.color};
`
<Button color={isDisabled ? "gray" : "blue"} />
The Bad
As the complexity of an app grows, we start seeing few of Linaria's drawbacks that require some working around.
Responsive Design
With Linaria you are limited to vanilla CSS and JS techniques when it comes to responsive design. Coming from other CSS-in-JS libraries you get used to some niceties they provide for responsive styling.
For example stitches
provides an object syntax for specifying variants at different breakpoints and so does theme-ui
with their sx
prop and array syntax. styled-components
and emotion
support utilities such as facepaint and styled-system that allow you to pass props as an array such as:
// responsive font-size
<Text fontSize={[ 3, 4, 5 ]} />
Bloated HTML Markup
This is a big drawback especially if you server render your app and if you end up using lots of dynamic props based styles as demonstrated in the CSS Variables example.
CSS Variables defined as inline styles bloating up HTML
The Ugly
CSS Variables and Inheritance
CSS pop quiz: What is the color of span? Or shall I say who is the rightful heir of span's color property?
<style>
:root {
--color: blue;
}
p {
color: red;
}
span {
--color: inherit;
color: var(--color);
}
</style>
<p>
<span>Lorem ipsum dolor sit amet<span>
</p>
One might think that the keyword inherit
would be applied to the color
property thus resulting in red
. But in reality CSS variables have their own inheritance, thus yielding color blue
inherited from the CSS property --color
itself.
This translates to a frustrating scenario in Linaria when you are trying to apply the keyword inherit
to a dynamic property. Since it internally uses CSS Variables the outcome ends up being not what you expected.
const Text = styled.p`
color: ${(props) => props.color || "inherit"};
`
<Text color="inherit">Hello</Text>
Play with it yourself below.
- Vanilla CSS: https://codepen.io/afzalsayed96/pen/wvzKqoM
- Linaria: https://codesandbox.io/s/bitter-wave-1riyd?file=/src/App.js
Nesting Styled Components
When nesting the same styled components, children end up overriding properties provided by parent selectors due to the reuse of same css variable names.
Consider the following example from an issue here:
const Column = styled.div`
& > * + * {
margin-top: ${({ spacing }) => spacing || '0'};
}
`
<Column spacing='30px'>
<Column></Column>
<Column></Column>
</Column>
The second nested Column
div should have a margin-top
property of 30px
. But what happens is it get's overriden by the default 0
because CSS variables follow the cascade (duh!)
Play with it yourself on codesandbox