Dariusz Winkler

Functional CSS

What's all the hype about?

Reusability

Adaptability

Readability

Scalability

Performance

Maintainability

  • Reusability
  • Adaptability
  • Readability
  • Scalability
  • Performance

Methodologies

  • BEM (Blocks, Elements, Modifiers)
  • SMACSS (Scalable and Modular Architecture for CSS)
  • OOCSS (Object-Oriented CSS)
  • Functional CSS

BEM

  • Block: Standalone entity.
  • Element: A part of a block.
  • Modifier: A flag on a block or element.
.block {}
.block__element {}
.block__element--modifier {}
<form class="form">
  <input class="form__input form__input--disabled" />
</form>

Reusable and adaptable

1. Duplicate styles

.article-preview
  .article-preview__image
  .article-preview__content
    .article-preview__title
    .article-preview__body
  • Adaptable
  • Not reusable, not DRY*

* Don’t Repeat Yourself

2. CSS Preprocessor

@extend or mixin

.article-preview          { @extend .author-bio; }
.article-preview__image   { @extend .author-bio__image; }
.article-preview__content { @extend .author-bio__content; }
.article-preview__title   { @extend .author-bio__name; }
.article-preview__body    { @extend .author-bio__body; }
  • ? Adaptable
  • ? Reusable

3. Content-agnostic component

.media-card
  .media-card__image
  .media-card__content
    .media-card__title
    .media-card__body
  • Reusable, DRY
  • ? Adaptable
  • ? Semantic?

Semantic class names

“[…] authors are encouraged to use values that describe the nature of the content, rather than values that describe the desired presentation of the content.”

w3.org


.bold        { font-weight: bold }  /* presentational */
.author-name { font-weight: bold }  /* semantic       */

“HTML is for content. CSS is for styling. Separate your concerns.”

Frontend developers
<div class="profile-wrapper">
  <div class="profile">
    <div class="profile-name-wrapper">
      <div class="profile-name">Alex</div>
    </div>
  </div>
</div>

Separation of Concerns?

“Semantic” classnames

“Separation of concerns”

CSS depends on HTML

HTML is restyleable!

Presentational classnames

“Mixing concerns”

HTML depends on CSS

CSS is reusable!

Neither approach is “wrong”.

Functional CSS

“… is the approach to CSS architecture that favors small, single-purpose classes with names based on visual function.”

Also known as

