Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

CSS at scale

CSS at scale

A little reminder about how CSS let's you do shit and how you should embrace the BEM methodology to make your code easy to read and write. (sorry for the crappy PDF export 😬)

Matthias Le Brun

June 24, 2015
Tweet

More Decks by Matthias Le Brun

Other Decks in Programming

Transcript

  1. Les problèmes de CSS 1. Les selecteurs sont des variables

    globales .selector { font-size: 1rem; } = window.selector = { fontSize: "1rem", }
  2. Les problèmes de CSS 2. La cascade .nav { font-size:

    0; } .nav .item { display: inline-block; /* font-size is 0 */ }
  3. Les problèmes de CSS 3. La spécificité * {} /*

    specificity = 0,0,0,0 */ li {} /* specificity = 0,0,0,1 */ li:first-line {} /* specificity = 0,0,0,2 */ ul li {} /* specificity = 0,0,0,2 */ ul ol+li {} /* specificity = 0,0,0,3 */ h1 + *[rel=up]{} /* specificity = 0,0,1,1 */ ul ol li.red {} /* specificity = 0,0,1,3 */ li.red.level {} /* specificity = 0,0,2,1 */ #x34y {} /* specificity = 0,1,0,0 */ style="" /* specificity = 1,0,0,0 */ !important /* specificity = P,T,D,R */
  4. Les problèmes de CSS 4. L'annulation de propriétés .item {

    display: block; font-size: 1rem; color: blue; /* un dev vient de rajouter la propriété `border` */ border: 1px solid red; } .some-context .item { display: inline-block; color: red; /* regression dans .some-context */ }
  5. Les problèmes de CSS 5. La priorisation .blue { color:

    blue; } .red { color: red; } <!-- aucun contrôle au niveau du markup --> <div class="blue red">text</div> <div class="red blue">text</div>
  6. Les problèmes de CSS En résumé Un langage sans scope

    qui transmet automatiquement toute propriété d'un sélecteur à ses descendants qui priorise les sélecteurs comme un ivrogne qui est régression-friendly™ qui rend impossible la prédictabilité de priorisation à grande échelle
  7. Ce qui n'aide pas non plus 1. @extend .blue {

    color: blue; } .red { color: red; } .my-selector { @extend .red; @extend .blue; }
  8. Ce qui n'aide pas non plus 2. Les «CSS atomiques»

    .block { display: block; } .inline-block { display: inline-block; } .relative { position: relative; } .absolute { position: absolute; } .static { position: static; } .padding-10 { padding: 10px; }
  9. Ce qui n'aide pas non plus 2. OOCSS, SMACSS …

    Approches compliquées à apprendre à une équipe junior Différents niveaux non adaptés à un découpage en composants (layout, module, theme …)
  10. BEM Block Element Modifier <div class="Header"> <div class="Header-nav"> <div class="Nav">

    <a href="/" class="Nav-item Nav-item--active"> Home </a> <a href="/about" class="Nav-item"> About </a> </div> </div> </div>
  11. BEM Block le Block représente un composant Il peut être

    utilisé sans contexte particulier Il peut avoir son private tree Il peut avoir un état local (e.g. .Button--small) Cet état est appliqué par un «Modifier»
  12. BEM Element L'Element est un bloc appartenant au private tree

    de son ancêtre Block Il peut avoir un état local (e.g. .Nav-item--active)
  13. BEM Block Element Modifier Une façon de structurer sainement son

    app/site Des règles minimales Un nœud pouvant exister sans dépendre d'un ancêtre est un Block .Block Un nœud pouvant n'exister qu'en tant que descendant d'un ancêtre N est un element du Block N .Block-element Un état local pour un Block ou un Element est défini par un modifier de ce Block ou Element.Block--modifier ou .Block-element--modifier
  14. BEM Block Element Modifier: aller plus loin Dans le cas

    où un block est enfant d'un autre block, préférer le wrapping à la composition <!-- bad --> <div class="Header"> <div class="Header-nav Nav"><!-- ... --></div> </div> <!-- good --> <div class="Header"> <div class="Header-nav"> <div class="Nav"><!-- ... --></div> </div> </div>
  15. BEM Block Element Modifier: aller plus loin Prefixer les classNames

    par le nom de l'organisation, afin de prévenir les conflits avec le third-party <div class="org-Header"> <div class="org-Header-nav"> <div class="org-Nav"><!-- ... --></div> </div> </div>
  16. BEM Block Element Modifier: aller plus loin Éviter les side

    effects de la cascade en définissant les propriétés au niveau le plus bas possible /* bad */ .Nav { font-size: 2rem; } .Nav-item { padding: .5rem; } /* good */ .Nav {} .Nav-item { font-size: 2rem; padding: .5rem; }
  17. BEM Block Element Modifier: aller plus loin Si votre stack

    vous impose des selecteurs pour les actions JS, utilisez des classNames uniquement prévus à cet effet <button class="org-Button org-Button--small org-js-OpenLoginModal"> Login </button>
  18. BEM Block Element Modifier: aller plus loin Ne groupez jamais

    les media queries, gardez les toujours près des déclarations qu'elles complètent/override .Nav {} .Nav-item { font-size: 2rem; } @media(--maxM) { .Nav-item { font-size: 1.5rem; } }
  19. BEM Block Element Modifier: les avantages Rend triviale la compréhension

    du markup et du style Crée rapidement des automatismes Apporte naturellement l'isolation des styles Permet d'éliminer facilement le code legacy Permet de repérer les différents niveaux de legacy en changeant de préfixe
  20. Next steps Inline styles BEM résoud beaucoup de soucis, mais

    pas le contrôle de la priorisation JavaScript + la propriété style nous le permettent + variables, conditions, modules …
  21. Next steps Inline styles import React, {Component} from "react" import

    {lighten, darken} from "color" import styleVariables from "stylesVariables" const styles = { button: { display: "block", font-weight: 700, }, buttonDefault: { backgroundColor: styleVariables.colorBlue, }, buttonHover: { backgroundColor: lighten(styleVariables.colorBlue, .1), }, buttonPressed: { backgroundColor: darken(styleVariables.colorBlue, .1),
  22. backgroundColor: darken(styleVariables.colorBlue, .1), }, } export class extends Component {

    state = { hover: false, pressed: false, } render() { const {text} = this.props const {hover, pressed} = this.state return ( <div style={{ ...styles.button, ...styles.buttonDefault, ...hover && styles.buttonHover, ...pressed && styles.buttonPressed, }}> {text} </div>
  23. Next steps Inline styles: events import React, {Component} from "react"

    import {lighten, darken} from "color" import styleVariables from "stylesVariables" const styles = { button: { display: "block", font-weight: 700, }, buttonDefault: { backgroundColor: styleVariables.colorBlue, }, buttonHover: { backgroundColor: lighten(styleVariables.colorBlue, .1), }, buttonPressed: { backgroundColor: darken(styleVariables.colorBlue, .1),
  24. backgroundColor: darken(styleVariables.colorBlue, .1), }, } export class extends Component {

    state = { hover: false, pressed: false, } handleMouseEnter() { this.setState({ hover: true, }) } handleMouseLeave() { this.setState({ hover: false, }) } handleMouseDown() {
  25. handleMouseDown() { this.setState({ pressed: true, }) } handleMouseUp() { this.setState({

    pressed: false, }) } render() { const {text} = this.props const {hover, pressed} = this.state return ( <div onMouseEnter={() => this.handleMouseEnter()} onMouseLeave={() => this.handleMouseLeave()} onMouseDown={() => this.handleMouseDown()} onMouseUp={() => this.handleMouseUp()} style={{ ...styles.button,
  26. Next steps Inline styles: bénéfices Permet de prioriser les styles

    Possède naturellement des fonctions comme first class citizen JavaScript dispose déjà d'un outillage intéressant pour l'analyse de code Rend possible la cohabitation de style & markup dans le même fichier (tout comme avec des WebComponents) Abolit la spécificité des selecteurs Évite au browser de parser la page pour dresser la correspondance selector/element