A Unified Styling Language

In the past few years we’ve seen the rise of CSS-in-JS, emerging primarily from within the React community. This, of course, hasn’t been without its controversies. Many people, particularly those already intimately familiar with CSS, have looked on in disbelief.

“Why would anyone want to write CSS in JS?
Surely this is a terrible idea!
If only they’d learn CSS!”

If this was your reaction, then read on. We’re going to take a look at why writing your styles in JavaScript isn’t such a terrible idea after all, and why I think you should be keeping an eye on this rapidly evolving space.

Misunderstood communities

The React community is often misunderstood by the CSS community, and vice versa. This is particularly interesting for me, as I’m caught somewhere between these two worlds.

I started learning HTML in the late nineties, and I’ve been working with CSS professionally since the dark ages of table-based layouts. Inspired by CSS Zen Garden, I was on the front lines of migrating existing codebases towards semantic markup and cascading style sheets. It wasn’t long after this that I became obsessed with separating our concerns, using unobtrusive JavaScript to decorate our server-rendered markup with client-side interactions. There was a small but vibrant community surrounding these practices, and we became the first generation of front-end developers, trying to give the browser platform the respect it deserved.

With a web-focused background like this, you might imagine that I’d be vehemently opposed to React’s HTML-in-JS model, which seemingly goes against the principles we held so dear—but in fact, it’s quite the opposite. In my experience, React’s component model, coupled with its ability to render server-side, finally gives us a way to build complex single-page apps at scale, in a way that still allows us to ship fast, accessible, progressively enhanced products to our users. We’ve even leveraged this ability here at SEEK, our flagship product being a single-page React app where the core search flow still works when JavaScript is disabled—gracefully degrading to a traditional web site by running the same JavaScript code on the server.

So, consider this an olive branch from one community to another. Together, let’s try and understand what this movement is all about. It might not be perfect, it might not be something you plan to use in your products, it might not even be terribly convincing for you—but it’s at least worth trying to wrap your head around.

Why CSS-in-JS?

If you’re familiar with my recent work with React and CSS Modules, you may be surprised to see me defending CSS-in-JS.

CSS Modules (Source)

After all, CSS Modules is typically chosen by developers who want locally-scoped styles without buying in to CSS-in-JS. In fact, I don’t even use CSS-in-JS in my own work.

Despite this, I continue to maintain a keen interest in the CSS-in-JS community, keeping a close eye on the innovations that they continually come up with. Not only that, I think the broader CSS community should be interested too.

But why?

To get a clearer understanding of why people are choosing to write their styles in JavaScript, we’ll focus on the practical benefits that emerge when taking this approach.

I’ve broken this down into five major areas:

  1. Scoped styles
  2. Critical CSS
  3. Smarter optimisations
  4. Package management
  5. Non-browser styling

Let’s break this down further and have a closer look at what CSS-in-JS brings to the table for each of these points.


1.

Scoped styles

It’s no secret that architecting CSS effectively at scale is incredibly difficult. When joining an existing long-lived project, it wasn’t uncommon to find that the CSS was the hardest part of the system to figure out.

To counter this, the CSS community has invested heavily in trying to address these issues, making our styles more maintainable with methodologies like OOCSS by Nicole Sullivan and SMACSS by Jonathan Snook—but the clear winner right now in terms of popularity seems to be BEM, or Block Element Modifier, from Yandex.

Ultimately, BEM (when applied purely to CSS) is just a naming convention, opting to limit styles to classes following a .Block__element--modifier pattern. In any given BEM-styled codebase, developers have to remember to follow BEM’s rules at all times. When strictly followed, BEM works really well, but why is something as fundamental as scoping left up to pure convention?

Whether they explicitly say so or not, the majority of CSS-in-JS libraries are following the BEM mindset of trying to target styles to individual UI elements, but implementing it in a radically different way.

What does this look like in practice? When using glamor by Sunil Pai, it looks something like this:

import { css } from 'glamor'
const title = css({
fontSize: '1.8em',
fontFamily: 'Comic Sans MS',
color: 'blue'
})
console.log(title)
// → 'css-1pyvz'

What you’ll notice here is that the CSS class is nowhere to be found in our code. It’s no longer a hard-coded reference to a class defined elsewhere in the system. Instead, it is generated automatically for us by the library. We don’t have to worry about our selectors clashing in the global scope, which means we no longer have to manually prefix them.