.position-relative { position: relative }
.display-block     { display: block }
.border            { border: 1px solid #ccc }
.text-center       { text-align: center}
.font-weight-bold  { font-weight: bold }
.red               { color: red }
.font-16 { font-size: 16px }
.font-20 { font-size: 20px }
.font-28 { font-size: 28px }
.margin-1   { margin: 0.5rem }
.margin-2   { margin: 1rem }
.margin-3   { margin: 2rem }
.margin-x-2 { margin-left: 1rem; margin-right: 1rem }

Wait, what?

  • ? Adaptable
  • ? Reusable

  • Adaptable
  • Reusable

Functional CSS

  • Immutable
  • Predictable
  • Pure (no side effects)
  • Composable

Favors composition over inheritance

Context switching & Side effects

No context switching
No side effects

The older your codebase is
the less CSS you will write.

Productivity Boost

Naming is hard

There are 2 hard problems in computer science: cache invalidation, naming things, and off-by-1 errors.


Naming utility classes is straightforward.

.margin-top-0 { margin-top: 0 }  /* favors readability */
.mt-0         { margin-top: 0 }  /* favors brevity     */
<div class="profile-wrapper">
  <div class="profile-wrapper__name">Alex</div>
</div>

<div class="flex">
  <div class="flex-1">Alex</div>
</div>

“You know how many times I’ve had to think of a name for a random container that exists simply to align some crap?”

Hacker News

CSS specifity & order

<a class="nav-item link" href="#">Link</a>
.link     { color: blue }
.nav-item { color: red }

Portability

  • Custom spacing, typography, colors and breakpoints per project
  • Same CSS classes for every project
  • Cross-team consistency

Adaptability

“Turn all red buttons blue”
  • Issue not dependent on any CSS architecture
  • Use templates / components
<button class="bg-blue-500 hover:bg-blue-700 text-white
               font-bold py-2 px-4 rounded">
  <%= label %>
  <% if (icon) { %>
    <%= icon %>
  <% } %>
</button>
  • Search and replace
  • Extract common component (.btn, .modal)

Utility-first

  • No more premature abstraction
  • No unnecessary bloat and complexity
  • Mix with other methodologies
  • TailwindCSS @apply:
<button class="btn-blue">Button</button>

<style>
  .btn-blue {
    @apply bg-blue-500 text-white font-bold py-2 px-4 rounded;
  }
</style>

“It’s just inline styles”

<h2 style="font-size: 16px; font-weight: bold; color: purple">
  Breaking Bad
</h2>
<h2 class="font-16 font-bold font-purple">
  Breaking Bad
</h2>
Why are inline styles bad?
Are both patterns equal?

“It’s just inline styles”

<h2 style="font-size: 16px; font-weight: bold; color: purple">
  Breaking Bad
</h2>
<h2 class="font-16 font-bold font-purple">
  Breaking Bad
</h2>
  • 1 to 1 (inline) vs. 1 to many (classes)
    • Inconsistencies
  • Specifity
  • Media queries, pseudo elements

Media Queries

  • Flexbox container
  • Column direction on mobile
  • Row direction on desktop
<div class="flex flex-column flex-md-row">
  <div>Element 1</div>
  <div>Element 2</div>
</div>

HTML bloat

<div class="mt-4 md:mt-0 md:ml-6 w-64">
  <h3 class="uppercase tracking-wide text-sm text-indigo-600">
    Marketing
  </h3>
  <a href="/pricing.html"
     class="block mt-1 text-lg leading-tight font-semibold
            text-gray-900 hover:underline">Pricing</a>
  <p class="mt-2 text-gray-600">
    Get the best offer for your business
  </p>
</div>
  • “It’s ugly”
  • “It’s bloated”
  • “It’s unreadable”

Theming

  • .margin-20 .margin-3
  • .font-16 .font-300 / .font-medium
  • .color-blue .color-primary

Use abstract over absolute units

Learning curve

  • Every methodology requires a style guide
  • Functional classes are self-describing
  • Cross-team knowledge

Performance: Expensive selectors

/* expensive */
header#admin-main-header.header--bar-right-part li > a {
  line-height: 35px
}

/* cheap */
.line-height-2 { line-height: 35px }

Performance: File size

  • File size over time
  • CSS vs. HTML
  • Caching
  • GZip compression

Unused CSS

  • TailwindCSS (before compression):
    • Default: 1.42 MB, 20.000 rules
  • Import only used CSS
    • My config: 15 KB, 610 rules
  • Remove unused CSS:

Autocomplete

CSS styles

CSS classes

Locating and selecting components

Frameworks

In the wild

My experience: Enterprise project

  • Based on Bootstrap
  • Gradual shift to utility-heavy usage
  • Good for theming, not good for brand-specific designs

My experience: Personal project

  • Great developer experience
  • 35 React components
  • 6 component-specific stylesheets
    • Button, Icon, Loading, …
  • 2 color themes

Facebook Redesign

  • 2 MB uncompressed CSS (400 KB compressed). 10% used for initial render.
  • Difficult to identify if various CSS rules were still in use.
  • Changes in one file could break the styles in another without the author realizing it.
  • CSS precedence depends on ordering.
⇒ Generating Atomic CSS at build time.

https://engineering.fb.com/web/facebook-redesign/

No silver bullet

  • Tooling required for best performance
  • Templating recommended
  • Not suitable for highly individual themes
  • Often not suitable for styling 3rd-party components
  • Most UI Frameworks don’t use Functional CSS

If you love the way you write CSS and don’t want to change…

then don’t.

… but

“You have to be prepared to disgard old ideas, look at alternatives, and even revisit ways that you may have previously dismissed.”

Nicolas Gallagher

Resources

Thank you!

darekkay.com / presentations
Dariusz Winkler