DEV Community

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

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

Colby Fayock on March 18, 2020

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 ...
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
 
nasidulislam profile image
Nasidul Islam

CSS in JS is just plain gross.

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
 
johnrock profile image
John Rock

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

Collapse
 
colbyfayock profile image
Colby Fayock

Thanks!

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
 
colbyfayock profile image
Colby Fayock

fair :)