profile image
Sean Walker
2021-10-13

A sane way to organize your css

There are quite a few ways to organize your css:

And countless others I haven’t even heard of.

I want to toss another one onto the mix that handles a lot of the problems I was facing with the three above.

The problem with my CSS was that I was mixing too many things:

  1. how to handle responsive stuff
  2. ids AND classes for styling
  3. wanting to have a coherent visual style for things like forms and buttons but still do minor tweaks here and there?
  4. css for broad layout things like grid/flex

I’ll tackle these in order, the first part is not the greatest, but it’s not the worst either.

1. How to handle responsive stuff

I had two options here:

I started to go down the tailwind/variant path but I noticed that it might be easier to just treat various widths separately. There’s where I am now, doing the dumbest thing possible:

.lg {
  display: none;
}

.md {
  diplay: none;
}

.sm {
  display: none;
}

.xs {
  display: block;
}

@media(min-width: 640px) {
  .xs {
    display: none;
  }

  .sm {
    display: block;
  }
}

@media(min-width: 1024px) {
  .xs {
    display: none;
  }

  .md {
    display: block;
  }
}

@media(min-width: 1280px) {
  .lg {
    display: block;
  }

  .xs {
    display: none;
  }
}

I’ve come up with something like this before, but I just wanted to write it down.

Here’s how I use it:

<div class="lg">
  show this on displays greater than 1280px
</div>

<div class="md">
  show this on displays less than 1280px and greater than 1024px
</div>

<div class="sm">
  show this on displays less than 1024px and greater than 640px
</div>

<div class="xs">
  show this on displays less than 640px
</div>

<div>show this on all displays</div>

You can make this more granular if you want, anything less than 640px gets “mobile” treatment.

2. ids AND classes for styling

Don’t use ids for styling, only for hooks into js or input elements, that’s it.

Use classes for styling only, not for js stuff. Or if you have to use classes for js, make a separate class js-whatever that means it’s for js.

I feel like this one is pretty old at this point, again just wanted to write it down.

3. wanting to have a coherent visual style for things like forms and buttons but still do minor tweaks here and there?

This one is what I struggled with for a long time. Tailwind is supposed to help here with @apply and utility classes but it always felt like a weird version of css variables.

Then I found pollen.style. This solved the build tooling problem I had with tailwind and it gives me a consistent visual guideline to follow, but I can still make things look and feel the way I want them too (i.e. not bootstrap-y).

So that solves that, it’s basically like always using tailwind’s @apply but just with regular css variables.

Unfortunately I still found myself putting random utility classes in my html because I wanted to tweak a button or have a link look like a button or a button look like a link or something.

I still don’t have a great answer to this problem, the thing I’ve been lately is style things classless-ly (like by their elements, no classes) with pollen’s css variables and then when it comes time to override, create classes for the things you want, like .button similar to bootstrap but easy to override.

Here’s a more concrete example:

a {
  color: var(--color-indigo-500);
  text-decoration: none;
}

button {
  padding: var(--size-4);
  background-color: var(--color-indigo-500);
  color: white;
}

/* for buttons that want to be links: */

.button {
  padding: var(--size-4);
  background-color: var(--color-indigo-500);
  color: white;
}

/* for links that want to be buttons */

.link {
  color: var(--color-indigo-500);
  text-decoration: none;
}

There is a little duplication to separate the visual classes from the classless elements, but I think it does two things:

  1. Gets rid of specificity problems from doing button, .button {} and a, .link {} together.
  2. Makes it a little nicer:
<button></button>
<a></a>

<!-- vs -->

<button class="button"></button>
<a class="link"></a>

A little duplication goes a long way.

4. css for broad layout things like grid/flex

This is a separate concern from all of the rest of the css, so it gets it own section.

Flexbox really solves this nicely and coupled with css grid most of the large layout issues are gone.

I use flexbox like how it’s used in SwiftUI:

vstack {
  display: flex;
  flex-direction: column;
}

hstack {
  display: flex;
  flex-direction: row;
}

spacer {
  flex: 1;
}

You can make those classes if you want or put dashes in them if you’re worried about compatibility problems.

Alright, that’s the jist of my thinking on how to structure css. Hope it helps you regain your sanity when dealing with css, because in the end there’s no one size fits all solution, tailwind, BEM and classless css are nice but they aren’t a silver bullet.