Write Atomic CSS like Facebook with Stylify
Tags: css, webdev, frontend, javascript
Published: 2022-01-10 17:57:23

Pixel perfect webdesign, atomic CSS, mangled selectors and minimalistic output? Yes 🤩!

---

Some time ago during a coffee ☕ break I have been digging through the Facebook CSS. I checked multiple pages, downloaded the CSS from them and got an idea on a tool that could simplify the way I write the CSS.

Laziness is a great thing. It leads people to simplify their work so in the end they have to do nothing. It also led me to create the https://stylifycss.com 💎.

When I have been digging through the Facebook code, I found the following.

Html:

<img src="https://stylifycss.com/images/blog/stylify-facebook/fb.jpg" loading="lazy" width="818" height="163" class="object-fit:cover">

CSS:

<img src="https://stylifycss.com/images/blog/stylify-facebook/fb2.jpg" loading="lazy" width="433" height="253" class="object-fit:cover">

If you take a closer look, you can see, that they are using atomic CSS and they mangle selectors.

I have also found an article [Rebuilding our tech stack for the new Facebook.com](https://engineering.fb.com/2020/05/08/web/facebook-redesign/) from Facebook itself in which they explain what have they changed for the new Facebook version. What the article also says is that they have been loading over 400 kB of compressed CSS and before switching to Atomic CSS.

From my experience, writting CSS manually is just slow and time consuming. Component frameworks are great until you start transforming every component. The Tailwind's JIT is close enough, but I don't like when I have to remember or search for the selector I want to use. I also need smaller chunks and integrate it into existing projects without increasing their size.

So the objective was clear. Create a tool that will be able to:
- Generate CSS separately according to content
- Mangle selectors
- Generate CSS on demand
- Use native CSS `properties:values` as selectors by default
- Work on its own without bundlers, frameworks and post/preprocessors

## Atomic CSS with Stylify
Stylify ships with the [native preset](https://stylifycss.com/docs/stylify/native-preset) in which the selectors are the same like CSS `property:value`. Thanks to that it is not necessary to remember or search for selectors. The Native Preset is optional and you can define your own selectors. Stylify also provides the following features (not all are listed):
- **Small chunks**: it can generate CSS for each file, component, layout separately
- **No pregenerated CSS**: the CSS is generated only if a component or selector is found in the content
- Internaly combines and reuses selectors as much as possible to keep the CSS small
- **Macros**: can be used to define custom selectors like `m:20px` for margin
- **Logical operands for screens**: like `&&` and `||` operands for screens combination: `sm&&tolg:font-size:24px`
- **Selectors mangling**: from long `font-weight:bold` to short `_ab`
- No preprocessor, postprocessor or bundler is required
- **On demand generated CSS**: the CSS can be bundled on demand, for example during a request
- Because it can generates CSS separately and doesn't bring any CSS by default, it **can be easily integrated into an existing project without increasing its size globally**

## Write HTML. Get CSS. Mangle selectors. All automagically.

The example bellow and all its code can be found and edited on the [StackBlitz](https://stackblitz.com/edit/expressjs-bvexzl?file=index.html).

In the example bellow there is a code for simple gallery image:
<!-- <stylify-ignore> -->
```html
<div class="
	display:inline-flex
	position:relative
	margin:24px
	overflow:hidden
	box-shadow:0__2px__8px__#000
	width:300px
	md:margin:48px
	md:width:600px
">
	<img class="width:100% object-fit:cover height:auto" src="https://stylifycss.com/images/blog/stylify-facebook/mountains.jpg" alt="">
	<div class="
		font-family:arial
		font-weight:bold
		font-size:18px
		position:absolute
		bottom:0
		left:0
		padding:24px
		background:rgba(0,0,0,0.7)
		color:#fff
		md:font-size:32px
	">
		Zakopané (Poland)
	</div>
</div>
```
<!-- </stylify-ignore> -->

The result of the code above will look like this:

<a href="">
	<img src="https://stylifycss.com/images/blog/stylify-facebook/stylify-facebook-result.jpg" alt="" width="702" height="577" loading="lazy">
</a>

The code above would look almost the same if it would be written in pure CSS. Only the `box-shadow` uses the `__` (two underscores) instead of a space.

Because of the maintainability and the fact that code above could be used on multiple places, it is necessary to make it more reusable. So let's define some components, macros and variables!

### Cleanup and Configuration

For the example above, I am using the following initialization that can be found on the [StackBlitz](https://stackblitz.com/edit/expressjs-bvexzl?file=index.html) (It is in the index.js and it is slightly changed in order to work in that environment):

```js
import { Compiler, nativePreset } from '@stylify/stylify';

const content = '';

const compiler = new Compiler(nativePreset.compiler);
const compilationResult = compiler.compile(content);
const css = compilationResult.generateCss();
const mangledContent = compiler.rewriteSelectors(content, compilationResult);
```

Let's add the shadow variable first into the compiler config:
```js
nativePreset.compiler.variables: {
	shadow: '0 2px 8px #000'
};
```

When the variable is defined, we can use it like this: `box-shadow:$shadow`.

The Native Preset is not required. You can define your own selectors. For example for the margin it would look like this:

```js
nativePreset.compiler.macros['m:(\\S+?)'] = (macroMatch, cssProperties) => {
	cssProperties.add('margin', macroMatch.getCapture(0));
};
```

When the macro is defined, it can be used with custom values like `m:24px` and `md:m:48px`.

If multiple and the same selectors should be used on multiple places, it is a good practice to define a component for them in order to simplify the maintainability and readability:

```js
nativePreset.compiler.components = {
	'gallery-image__wrapper': `
		display:inline-flex
		position:relative
		m:24px
		md:m:48px
		overflow:hidden
		box-shadow:$shadow
		width:300px
		md:width:600px
	`,
	'gallery-image': 'width:100% object-fit:cover height:auto',
	'gallery-image__label': `
		font-family:arial
		font-weight:bold
		font-size:18px
		position:absolute
		bottom:0
		left:0
		padding:24px
		background:rgba(0,0,0,0.7)
		color:#fff
		md:font-size:32px
	`
};
```

It is also a good practice to add the `box-sizing:border-box` to prevent the wtf moments somewhere in the future:

```js
nativePreset.compiler.plainSelectors: {
	'*': 'box-sizing:border-box'
};
```

With all the enhancements above, the finall code is a way smaller:

<!-- <stylify-ignore> -->
```html
<div class="gallery-image__wrapper">
	<img class="gallery-image" src="https://stylifycss.com/images/blog/stylify-facebook/mountains.jpg">
	<div class="gallery-image__label">
		Zakopané (Poland)
	</div>
</div>
```

## Minification and Optimization

Under the hood the Stylify optimizes the CSS in the following ways:

1. The selectors and components are generated only when found in the content
2. It tries to reuse the selectors as much as possible
3. It transforms the long selectors like `font-weight:bold ` into the short ones `_ab12`

Bellow is an image from StackBlitz with the processed and optimized output. The css (without new lines and spaces) has only **0.78kb**:

<img src="https://stylifycss.com/images/blog/stylify-facebook/processed-html.jpg" alt="" loading="lazy" width="856" height="506">

## Let me know what you think!
If you like the idea, let me know that by [starring Stylify repo](https://github.com/stylify/packages) ❤️.

Stylify took a year of development and the first release was published a month ago.
I will be very happy for any feedback, issue or an idea! 😊.

----
Stay in touch:
👉 [8machy](https://twitter.com/8machy)
👉 [dev.to/machy8](https://dev.to/machy8)
👉 [medium.com/@8machy](https://medium.com/@8machy)