The scoping of this selector matches the scoping rules of the surrounding code. If you want to make this rule available to the rest of your application, you’ll need to turn it into a JavaScript module and import it wherever it’s used. In terms of keeping our codebases maintainable over time, this is incredibly powerful, making sure that the source of any given style can be easily traced like any other code.

By moving from mere convention towards enforcing locally-scoped styles by default, we’ve now improved the baseline quality of our styles. BEM is baked in, not opt-in.

Before I continue, there’s a critically important point to clarify.

This is generating real CSS, not inline styles.

Most of the earliest CSS-in-JS libraries attached styles directly to each element, but the critical flaw in this model is that ‘style’ attributes can’t do everything that CSS can do. Most new libraries instead focus on dynamic style sheets, inserting and removing rules at runtime from a global set of styles.

As an example, let’s have a look at JSS by Oleg Slobodskoi, one of the earliest CSS-in-JS libraries to generate real CSS.

JSS (Source)

When using JSS, you can use standard CSS features like hover styles and media queries, which map directly to the equivalent CSS rules.

const styles = {
button: {
padding: '10px',
'&:hover': {
background: 'blue'
}
},
'@media (min-width: 1024px)': {
button: {
padding: '20px'
}
}
}

Once you insert these styles into the document, the automatically generated classes are provided to you.

const { classes } = jss.createStyleSheet(styles).attach()

These generated classes can then be used instead of hard-coded class strings when generating markup in JavaScript. This pattern works regardless of whether you’re using a full-blown framework, or something as simple as innerHTML.

document.body.innerHTML = `
<h1 class="${classes.heading}">Hello World!</h1>
`

Managing the styles in this way is of little benefit by itself—it’s usually paired with some kind of component library. As a result, it’s typical to find bindings available for the most popular libraries. For example, JSS can easily bind to React components with the help of react-jss, injecting a small set of styles into each component while managing the global lifecycle for you.

import injectSheet from 'react-jss'
const Button = ({ classes, children }) => (
<button className={classes.button}>
<span className={classes.label}>
{children}
</span>
</button>
)
export default injectSheet(styles)(Button)

By focusing our styles around components, integrating them more closely at the code level, we’re effectively taking BEM to its logical conclusion. So much so that many in the CSS-in-JS community felt like the importance of extracting, naming and reusing components was being lost in all the style-binding boilerplate.

An entirely new way of thinking about this problem emerged with the introduction of styled-components by Glen Maddern and Max Stoiber.

Styled Components (Source)

Instead of creating styles, which we then have to manually bind to components, we’re forced to create components directly.

import styled from 'styled-components'

const Title = styled.h1`
font-family: Comic Sans MS;
color: blue;

`

When applying these styles, we don’t attach a class to an existing element. We simply render the generated component.

<Title>Hello World!</Title>

While styled-components uses traditional CSS syntax via tagged template literals, others prefer working with data structures instead. A notable alternative is Glamorous by Kent C. Dodds from PayPal.

Glamorous (Source)

Glamorous offers the same component-first API as styled-components, but opts for objects instead of strings, eliminating the need to include a CSS parser in the library—reducing the library’s size and performance footprint.

import glamorous from 'glamorous'

const Title = glamorous.h1({
fontFamily: 'Comic Sans MS',
color: 'blue'
}
)

Whichever syntax you use to describe your styles, they’re no longer just scoped to components—they’re inseparable from them. When using a library like React, components are the fundamental building blocks, and now our styles form a core part of that architecture. If we describe everything in our app as components, why not our styles too?

For seasoned veterans of BEM, all of this may seem like a relatively shallow improvement given the significance of the change we’ve introduced to our system. In fact, CSS Modules lets you achieve this without leaving the comfort of the CSS tooling ecosystem. This is why so many projects stick with CSS Modules, finding that it sufficiently solves most of their problems with writing CSS at scale without sacrificing the familiarity of regular CSS.

However, it’s when we start to build on top of these basic concepts that things start to get a lot more interesting.


2.

Critical CSS

It’s become a relatively recent best practice to inline critical styles in the head of your document, improving initial load times by providing only those styles required to render the current page. This is in stark contrast to how we usually loaded styles—forcing the browser to download every possible visual style for our application before a single pixel was rendered on the screen.

