DEV Community

Cover image for You Don't Need CSS-in-JS: Why I Use Stylesheets
Colby Fayock
Colby Fayock

Posted on • Edited on • Originally published at colbyfayock.com

You Don't Need CSS-in-JS: Why I Use Stylesheets

CSS-in-JS is all the rage. But is it really the best option?

Solving problems you don't need to solve

Don't get me wrong, CSS-in-JS is a great solution, but it's for a problem most people don't have. Maintaining your components in a very siloed approach absolutely helps things like:

  • Unintentional side effects of cascading styles
  • Helping teams organize their rules
  • Avoiding stepping on each other's toes while developing

But those really only become problems with large teams with many developers and a vast library of components.

So what do you want me to use?

To start from a slightly higher point of view, you can get in the habit of a few basic ideas:

  • Set and follow some basic rules for writing
  • Use tooling or set standards for organization
  • Developing with methodologies like BEM

This will eliminate any of those concerns on a smaller project (or large) and can actually make life easier.

What CSS-in-JS is good at...

Helping large teams preserve sanity

Part of why this solution exists is because very large teams have a hard time avoiding conflicts when they have a huge library to deal with. Being able to have your component and anything that impacts it in one compartmentalized area helps people avoid stepping on each other's feet and potentially rolling out tweaks that unintentionally cascade throughout the app. This is great but more likely than not, you're 1 of a few (or alone) working on a small app. If you and your team aren't communicating about some basic rules and standards, I'd argue you have bigger problems.

Kind of eliminates the need to learn CSS (kind of)

