Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

The Cascade is Dead


Published on

With the advent of CSS-in-JS, the cascade is less and less relevant to developers, but there's a lot that stylesheets have to offer. In this presentation, Chris Eppstein discusses the new Stylesheet framework and optimizer that LinkedIn is building.

Published in: Software
  • Be the first to comment

The Cascade is Dead

  1. 1. THE CASCADE IS DEAD Long Live Style Sheets!
  2. 2. “ ” Every presentation about CSS architecture is, at its essence, a talk about how to manage the cascade. — Christopher Eppstein, November 10, 2017, Web directions Summit This talk is no exception 🙄
  4. 4. BENEFITS OF CSS-IN-JS According to Mark  Scoped styles  Critical CSS  Smarter optimizations  Package management  Non-browser styling I think there are more:  No meaningful cascade  Anonymous rule sets.  Determining styles for an element is straightforward  Deleting an element deletes the styles.
  5. 5. APOLOGIES IN ADVANCE This talk is less polished than I'd like…
  6. 6. WE HAD SOME PROBLEMS WITH OUR CSS AT LINKEDIN…  Before even launching: Our new single-page app had 3.2 MB of CSS.  Selector specificity was out of control and was measurably impacting site speed.  Designs & implementations that were out of compliance with the design system.  Hard for apps to down-level their style patterns to the design system. Our styles had become slow & bloated.
  7. 7. WE HAD CONSTRAINTS ON OUR POSSIBLE SOLUTIONS…  Design System for dozens of apps built in different tech stacks and of varying architectures.  Pure css/scss deliverable for legacy apps.  Make performance a 1st order consideration.  Where a trade-off must be made, prefer runtime performance to developer experience.  Support for Ember Applications Your constraints may be different!
  8. 8. WE DECIDED ON THE PROPERTIES OF AN IDEAL SOLUTION…  Solution should empower engineers to scale down to third-world mobile. (~5k of CSS compressed)  Solution must scale up to hundreds of engineers on a single application.  Server-side rendering  Inline Critical Styles  Code splitting of CSS  Great developer experience  Empower Design Systems  Tree shaking It’s good to have goals.
  9. 9. AND I HAVE OPINIONS…  I’m generally worried that CSS-in-JS will make CSS less approachable to people with a design background.  CSS-in-JS leads to JS-in-CSS – because abstractions.  CSS-in-JS Is theoretically worse for performance.  Atomic CSS and other declaration-oriented systems create high-performance garbage.  THE_BEM__naming-system—is-atrocious Which, of course, is why I’m here today!
  10. 10. THE PLAN  Component-oriented selectors.  Build a Better BEM  And optimize shared declarations into shared rules styles.  Use build-time code transforms to maximize benefit from optimization.  Generate code split styles and  "uglyify" CSS idents to maximize gzip efficiency.
  11. 11. BUT DOESN'T DECLARATION MERGING BREAK THE CASCADE? Demo Sneak Peek Hey, you're pretty smart! It does, in fact, break the cascade, if you're not careful 
  12. 12. Blazing fast CSS for your design system and app components.
  13. 13. An analysis-driven optimizer for CSS and Markup
  14. 14. RESULTS SO FAR (in bytes) BEM BEM +Min OptiCSS OptiCSS + min Plain 61534 47913 29355 21467 gzip 10574 8992 7283 6340 brotli 8857 7814 6190 5481 CSS Code split for home page (prototyped) Yes. That’s less than 5% of what we’re currently sending on first page load after gzip. BEM BEM +Min OptiCSS OptiCSS + min Plain 100% 77.8% 47.7% 34.9% gzip 100% 85% 68.8% 60% brotli 100% 882% 69.9% 61.9% Current CSS Size of ~1.6MB, ~140kb gzip
  15. 15. OK BUT…  Does it handle dynamic style changes?  Is there runtime overhead?  What about the templates sizes?  Is it hard to use?  Is it hard to adopt? Seems too good to be true?
  16. 16. WHAT IS A BLOCK? A collection of related design elements and their various modes and interaction states.
  17. 17. DEFINING A BLOCK  Block Root – The class for the root element of the block’s document subtree.  Block State – A state that the entire block can be in. Can affect the classes and the states of those classes.  Class – Indicates a type of element that is styled within the block.  Class State – A state that the class can be in. Only affects the elements of that class. Every block must be in it’s own file. Classes are "nouns", States are "adjectives"
  18. 18. A BLOCK IS AN INTERFACE TO A DESIGN CONCEPT  The existence of Classes and States are inferred from the selectors that implement them.  A block can inherit from another block.  Classes and states of the same name inherit from the classes and states of that same name in the base block.  Additional classes and states can be added.  A block can implement another Block’s interface The selectors and properties are implementation details.
  20. 20. BLOCK SYNTAX Classes  Literally a CSS class name.  A special class .root styles the block’s root element. States  An attribute selector for an attribute in the state namespace.  The attribute value is optional.  Only the = attribute operator is allowed.  States for a class are a compound selector of the state attribute and the class.
  21. 21. RULES FOR AUTHORING A BLOCK’S STYLES  Key selector must target a single block or class, or a pseudo-element of one.  Any number of states and pseudo-classes for the target block or class are allowed.  Selectors may be contained within an @-rule.  Combinators are forbidden except when the context selector is one or more block-level states.  !important is forbidden. The rules are basically BEM’s rules for selectors. !important isn’t necessary. These rules help minimize coupling.
  22. 22. MARKUP RULES  You may not use a block class outside of the root element's HTML subtree.  Two classes from the same block may not be applied to the same HTML element. While not required for optimization, these rules exist to keep the definitions of what is a root, class or state clear.
  23. 23. BLOCK-SPECIFIC SYNTAX  @block-reference my-block from "subdir/my.block.css";  Special properties for .root:  implements: block-name, other-block;  extends: block-name;  block-name: preferred-name;  @block-global [state|is-loading];  .class { @is-block <block-name>[state|foo]; }  @block-debug <block-name> to (comment|stderr|stdout) Some concepts for blocks require specialized syntax. This syntax is always removed from the CSS output.
  24. 24. BLOCK-SPECIFIC SYNTAX Are you ready? It's time to kill the cascade. To resolve property conflicts across blocks we use the special resolve() function. "Override" Resolution
  25. 25. BLOCK-SPECIFIC SYNTAX To resolve property conflicts across blocks we use the special resolve() function. The source order of the resolve declaration determines the winner. "Yield" Resolution
  26. 26. CONFLICT RESOLUTION  During analysis, two styles from different blocks on the same block element setting the same CSS property to different values is an error until it is resolved.  Shorthand aware. Initial value aware. Progressive-enhancement aware.  The ruleset generated by a resolve() is removed by the optimizer and the rewriter will use the correct class(es) even across optimizations that merge declarations. Resolve declarations are what make CSS-Blocks work and what makes it so optimizable.
  27. 27. CONFLICT RESOLUTION  Because resolution is property-based two properties from the same rulesets can have different resolution outcomes (override vs. yield)  Wildcard syntax for resolving the same property from different conflicting styles. Flexibility the cascade can't offer.
  28. 28. RESOLUTION CONSTRAINTS When resolving a property, css- blocks lets you prevent being overridden or control the possible override values.
  29. 29. INHERITANCE Inheritance doesn't change※ the CSS output.
  30. 30. INHERITANCE ※ Inheritance is modeled as automatic resolution.
  31. 31. PREPROCESSOR INTEGRATION Sass • Read contents CSS • Optional pre-processesor if extension isn't CSS CSS • Optional CSS Post Processor So maybe you've heard of Sass… CSS-Blocks works with any preprocessor.
  32. 32. TEMPLATE INTEGRATION  Current Implementations:  Handlebars/Glimmer  JSX (classnames-style)  Planned Implementations:  Handlebars/Ember  Vue  JSX (html-style) CSS-Blocks can be adapted to template and application framework's conventions and ethos to make it feel native to that framework.
  33. 33. HANDLEBARS  A CSS block file is associated by convention with each template and controller.  The block identifiers from @block-reference directives in that block expose that name as a block scope in the template. Classes and states are set on elements. The class attribute uses a special style-if/style- unless helpers.
  34. 34. JSX Style expressions are function calls✻ to a styles function that returns✻ optimized styles. ✻ it's actually rewritten during the build.
  35. 35. PASSING STYLES TO A COMPONENT  A Block is used to style a component and the relationships to its styles with other blocks are analyzed within a component boundary.  A component parameter can accept a block reference that inherits from or implements the block.  The analysis of the base block can be applied to the passed block. Functional boundaries are information boundaries. The unit of style is a block – that's what we pass.
  36. 36. HANDLING DYNAMISM Output classes are modeled as arbitrarily nested boolean expressions over presence of the class names set originally. CSS classes CSS-Block Styles Conditional expressions Optimized Class names
  37. 37. HANDLEBARS The optimizer gives instructions to the rewriter for what classes should be active and when according to the dynamic behavior of the element. The instructions (opcodes) encode the conditional expressions required to produce a runtime class list. <div class={{classnames 1 2 2 (isLoading) 1 1 "a" 0 "b" 1}}> <aside class={{classnames 0 4 "g" 0 "h" 1 "c" 2 "d" 3}}> </aside> <article class={{classnames 1 3 0 isRecommended 1 2 1 1 "i" 0 "e" 1 "f" 2}}> </article> </div>
  38. 38. OptiCSS  Markup Analysis Driven Optimizer for CSS  Handles Generic CSS, does not require CSS-Blocks  Configurable and Extensible
  39. 39. DEMO TIME!  Launch Demo
  40. 40. THE 1ST CSS-BASED ALTERNATIVE TO CSS-IN-JS. *whispers* You can even co-locate your styles in your JS file if that’s your thing.
  41. 41. BENEFITS OF CSS-IN-JS According to Mark  Scoped styles  Critical CSS  Smarter optimizations  Package management  Non-browser styling I think there are more:  No meaningful cascade  Anonymous rule sets.  Determining styles for an element is straightforward  Deleting an element deletes the styles.
  42. 42. CSS-Blocks + OptiCSS According to Mark  Scoped Styles  Critical CSS  Smarter Optimizations  Package Management ✗ Non-browser Styling I think there are more:  No meaningful (cross-component) cascade ✗ Anonymous Rule Sets (?)  Determining styles for an element is straightforward.  Deleting an element deletes its styles (at build time)
  43. 43. STATIC ANALYSIS IS FOR MORE THAN OPTIMIZATION  Override Analysis – Should a style stop setting a property or set it to something else?  Dead Code Removal – list styles that are never used, without running the app.  Correlation Analysis – should styles be combined? It unlocks a whole new world of tools for design. Are anonymous rulesets less important when our design abstractions are properly factored?
  44. 44. WRAPPING UP  LinkedIn  Adam Miller (  ☜ Sign up for Updates  Follow me on twitter: @chriseppstein
  45. 45. DECLARATION-ORIENTED STYLING  Atomic CSS (  Styletron (  Tailwind (  Tachyons (  Fela (
  46. 46. OPTIMIZATION TECHNIQUES  Identifiers  cutting-the-class-names-and-using-scope-isolation-625440de600b
  47. 47. BETTER BEMS 