While there are tools available for extracting and inlining critical CSS, like the appropriately named critical by Addy Osmani, they don’t fundamentally change the fact that critical CSS is difficult to maintain and automate. It’s a tricky, purely optional performance optimisation, so most projects seem to forgo this step.

CSS-in-JS is a totally different story.

When working in a server rendered application, extracting your critical CSS is not merely an optimisation—CSS-in-JS on the server fundamentally requires critical CSS to even work in the first place.

For example, when using Aphrodite from Khan Academy, it keeps track of which styles are used within a single render pass using its css function, which is called inline while applying classes to your elements.

import { StyleSheet, css } from 'aphrodite'
const styles = StyleSheet.create({
title: { ... }
})
const Heading = ({ children }) => (
<h1 className={css(styles.heading)}>{ children }</h1>
)

Even though all of your styles are defined in JavaScript, you can easily extract all the styles for the current page into a static string of CSS that can be inserted into the head of the document when rendering server-side.

import { StyleSheetServer } from 'aphrodite';

const { html, css } = StyleSheetServer.renderStatic(() => {
return ReactDOMServer.renderToString(<App/>);
});

You can now render your critical CSS block like this:

const criticalCSS = `
<style data-aphrodite>
${css.content}
</style>
`;

If you’ve looked into React’s server rendering model, you may find this to be a very familiar pattern. In React, your components define their markup in JavaScript, but can be rendered to a regular HTML string on the server.

If you build your app with progressive enhancement in mind, despite being written entirely in JavaScript, it might not require JavaScript on the client at all.

Either way, the client-side JavaScript bundle includes the code needed to boot up your single-page app, suddenly bringing it to life, rendering in the browser from that point forward.

Since rendering your HTML and CSS on the server happen at the same time, libraries like Aphrodite often help us streamline the generation of both critical CSS and server-rendered HTML into a single call, as we saw in the previous example. This now allows us to render our React components to static HTML in a similar fashion.

const appHtml = `
<div id="root">
${html}
</div>
`

By using CSS-in-JS on the server, not only does our single-page app continue to work without JavaScript, it might even render faster too.

As with the scoping of our selectors, the best practice of rendering critical CSS is now baked in, not opt-in.


3.

Smarter optimisations

We’ve recently seen the rise of new ways of structuring our CSS—like Atomic CSS from Yahoo and Tachyons by Adam Morse—that eschew “semantic classes” in favour of tiny, single-purpose classes. For example, when using Atomic CSS, you apply classes with a function-like syntax which can then be used to generate an appropriate style sheet.

<div class="Bgc(#0280ae.5) C(#fff) P(20px)">
Atomic CSS
</div>

The goal is to keep your CSS bundle as lean as possible by maximising the re-usability of classes, effectively treating classes like inline styles. While it’s easy to appreciate the reduction in file size, the impacts to both your codebase and your fellow team members are anything but insignificant. These optimisations, by their very nature, involve changes to both your CSS and your markup, making them a more significant architectural effort.

As we’ve touched on already, when using CSS-in-JS or CSS Modules, you no longer hard-code class strings in your markup, instead using dynamic references to JavaScript values that have been generated automatically by a library or build tool.

Instead of this:

<aside className="sidebar" />

We write this:

<aside className={styles.sidebar} />

This may look like a fairly superficial change, but this is a monumental shift in how we manage the relationship between our markup and our styles. By giving our CSS tooling the ability to alter not just our styles, but the final classes we apply to our elements, we unlock an entirely new class of optimisations for our style sheets.

If we look at the example above, ‘styles.sidebar’ evaluates to a string, but there’s nothing limiting it to a single class. For all we know, it could just as easily end up being a string of over a dozen classes.

<aside className={styles.sidebar} />
// Could easily resolve to this:
<aside className={'class1 class2 class3 class4'} />

If we can optimise our styles, generating multiple classes for each set of styles, we can do some really interesting things.

My favourite example of this is Styletron by Ryan Tsao.

Styletron (Source)

In the same way that CSS-in-JS and CSS Modules automate the process of adding BEM-style class prefixes, Styletron does the same thing to the Atomic CSS mindset.

The core API is focused around a single task—defining individual CSS rules for each combination of property, value and media query, which then returns an automatically generated class.

import styletron from 'styletron';
styletron.injectDeclaration({
prop: 'color',
val: 'red',
media: '(min-width: 800px)'
}
);
// → 'a'