Some developers mock CSS saying it's not real code, others are scared about it's magic (don't be, embrace it). Only having to worry about a few rules in one component helps put people's mind at ease knowing it's just a little more JS that changes how it looks a bit.

What can both do?

CSS pointing at CSS

Hot Module Reloading (HMR)

Though some say an advantage to CSS-in-JS is HMR, you'll find this works fine with stylesheets. Sometimes it actually works a little nicer if you're working on a component that requires a rerender such as those with a network request as a dependency, where the CSS changes won't force that rerender.

Variables, Global Settings

If someone is making an argument that CSS can't do that, it's because they haven't been paying attention for a while. Not only does Sass provide this, it's native to modern browsers.

Encapsulation

Yes, you don't need JS to do this. Add a class name to the top-level element of the component or page, nest all styles inside, and you have your encapsulation.

.page-about {
  .header {
    background-color: red;
  }
}

.navigation {
  .button {
    background-color: blue;
  }
}
Enter fullscreen mode Exit fullscreen mode

Linting

https://stylelint.io/

A lot more

Honestly, there's probably a lot more that both do similarly that you just don't realize.

What stylesheets and SASS do better...

Rule sharing and configuration

SASS allows you to configure variables, custom functions, and mixins that take your CSS development to the next level.

Ignoring the bad selector names:

// settings.scss

$color-ultraviolet: #5F4B8B;

// colbys-styles.scss

@import "settings";

.colbys-text-color {
  color: $color-ultraviolet
}

.colbys-background-color {
  background-color: $color-ultraviolet
}
Enter fullscreen mode Exit fullscreen mode

While the syntax and configuration of this are arguably easier than setting up a bunch of object configurations in JS, this greatly allows you to provide consistent visual experiences and DRY up your code.

Responsive design

One of the many things that add to the role of a good front end engineer is paying attention to how the project will look across multiple devices and sizes. Overall, UX is everyone's job. Developing with a responsive-first mindset not only makes that process easier, it helps build a better product.

Trying to make your components responsive in JS means more Javascript and more event listeners. Not only does this add complexity, it hits performance. We can do this much easier with media queries baked right into CSS.

.colbys-sidebar {
  width: 100%;
}

// NO EVENT LISTENERS

@media (min-width: 1024px) {
  .colbys-sidebar {
    width: 25%;
  }
}
Enter fullscreen mode Exit fullscreen mode

Instead of having to throttle the event listeners, making sure your event listeners unregister on unmount, and just dealing with organizing that all in "the react way", media queries trigger on-demand and will flip your styles as needed in a more consistent manner.

Less complexity of your components

Being able to focus on the functionality and the rendered output allows you to avoid pulling in libraries or complex methods to essentially patch CSS into your JS, not to mention the JS hack or two or three that you're using to get it working in the first place.

// This is an exaggeration

const styles = {
  color: blue;
}

if ( whos_favorite === 'Colby' || whos_favorite === 'Lord Commander' ) {
  styles.color = 'ultraviolet';
} else if ( whos_favorite === 'The Gary' ) {
  styles.color = 'red';
} else if ( whos_favorite === 'Mooncake' ) {
  styles.color = 'green';
} else if ( whos_favorite === 'HUE' ) {
  styles.color = 'blue';
} else if ( whos_favorite === 'KVN' ) {
  styles.color = 'yellow';
}

<MyCompnent styles={styles} />
Enter fullscreen mode Exit fullscreen mode

Performance

Less Javascript is always a win. It's less your browser has to load, less your browser has to compile, which will ultimately translate to quicker page speed. When the browser loads a page, it tries to optimize the HTML and CSS as much as possible. Yes, you probably are loading more CSS upfront, but more JS is very costly and also is more likely to force a full rerender;

A lot of the little magic bits you do with Javascript can be done with some pretty powerful CSS animation methods, just browse Codepen a bit or check out something like Animista.

I don't actually have any numbers on this aside from a few good notes and some CSS-in-JS benchmarksHas anyone done the legwork on this?

At the end of the day, do what's effective

Fighting over using CSS-in-JS

Everyone has a personal preference, everyone is productive in a different way. Do what's best for you, do what's best for your team, and avoid treating what other developers say as dogmatic rights and wrongs.

If you're a lone developer on a project and want to practice CSS-in-JS to get used to it for when you're on a big team, go for it! If you're on a huge, huge team at Facebook and want to use stylesheets, well you might run into issues if everyone's not following the same guidelines, but do what's best for you and your team.

The only way you can figure that out is with experience and experimentation. Play with both solutions and figure out why YOU think one is better than the other. You never know where you'll end up after landing that gig at Google or your new startup in your garage.

Get more content straight your inbox!

Originally published on July 18, 2019 at colbyfayock.com

Top comments (22)

Collapse
 
blazephoenix profile image
Tanmay Naik • Edited

CSS in JS is for teams that don't understand or don't want to learn CSS. If you know how to maintain modularity in CSS, you don't need it in JS. SASS helps do exactly that.

Collapse
 
colbyfayock profile image
Colby Fayock

💯

Collapse
 
aleksandrhovhannisyan profile image
Aleksandr Hovhannisyan • Edited

CSS in JS is spaghetti. Tried it once with styled-components and did not enjoy it. It makes it more difficult for me to concentrate on one thing at a time because of all the visual noise. I prefer to keep my stylesheets separate and use well-named class and ID names.

Collapse
 
pozda profile image
Ivan Pozderac

Every code can be spaghetti. What horrible SASS and Stylus files have I seen last couple of years and refactored to be smaller, readable and dry!

Don't get me wrong, I love using BEM and SASS, but styled components is something that actually removes visual noise and help me concentrate at one thing at the time as well as making process of sharing components between different suite of apps a little bit less difficult.

There are many ways to arrange your code and if you use defaults like writing css in the same file as component it could be distracting and overwhelming. I like to extract styles in separate file and just import what I need. So the example of simple searchbar component would be something like this:

import React from 'react'
import appConstants from 'utils/appConstants'
import {
    StyledSearchbar,
    StyledSearchbarField,
    StyledSearchbarIconWrapper
} from './SearchbarStyles'
import {Icon} from 'components'

interface Props {
    onChange: (e: React.ChangeEvent<HTMLInputElement>) => void,
    handleEnterKey: (e: React.KeyboardEvent<HTMLInputElement>) => void,
    onClick: () => void,
    query: string
}

const Searchbar = ({onChange, onClick, query, handleEnterKey}: Props) => (
    <StyledSearchbar>
        <StyledSearchbarField
            placeholder={appConstants.placeholder.SEARCH}
            onChange={onChange}
            onKeyDown={handleEnterKey}
        />
        <StyledSearchbarIconWrapper disabled={query.length < 1} onClick={query.length < 1 ? undefined : onClick}>
            <Icon d={Icon.res.SEARCH} height={16} width={16} />
        </StyledSearchbarIconWrapper>
    </StyledSearchbar>
)
export default Searchbar

And all the styles are separated and working fine from the other file. If you need to change CSS, no need to medle with component files.

And the other thing is that we have few apps with components that we share between them and this helps a lot, not that you can't do it with SASS or PostCSS, but we estimated that styled components will be less painful for that kind of job.

Collapse
 
colbyfayock profile image
Colby Fayock

agreed

Collapse
 
josemunoz profile image
José Muñoz

Trying to make your components responsive in JS means more Javascript and more event listeners.

I'm gonna need a source for that

Collapse
 
colbyfayock profile image
Colby Fayock

i guess I'll turn it back, how would you do it otherwise? if you're using a JS solution, you would need know that the page changed size in order to change the view, otherwise you're using CSS and HTML which isn't the point I'm trying to make

Collapse
 
bendman profile image
Ben Duncan

First of all, great article. I think many people overlook the power in regular CSS, and a lot of it has to do with a lack of understanding about the cascade and the flexibility in CSS selectors, custom properties, and functions like calc() or a preprocessor step to make conventions like BEM easier.

To answer your question though, many CSS-in-JS libraries transpile to CSS, including support for @media queries.

As an example, here are some media query mixins I've used recently, written in JS for use with the styled-components library:

/**
 * Media Query Utilities
 */
export const media = {
  mobile: (first, ...args) => css`
    @media (max-width: ${breakpoints.mobile}) {
      ${css(first, ...args)}
    }
  `,
  desktop: (first, ...args) => css`
    @media (min-width: ${breakpoints.desktop}) {
      ${css(first, ...args)}
    }
  `,
  /**
   * Return a style that only applies when the property matches the media query:
   *
   * `'mobile'` => apply style to mobile
   *
   * `'desktop'` => apply style to desktop
   *
   * `true` => apply the style for all sizes
   *
   * `false` => don't apply the style
   */
  switch: (switchProp?: BreakpointSwitchProp) => (first, ...args) => {
    if (switchProp === 'mobile') {
      return media.mobile(first, ...args)
    } else if (switchProp === 'desktop') {
      return media.desktop(first, ...args)
    } else if (switchProp === true) {
      return css(first, ...args)
    } else {
      return ''
    }
  },
  noMotion: (first, ...args) => css`
    @media (prefers-reduced-motion: reduce) {
      ${css(first, ...args)}
    }
  `
}
Thread Thread
 
colbyfayock profile image
Colby Fayock

thanks! interesting - so is it compiled for the lifetime of the app? one particular piece I wasn't clear on is page to page loading, particularly if the app would still use JS to compile and fetch those new styles

Thread Thread
 
bendman profile image
Ben Duncan

It depends on your setup, typically with webpack loaders or something similar. There is quite a bit of infrastructure involved. It's been a while since I delved into this stuff but I think it can be either compiled into CSS files that are then available to import with normal <link> tags, or injected into style tags in the document. I think the second option is used to load the new page styles when routing in single-page apps. I know I've hit some bugs in single-page apps with loading order effecting the resulting styles, which can be a pain.

I'm sure someone else knows more about this than me and might be able to chime in though!

Thread Thread
 
colbyfayock profile image
Colby Fayock

yeah - makes sense. good to know though, appreciate the info

Collapse
 
josemunoz profile image
José Muñoz

I guess this has been answered already, but going beyond just styled-components: emotion.sh/docs/media-queries

Thread Thread
 
colbyfayock profile image
Colby Fayock

thanks for the share, will check it out

Collapse
 
darthbob88 profile image
Raymond Price

I've got to be honest, I went with CSS modules over styled-components for my last project because a) I really like autocomplete, and that only works with actual CSS, not strings, and b) Goddammit, I'm using a label element here, not MyOwnCustomizedLabelWithStylez, and on this hill I will die.

Collapse
 
johnrock profile image
John Rock

Good read, could not agree with you more on this!

Collapse
 
colbyfayock profile image
Colby Fayock

Thanks!

Collapse
 
nasidulislam profile image
Nasidul Islam

CSS in JS is just plain gross.

Collapse
 
joeattardi profile image
Joe Attardi

I was using styled-components for a while, but I never really loved it. I prefer plain old CSS modules! (Using Sass as a preprocessor)

Collapse
 
thekashey profile image
Anton Korzunov

Just read your article. Saw the same picture I've chosen for my unpublished one, and well... the name is also just the same

Collapse
 
colbyfayock profile image
Colby Fayock • Edited

that's funny, because I created that image myself in photoshop and this was originally posted on my blog as well as freecodecamp 7 months ago freecodecamp.org/news/you-dont-nee...

what do you think?

edit: i see you attributed the image. thank you :)

Collapse
 
thekashey profile image
Anton Korzunov

Unfortunately, I am not very capable to create cool images by myself, and this one is literally the best one. Hope you will like the way I've used it.

Collapse
 
colbyfayock profile image
Colby Fayock

fair :)