Yesterday I had the privelege of giving my very first public tech talk ever. Thanks for everybody coming to Frontend Meetup Freiburg and listen to me rambling about why TailwindCSS is awesome. Really appreciated and looking forward for further exchange.
As promised, here are the slides:
Write maintainable frontend code and battle CSS anxiety by follwing a more functional approach to writing HTML & CSS.
In the late summer of 2017 I came across the concept of Functional CSS, later more commonly referred to as Utility-First CSS.
Like everybody else I was highly sceptical at first. Looking at class collections such as
f6 link dim br2 ph3 pv2 mb2 dib white bg-black makes a lot of developers cringe – not only at first sight. But after digging deeper and seeing how some amazing people used the seemingly radical approach to their advantage got me convinced quickly.
Thanks to Emma for taking some pictures.
I’d also like to point out some articles along with some quotations that had most impact on my journey towards this utility-first mindset:
- However, not all semantics need to be content-derived. Class names cannot be “unsemantic”. Whatever names are being used: they have meaning, they have purpose. Class name semantics can be different to those of HTML elements
- Content-layer semantics are already served by HTML elements
- Class names impart little or no useful semantic information to machines
- Class names should communicate useful information to developers.
- Tying your class name semantics tightly to the nature of the content has already reduced the ability of your architecture to scale or be easily put to use by other developers.
- The most reusable components are those with class names that are independent of the content.
- We shouldn’t be afraid to include additional HTML elements if they help create more robust, flexible, and reusable components. Doing so does not make the HTML “unsemantic”, it just means that you use elements beyond the bare minimum needed to markup the content.
- A flexible and reusable component is one which neither relies on existing within a certain part of the DOM tree, nor requires the use of specific element types. It should be able to adapt to different containers and be easily themed
- When you choose to author HTML and CSS in a way that seeks to reduce the amount of time you spend writing and editing CSS, it involves accepting that you must instead spend more time changing HTML classes on elements if you want to change their styles. This turns out to be fairly practical, both for front-end and back-end developers – anyone can rearrange pre-built “lego blocks”; it turnsout that no one can perform CSS-alchemy.
- Eventually though, something started to feel a bit off. I had “separated my concerns”, but there was still a very obvious coupling between my CSS and my HTML. Most of the time my CSS was like a mirror for my markup; perfectly reflecting my HTML structure with nested CSS selectors. My markup wasn’t concerned with styling decisions, but my CSS was very concerned with my markup structure. Maybe my concerns weren’t so separated after all.
- When you think about the relationship between HTML and CSS in terms of “separation of concerns”, it’s very black and white. You either have separation of concerns (good!), or you don’t (bad!). This is not the right way to think about HTML and CSS. Instead, think about dependency direction.
- Neither is inherently “wrong”; it’s just a decision made based on what’s more important to you in a specific context. For the project you’re working on, what would be more valuable: restyleable HTML, or reusable CSS?
- The more a component does, or the more specific a component is, the harder it is to reuse.
- You should still create components. One of the areas where my opinion differs a bit from some of the really die-hard functional CSS advocates is that I don’t think you should build things out of utilities only.
- “Favor composition over inheritance”.
- immutability, composability, predictability, and avoidance of side-effects
- Code that is easier to maintain and to scale.
- Utility classes expose a well-defined API that you can use to compose more complex components. You’re not re-writing styles; instead, you’re relying on classes that define styles and behaviors once and for all.
- provides a single source of truth
- when it comes to HTML and CSS, you can’t look at it from a strict “separation of concerns” perspective. It’s a “which depends on which” relationship.
- The problem with BEM is that it focuses on building components first. Instead of looking for the smallest, unsplittable patterns, you’re building blocks and their child elements. BEM does an excellent job at namespacing and preventing style leaks, but its component-first nature inevitably leads to premature abstraction: you make a component for a certain use-case and end up never reusing it (a navbar component, for example).
- you end up creating tons of modifiers you only use once for a specific use-case.
- Premature abstraction keeps components from evolving and splitting into independent entities if they need to. Modifiers multiply as an attempt to fix it, resulting in non-reusable variations for unicorn use-cases, and undo band-aids when we realize our component does too much.
- Utility-first isn’t about ditching components altogether. It means you should start off with utility classes, make the most of them, and only abstract when you see repeating patterns
- It is crucial to understand that a component isn’t just a similar-looking “block” that you can reuse. It’s a pattern that is strongly tied to your specific project. Sure, you’re probably going to use tons of .btn and .modal, so it makes sense to abstract them early on. But are you positive you’re going to ever reuse .testimonial? Or at least reuse it enough to make it worth being a new component? Will it always look like this in every context, or is it specific to the homepage? Keep your options open. It’s a lot easier to later abstract a composite style into a component than to try and undo one.
- Functional: Small, clear, easy to read classes that are easy to apply and do one thing.
- Composable: declarative composition —
<a class="mb2 bg-green white px2 rounded">rather than OO-derived objects & modifiers —
<a class="btn btn--primary">.
- Immutable: Declare a property once and you should be damn sure it’s never going to get overwritten.
- it should be guaranteed to do the thing you want it to do
- Side-effect free: Not only should a class do the same thing every time, but it should never, ever change anything other than what you’re targeting.
- Everyone loves writing CSS. It’s fun! Maintaining a CSS codebase at scale is another story. A few tight deadlines and quick shortcuts, and whoops – you find yourself in the dreaded “append only stylesheet” situation.
- Utility classes to the rescue! Keep an open mind, and let’s embark on a real-life journey into the controversial, emotional and highly opinionated World of “utility-first” CSS.
- When it comes to CSS, I believe that the sacred principle of “separation of concerns” (SoC) has lead us to accept bloat, obsolescence, redundancy, poor caching and more. Now, I’m convinced that the only way to improve how we author style sheets is by moving away from this principle.
- We are now editing HTML templates instead of style sheets. […] it narrows the scope dramatically. We are styling not in the global scope (the style sheet), but at the module and block level. We can change the style of a module without worrying about breaking something else on the page.
- Bad: We leave alone rules that we suspect to be obsolete for fear of breaking something. We create new rules, rather than modify existing ones, because we are not sure the latter is 100% safe.
- Presentational rules do not change. Style sheets made from such rules mature into tool sets in which authors can find everything they need. By their nature, they stop growing and become immutable, and immutable is cache-friendly.
- Note that if maintenance is easier on the CSS side than on the HTML side, then the reason is simply that we can cheat on the CSS side by not cleaning up rules. But if we were required to keep things lean and clean, then the pain would be the same.