Of course, Styletron provides higher level APIs, such as its injectStyle function which allows multiple rules to be defined at once.

import { injectStyle } from 'styletron-utils';
injectStyle(styletron, {
color: 'red',
display: 'inline-block'
});
// → 'a d'
injectStyle(styletron, {
color: 'red',
fontSize: '1.6em'
});
// → 'a e'

Take special note of the commonality between the two sets of class names generated above.

By relinquishing low-level control over the classes themselves, only defining the desired set of styles, we allow the library to generate the optimal set of atomic classes on our behalf.

CSS-in-JS bundle size comparison using Airbnb’s styles (Source)

Optimisations that are typically done by hand—finding the most efficient way to split up our styles into reusable classes—can now be completely automated. You might be starting to notice a trend here. Atomic CSS is baked in, not opt-in.


4.

Package management

Before digging into this point, it’s first worth stopping and asking yourself a seemingly simple question.

How do we share CSS with each other?

We’ve migrated from manually downloading CSS files, towards front-end specific package managers like Bower, and now via npm thanks to tools like Browserify and webpack. Even though some tooling has automated the process of including CSS from external packages, the front-end community has mostly settled on manual inclusion of CSS dependencies.

Either way, there’s one thing that CSS dependencies aren’t very good at—depending on other CSS dependencies.

As many of you might remember, we’ve seen a similar effect with JavaScript modules between Bower and npm.

Bower wasn’t coupled to any particular module format, whereas modules published to npm use the CommonJS module format. This has had a massive impact on the number of packages published to each platform.

Complex trees of small, nested dependencies felt right at home on npm, while Bower attracted large, monolithic dependencies, of which you might only have two or three—plus a few plugins, of course. Since your dependencies didn’t have a module system to rely on, each package couldn’t easily make use of its own dependencies, so the integration was always a manual step left up to the consumer.

As a result, the number of packages on npm over time forms an exponential curve, while Bower only had a fairly linear increase of packages. While there are certainly a variety of reasons for this differentiation, it’s fair to say that a lot of it has to do with the way each platform allows (or doesn’t allow) packages to depend on each other at runtime.

Yes, it’s this graph again. (Source)

Unfortunately, this looks all too familiar to the CSS community, where we’ve also seen a relatively slow increase of monolithic packages compared to what we see with JavaScript packages on npm.

What if we instead wanted to match npm’s exponential growth? What if we wanted to be able to depend on complex package hierarchies of varying sizes, with less focus on large, all-encompassing frameworks? To do this, we’d not only need a package manager that’s up to the task—we’d also need an appropriate module format too.

Does this mean that we need a package manager specifically designed for CSS? For preprocessors like Sass and Less?

What’s really interesting is that we’ve already gone through a similar realisation with HTML. If you ask the same questions about how we share markup with each other, you’ll quickly notice that we almost never share raw HTML directly—we share HTML-in-JS.

We do this via jQuery plugins, Angular directives and React components. We compose large components out of smaller components, each with their own HTML, each published independently to npm. HTML as a format might not be powerful enough to allow this, but by embedding HTML within a fully-fledged programming language, we’re easily able to work around this limitation.

What if, like HTML, we shared our CSS—and the logic that generates it—via JavaScript? What if, instead of using mixins, we used functions returning objects and strings? Instead of extending classes, what if we simply merged objects with Object.assign, or the new object spread operator?

const styles = {
...rules,
...moreRules,
fontFamily: 'Comic Sans MS',
color: 'blue'
}

Once we start writing our styles this way, we can now compose and share our styling code like any other code in our application, using the same patterns, the same tooling, the same infrastructure, the same ecosystem.

A great example of how this starts to pay off is in libraries like Polished by Max Stoiber, Nik Graf and Brian Hough.

Polished (Source)

Polished is essentially the Lodash of CSS-in-JS, providing a complete suite of mixins, colour functions, shorthands and more, making the process of authoring styles in JavaScript much more familiar for those coming from languages like Sass. The key difference now is that this code is much more composable, testable and shareable, able to use the full JavaScript package ecosystem.

So, when it comes to CSS, how do we achieve the same level of open source activity seen across npm as a whole, composing large collections of styles from small, reusable, open-source packages? Strangely enough, we might finally achieve this by embedding our CSS within another language and completely embracing JavaScript modules.


5.

Non-browser styling

