Meet Sass Pal.
Tags: css, angular, react, vue
Published: 2020-06-25 14:33:11

So, SASS has variables, mixins, functions, parent selectors, nesting. Cool. That gives developers more power, not more structure.

You could `npm install bootstrap` and import just its sass files into your frontend project. Now you have pre-made components, some variables, utilities. You later realize you don't need all those unused components, so you start to comment out some `@import` statements. Then you want to change the color palette and override variables. Then you want buttons to look different and add CSS to override the framework's CSS. You may reach a point where you use only Bootstrap's utilities.

You swear you're not gonna use frameworks again and instead switch to a utilities-only library, Tailwind, which is a fully composable way of avoiding to write any CSS and instead stuff your templates with hundreds of utility classes. It has its strengths though: it's good to have everything on the table and just pick up what you want, but it can be tiresome to set up a huge regex via PostCSS and purge everything when you're finished. Try to do that with Angular and let me know (EDIT: this has improved in the last year).

Meet Sass Pal, a Sass library that *attempts* to solve most of these problems. The main concepts include
- Not a single line of CSS is output unless you need it
- Sensible defaults for colors, media breakpoints and units
- Helps to centralize shared values into a store
- Completely overridable and extensible
- No pollution of global namespace: only one `$_PAL_STORE` variable exists and all mixins and functions start with `pal-`
- Gradual migration: you can use as little as needed or go full Sass Pal without colliding with any existing styling code
- A suite of unit tests and a comprehensive documentation with examples

The cool part is that is has a lot of features like *builders*, *request maps*, *device queries*, a *store* and *reducers* (high five to Redux enthusiasts out there), but you can still ignore everything and just use a tiny fraction of it, since all disappears once compiled to CSS. Let's peak into the docs. So this

```scss
.hello-world {
  @include pal((

    'any': (
      space: my2 'p^b4',
      border: (x: 2 #ccc, y: 1 #ddd),
      position: absolute (2 4),
      size: (
        w-3/4,
        h-8u,
        wmin-1/2%,
      ),
    ),

    'tablet+': (
      space: my0 py5 px8,
      border: (x: 3 #ccc, y: 3 #ddd),
    ),

    'desktop+:hover': (
      space: my2
    )

  ));
}
```

compiles to this

```css
.hello-world {
  margin-top: 1rem;
  margin-bottom: 1rem;
  padding-top: 2rem;
  padding-right: 2rem;
  padding-left: 2rem;
  border-right: 1rem solid #ccc;
  border-left: 1rem solid #ccc;
  border-top: 0.5rem solid #ddd;
  border-bottom: 0.5rem solid #ddd;
  position: absolute;
  top: 1rem;
  bottom: 1rem;
  left: 2rem;
  right: 2rem;
  width: 75%;
  height: 4rem;
  min-width: 50%;
}

@media screen and (min-width: 768px) {
  .hello-world {
    margin-top: 0;
    margin-bottom: 0;
    padding-top: 2.5rem;
    padding-bottom: 2.5rem;
    padding-right: 4rem;
    padding-left: 4rem;
    border-right: 1.5rem solid #ccc;
    border-left: 1.5rem solid #ccc;
    border-top: 1.5rem solid #ddd;
    border-bottom: 1.5rem solid #ddd;
  }
}

@media screen and (min-width: 1024px) {
  .hello-world:hover {
    margin-top: 1rem;
    margin-bottom: 1rem;
  }
}
```

For me, the best part is not that you write less code, but that you can separate the actual styling (inside the components) from the state management of your styling values (inside your store). Like, what does `'desktop+:hover'` mean in the example? Basically, whatever you want it to mean. By default, anyway, it means *these rules only apply to desktops or bigger devices, only while hovering*, where a *desktop* is just a name you give to a resolution range you can override. What does `side: (w-3/4, h-8u)` mean again? It means *I want this component to have a width of 75% of its container and an height equal to 8 times the base unit* and the *base unit* is `0.5rem` by default or any other number if you override it.

To learn more, visit
https://github.com/alaindet/sass-pal
https://alaindet.github.io/sass-pal/

Photos courtesy of
https://unsplash.com/photos/qV2eVjm7cnw
https://unsplash.com/photos/-LxNvgW1psM