So far, all of the points we’ve covered—while certainly a lot easier when writing CSS in JavaScript—they’re by no means things that are impossible with regular CSS. This is why I’ve left the most interesting, future-facing point until last. Something that, while not necessarily playing a huge role in today’s CSS-in-JS community, is quite possibly going to become a foundational layer in the future of design. Something that affects not just developers, but designers too, radically altering the way these two disciplines communicate with each other.

First, to put this in context, we need to take a quick detour into React.

The React model is all about components rendering intermediate representations of the final output. When working in the browser, rather than directly mutating DOM elements, we’re building up complex trees of virtual DOM.

What’s interesting, though, is that rendering to the DOM is not part of the core React library, instead being provided by react-dom.

import { render } from 'react-dom'

Even though React was built for the DOM first, and still gets most of its usage in that environment, this model allows React to target wildly different environments simply by introducing new renderers.

JSX isn’t just about virtual DOM—it’s about virtual whatever.

This is what allows React Native to work, writing truly native applications in JavaScript, by writing components that render virtual representations of their native counterparts. Instead of div and span, we have View and Text.

From a CSS perspective, the most interesting thing about React Native is that it comes with its own StyleSheet API:

var styles = StyleSheet.create({
container: {
borderRadius: 4,
borderWidth: 0.5,
borderColor: '#d6d7da',
},
title: {
fontSize: 19,
fontWeight: 'bold',
},
activeTitle: {
color: 'red',
}
})

Here you can see a familiar set of styles, in this case covering colours, fonts and border styling.

These rules are fairly straightforward and map easily to most UI environments, but things get really interesting when it comes to native layout.

var styles = StyleSheet.create({
container: {
display: 'flex'
}
})

Despite being outside of a browser environment, React Native ships with its own native implementation of flexbox.

Initially released as a JavaScript package called css-layout, reimplementing flexbox entirely in JavaScript (backed by an appropriately comprehensive test suite), it’s now been migrated to C for better portability.

Given the scope and importance of the project, it’s been given a more significant brand of its own in the form of Yoga.

Yoga (Source)

Even though Yoga is all about porting CSS concepts to non-browser environments, the potentially unmanageable scope has been reigned in by focusing on only a subset of CSS features.

“Yoga’s focus is on creating an expressive layout library, not implementing all of CSS”

These sorts of tradeoffs may seem limiting, but when you look at the history of CSS architecture, it’s clear that working with CSS at scale is all about picking a reasonable subset of the language.

In Yoga’s case, they eschew the cascade in favour of scoped styles, and focus their layout engine entirely on flexbox. While this rules out a lot of functionality, it also unlocks an amazing opportunity for cross-platform components with embedded styling, and we’ve already seen several notable open source projects trying to capitalise on this fact.

React Native for Web by Nicolas Gallagher aims to be a drop-in replacement for the react-native library. When using a bundler like webpack, aliasing third-party packages is fairly straightforward.

module: {
alias: {
'react-native': 'react-native-web'
}
}

Using React Native for Web allows React Native components to work in a browser environment, including a browser port of the React Native StyleSheet API.

Similarly, react-primitives by Leland Richardson is all about providing a cross-platform set of primitive components that abstract away the implementation details of the target platform, creating a workable baseline for cross-platform components.

Even Microsoft is getting in on the act with the introduction of ReactXP, a library designed to streamline efforts to share code across both web and native, which also includes its own platform-agnostic style implementation.

Even if you don’t write software for native applications, it’s important to note that having a truly cross-platform component abstraction allows us to target an effectively limitless set of environments, sometimes in ways that you might never have predicted.

The most surprising example of this I’ve seen is react-sketchapp by Jon Gold at Airbnb.

react-sketchapp (Source)

For many of us, so much of our time is spent trying to standardise our design language, limiting the amount of duplication in our systems as much as possible. Unfortunately, as much as we’d like to only have a single source of truth, it seemed like the best we could hope for was to reduce it to two—a living style guide for developers, and a static style guide for designers. While certainly much better than what we’ve been historically used to, this still leaves us manually syncing from design tools—like Sketch—to code and back. This is where react-sketchapp comes in.

Thanks to Sketch’s JavaScript API, and the ability for React to connect to different renderers, react-sketchapp lets us take our cross-platform React components and render them into our Sketch documents.

Profile Cards example powered by react-sketchapp (Source)

Needless to say, this has the potential to massively shake up how designers and developers collaborate. Now, when we refer to the same components while iterating on our designs, we can potentially be referring to the same implementation too, regardless of whether we’re working with tools for designers or developers.

With symbols in Sketch and components in React, our industry is essentially starting to converge on the same abstraction, opening the opportunity for us to work closer together by sharing the same tools.


It’s no coincidence that so many of these new experiments are coming from within the React community, and those communities surrounding it.

In a component architecture, co-locating as many of a component’s concerns in a single place becomes a high priority. This, of course, includes its locally scoped styles, but even extends to more complicated areas like data fetching thanks to libraries like Relay and Apollo. The result is something that unlocks an enormous amount of potential, of which we’ve only just scratched the surface.

While this has a huge impact on the way we style our applications, it has an equally large effect on everything else in our architecture—but for good reason.

By unifying our model around components written in a single language, we have the potential to better separate our concerns—not by technology, but by functionality. Scoping everything around the unit of a component, scaling large yet maintainable systems from them, optimised in ways that weren’t possible before, sharing our work with each other more easily and composing large applications out of small open-source building blocks. Most importantly, we can do all of this without breaking progressive enhancement, without giving up on the principles that many of us see as a non-negotiable part of taking the web platform seriously.

Most of all, I’m excited about the potential of components written in a single language to form the basis of a new, unified styling language—one that unites the front-end community in ways we’ve never seen before.


At SEEK, we’re working to take advantage of this by building our own living style guide around this component model, where semantics, interactivity and visual styling are all united under a single abstraction. This forms a common design language, shared between developers and designers alike.

As much as possible, building a page should be as simple as combining an opinionated set of components that ensure our work stays on brand, while allowing us to upgrade our design language long after we’ve shipped to production.

import {
PageBlock,
Card,
Text
}
from 'seek-style-guide/react'
const App = () => (
<PageBlock>
<Card>
<Text heading>
Hello World!</Text>
</Card>
</PageBlock>
)

Even though our style guide is currently built with React, webpack and CSS Modules, the architecture exactly mirrors what you’d find in any system built with CSS-in-JS. The technology choices may differ, but the mindset is the same.

However, these technology choices will likely need to shift in unexpected ways in the future, which is why keeping an eye on this space is so critical to the ongoing development of our component ecosystem. We may not be using CSS-in-JS today, but it’s quite possible that a compelling reason to switch could arise sooner than we think.


CSS-in-JS has come a surprisingly long way in a short amount of time, but it’s important to note that, in the grand scheme of things, it’s only just getting started.

There’s still so much room for improvement, and the innovations are showing no signs of stopping. Libraries are still popping up to address the outstanding issues and to improve the developer experience—performance enhancements, extracting static CSS at build time, targeting CSS variables and lowering the barrier to entry for all front-end developers.

This is where the CSS community comes in. Despite all of these massive alterations to our workflow, none of this changes the fact that you still need to know CSS.

We may express it with different syntax, we may architect our apps in different ways, but the fundamental building blocks of CSS aren’t going away. Equally, our industry’s move towards component architectures is inevitable, and the desire to reimagine the front-end through this lens is only getting stronger. There is a very real need for us to work together, to ensure our solutions are widely applicable to developers of all backgrounds, whether design-focused, engineering-focused, or both.

While we may sometimes seem at odds, the CSS and JS communities both share a passion for improving the front-end, for taking the web platform seriously, and improving our processes for the next generation of web sites. There’s so much potential here, and while we’ve covered an incredible amount of ground so far, there’s still so much work left to be done.


At this point, you still might not be convinced, and that’s totally okay. It’s completely reasonable to find CSS-in-JS to be ill-fitting for your work right now, but my hope is that it’s for the right reasons, rather than superficial objections to mere syntax.

Regardless, it seems quite likely that this approach to authoring styles is only going to grow more popular over the coming years, and it’s worth keeping an eye on it while this approach continues to evolve at such a rapid pace. I sincerely hope that you’re able to join us in helping make the next generation of CSS tooling as effective as possible for all front-end developers, whether through code contributions or simply being an active part of the conversation. If not, at the very least, I hope I’ve been able to give you a better understanding of why people are so passionate about this space, and—maybe—why it’s not such a ridiculous idea after all.


This article was written in parallel with a talk of the same name — presented at CSSconf EU 2017 in Berlin, Germany — which is now available on YouTube.