CSS-in-JS The good or the evil? Andrey Okonetchnikov - - PowerPoint PPT Presentation

β–Ά
css in js
SMART_READER_LITE
LIVE PREVIEW

CSS-in-JS The good or the evil? Andrey Okonetchnikov - - PowerPoint PPT Presentation

CSS-in-JS The good or the evil? Andrey Okonetchnikov @okonetchnikov ColorSnapper http://colorsnapper.com Past Current time Future A brief history of CSS CSS was designed for documents How many of you have ever re-designed a web-site


slide-1
SLIDE 1

CSS-in-JS

The good or the evil?

slide-2
SLIDE 2

Andrey Okonetchnikov

@okonetchnikov

slide-3
SLIDE 3
slide-4
SLIDE 4

ColorSnapper

http://colorsnapper.com

slide-5
SLIDE 5

Past Current time Future

slide-6
SLIDE 6

A brief history of CSS

slide-7
SLIDE 7

CSS was designed for documents

slide-8
SLIDE 8
slide-9
SLIDE 9
slide-10
SLIDE 10
slide-11
SLIDE 11
slide-12
SLIDE 12

How many of you have ever re-designed a web-site with CSS changes only?

βœ‹

slide-13
SLIDE 13

CSS was designed for documents, not for web-applications

slide-14
SLIDE 14
slide-15
SLIDE 15
slide-16
SLIDE 16
slide-17
SLIDE 17

Best practices

slide-18
SLIDE 18

Separation of concerns

JS CSS HTML

slide-19
SLIDE 19

Separation of concerns

JS CSS HTML Checkbox Button Dropdown List Modal

slide-20
SLIDE 20

UI Components

Button

slide-21
SLIDE 21

UI Components

Button

slide-22
SLIDE 22
  • Logic
  • HTML
  • Styles

Button

  • Logic
  • HTML
  • Styles
  • Logic
  • HTML
  • Styles
slide-23
SLIDE 23

Past Current time Future

slide-24
SLIDE 24

HTML-in-JS

a.k.a. JSX

slide-25
SLIDE 25
slide-26
SLIDE 26
slide-27
SLIDE 27
slide-28
SLIDE 28
slide-29
SLIDE 29

https://trends.google.com/trends/explore?q=%2Fm%2F012l1vxv,%2Fm%2F0268gyp

slide-30
SLIDE 30
slide-31
SLIDE 31

Everything is a component!

slide-32
SLIDE 32

f(state) =? UI

slide-33
SLIDE 33

What about styles?

slide-34
SLIDE 34
  • Logic
  • HTML
  • Styles

Button

  • Logic
  • HTML
  • Styles
  • Logic
  • HTML
  • Styles
slide-35
SLIDE 35
  • Logic
  • HTML
  • Styles

Button

  • Logic
  • HTML
  • Styles
  • Logic
  • HTML
  • Styles
slide-36
SLIDE 36
  • Logic
  • HTML
  • Styles

Button

  • Logic
  • HTML
  • Styles
  • Logic
  • HTML
  • Styles

Global styles

slide-37
SLIDE 37
slide-38
SLIDE 38

Global CSS

1 .btn { 2 /+ styles for button *0 3 } 4 5 .active { 6 /+ styles for active button *0 7 background-color: blue; 8 } 9 10 .label { 11 /+ styles for button label *0 12 } 1 .star { 2 /+ styles for star *0 3 } 4 5 .active { 6 /+ styles for active star *0 7 background-color: orange; 8 } 9

πŸ’¦

slide-39
SLIDE 39

.btn.active

slide-40
SLIDE 40

.content .albums .album .btn

slide-41
SLIDE 41
slide-42
SLIDE 42

BEM

https://en.bem.info/

slide-43
SLIDE 43

.Block .Block-.element .Block-.element__modifier

B E M Block Element Modifier

slide-44
SLIDE 44

Without BEM

<button class="button active"> <span class="label"> Click me! <0span> <0button>

slide-45
SLIDE 45

With BEM

<button class="Button Button__active"> <span class="Button-.label"> Click me! <0span> <0button>

slide-46
SLIDE 46

BEM prevents this!

slide-47
SLIDE 47

Manual work

slide-48
SLIDE 48

<ul class="nav"> <li class="nav__item nav__item_active"><a class="nav__link">One<0a><0li> <li class="nav__item"><a class="nav__link">Two<0a><0li> <li class="nav__item"><a class="nav__link">Three<0a><0li> <0ul>

slide-49
SLIDE 49

.nav__item { padding: 4px 10px; color: black; } .nav__item_active { font-weight: bold; background: #ffc7c7; } .navigation__item { padding: 4px 10px; color: black; } .navigation__item_active { font-weight: bold; background: #ffc7c7; }

slide-50
SLIDE 50
slide-51
SLIDE 51
slide-52
SLIDE 52

Manual work

slide-53
SLIDE 53

https://github.com/css-modules/css-modules

slide-54
SLIDE 54

Before: BEM-style

const Button = ({ children }) =? ( <button className="Button"> <span className="Button__label"> { children } <0span> <0button> )

slide-55
SLIDE 55

After: CSS-modules

import styles from './Button.css' const Button = ({ children }) =? ( <button className={styles.button}> <span className={styles.label}> { children } <0span> <0button> )

slide-56
SLIDE 56

CSS-modules

βœ… Explicit imports βœ… Scoped & fast selectors βœ… True rules isolation βœ… Code reuse, expressiveness βœ… Framework agnostic 🚬 Non standard syntax (compose, vals, etc.) 🚬 Build step is required 🚬 No dead code elimination 🚬 No automatic vendor prefixing

slide-57
SLIDE 57

https://cssinjs.org

slide-58
SLIDE 58

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

slide-59
SLIDE 59

Before: BEM-style

const Button = ({ children }) =? ( <button className="Button"> <span className="Button__label"> { children } <0span> <0button> )

slide-60
SLIDE 60

After: JSS

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

slide-61
SLIDE 61

CSS-in-JS (JSS)

βœ… Explicit imports βœ… Scoped & fast selectors βœ… True rules isolation βœ… Code reuse, expressiveness βœ… Framework agnostic βœ… Uses w3c standard βœ… No build step is required βœ… Dead code elimination βœ… Automatic vendor prefixing

slide-62
SLIDE 62

–Max or Glenn, probably?

β€œIf we generate class names, why do we still use class attribute?”

slide-63
SLIDE 63

Natural mapping

The Design of Everyday Things by Don Norman

slide-64
SLIDE 64

Natural mapping

slide-65
SLIDE 65

https://www.styled-components.com/

slide-66
SLIDE 66

/0 Create a Title component that'll render an <h1> tag with some styles const Title = styled.h1` font-size: 1.5em; text-align: center; color: palevioletred; `; render( <Title> Hello PiterCSS! <0Title> );

slide-67
SLIDE 67

const Button = styled.button` /+ Adapt the colours based on primary prop *0 background: ${props =? props.primary ? 'palevioletred' : 'white'}; color: ${props =? props.primary ? 'white' : 'palevioletred'}; font-size: 1em; margin: 1em; padding: 0.25em 1em; border: 2px solid palevioletred; border-radius: 3px; `; render( <div> <Button>Normal<0Button> <Button primary>Primary<0Button> <0div> );

slide-68
SLIDE 68

β€œstyled-components […] removes the mapping between components and styles.”

https://www.styled-components.com/

slide-69
SLIDE 69

πŸ’†styled-components

βœ… No messing with classNames (implementation detail) βœ… Same mental model and structure for the whole application

slide-70
SLIDE 70

And because the model is the same…

slide-71
SLIDE 71

πŸ’†styled-components for react-native!

import styled from 'styled-components/native'; const StyledView = styled.View` background-color: papayawhip; `; const StyledText = styled.Text` color: palevioletred; `; class MyReactNativeComponent extends React.Component { render() { return ( <StyledView> <StyledText>Hello World!<0StyledText> <0StyledView> ) } }

slide-72
SLIDE 72

– https://www.cooper.com/journal/2012/08/the-best-interface-is-no-interface

β€œNo UI is about machines helping us, instead of us adapting for computers.”

slide-73
SLIDE 73

Myths & Lies

slide-74
SLIDE 74

CSS-in-JS is slow

slide-75
SLIDE 75

CSS-in-JS β‰  inline styles!

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

slide-76
SLIDE 76

http://cssinjs.org/function-values/

slide-77
SLIDE 77

Maintanability > Speed

slide-78
SLIDE 78

https://twitter.com/dan_abramov/status/842329893044146176

slide-79
SLIDE 79
slide-80
SLIDE 80
slide-81
SLIDE 81

http://slides.com/malyw/houdini-codemotion#/16

slide-82
SLIDE 82
slide-83
SLIDE 83

import React from 'react' import { createComponent } from 'react-fela' import felaSnapshot from './test-helpers/felaSnapshot.js' const boxRules = ({ size = 10 }) =? ({ width: size + 'px', height: size + 'px', backgroundColor: 'red' }) const Box = createComponent(boxRules) describe('Box', () =? { it('should render component', () =? { const snapshot = felaSnapshot(<Box>hello<0Box>) expect(snapshot).toMatchSnapshot() }) })

slide-84
SLIDE 84

exports[`Box should change box size when size prop is passed 1`] = ` <div className="a b c" id={undefined} style={undefined} > hello <0div> `;

slide-85
SLIDE 85

Crafted CSS is better for performance

slide-86
SLIDE 86
slide-87
SLIDE 87

https://meiert.com/en/blog/20170531/70-percent-css-repetition/

β€œIn CSS, we repeat ourselves too much. While it’s absolutely, practically possible to limit declaration repetition to 10–20%, reality averages 72% (median 66%).”

slide-88
SLIDE 88

β˜‘Use functional CSS

slide-89
SLIDE 89

https://acss.io

slide-90
SLIDE 90

Atomic CSS

<div class="Pos(a) Bgc(brandColor) W(columnWidth) H(90px)"><0div> <div class="C(brandColor) BdB Bdc(brandColor) Mstart(columnWidth) P(10px)"> Lorem ipsum <0div>

slide-91
SLIDE 91
slide-92
SLIDE 92

http://tachyons.io

slide-93
SLIDE 93

Tachyons

<article class="pa3 pa5-ns"> <h1 class="f3 f1-m f-headline-l">Title<0h1> <p class="measure lh-copy"> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. <0p> <0article>

slide-94
SLIDE 94
slide-95
SLIDE 95
slide-96
SLIDE 96

Manual work

slide-97
SLIDE 97
slide-98
SLIDE 98

Enables CSS optimisations

slide-99
SLIDE 99

but still very easy to use API

import {styled} from 'styletron-react'; const Panel = styled('div', (props) =? ({ backgroundColor: props.alert ? 'orange' : 'lightblue', fontSize: '12px' })); <Panel alert>Danger!<0Panel>

slide-100
SLIDE 100

airbnb.com CSS output size

slide-101
SLIDE 101

βœ…Use Generate functional CSS

slide-102
SLIDE 102
slide-103
SLIDE 103

SASS has variables, mixins, etc.

slide-104
SLIDE 104

JavaScript SASS has variables, mixins functions

slide-105
SLIDE 105

https://una.im/sass-es2015/#πŸ’‚

slide-106
SLIDE 106

Variables

let color = "red"; $color: "red";

slide-107
SLIDE 107

Lists

const colorArray = ["red", "yellow", "green"]; for (const color of colorArray) { console.log(color); } $colorList: "red", "yellow", "green"; @each $color in $colorList { @debug $color; }

slide-108
SLIDE 108

Functions

function PrintMe(firstArg, ../theRest) { console.log(firstArg, theRest); } PrintMe('Hello', 'You', 'Look', 'Nice');

@mixin funCircle($size, $gradient../) { width: $size; height: $size; border-radius: 50%; background: radial-gradient($gradient); } .entrancing { @include funCircle(50px, blue 10%, red 80% ,pink); }

slide-109
SLIDE 109

https://polished.js.org/

slide-110
SLIDE 110

/0 Styles as object usage const styles = { background: lighten(0.2, '#CCCD64'), background: lighten(0.2, 'rgba(204,205,100,0.7)'), } /0 styled-components usage const div = styled.div` background: ${lighten(0.2, '#FFCD64')}; background: ${lighten(0.2, 'rgba(204,205,100,0.7)')}; ` /0 Output element { background: "#e5e6b1"; background: "rgba(229,230,177,0.7)"; }

slide-111
SLIDE 111

Just use the platform*!

* Or, just Google Chrome?

slide-112
SLIDE 112
slide-113
SLIDE 113
slide-114
SLIDE 114
slide-115
SLIDE 115
slide-116
SLIDE 116
slide-117
SLIDE 117

styled-jsx

export default () =? ( <div> <p>only this paragraph will get the style :)<0p> { /+ you can include <Component /?s here that include

  • ther <p>s that don't get unexpected styles! *0 }

<style jsx>{` p { color: red; } `}<0style> <0div> )

slide-118
SLIDE 118

styled-jsx

import _JSXStyle from 'styled-jsx/style' export default () =? ( <div data-jsx='cn2o3j'> <p data-jsx='cn2o3j'>only this paragraph will get the style :)<0p> <_JSXStyle styleId='cn2o3j' css={`p[data-jsx=cn2o3j] {color: red;}`} /? <0div> )

slide-119
SLIDE 119
slide-120
SLIDE 120

To complicated to setup

slide-121
SLIDE 121

How many of you know how to extract critical CSS or doing that?

βœ‹

slide-122
SLIDE 122

Critical CSS with <πŸ’†>

import { renderToString } from 'react-dom/server' import { ServerStyleSheet } from 'styled-components' const sheet = new ServerStyleSheet() const html = renderToString(sheet.collectStyles(<YourApp /?)) const css = sheet.getStyleTags()

slide-123
SLIDE 123

https://medium.com/seek-blog/a-unified-styling-language-d0c208de2660

β€œ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.”

slide-124
SLIDE 124

Past Current time Future

slide-125
SLIDE 125

Universal rendering

slide-126
SLIDE 126
slide-127
SLIDE 127

import React from 'react'; import {AppRegistry, Pano, Text, View} from 'react-vr'; class WelcomeToVR extends React.Component { render() { /0 Displays "hello" text on top of a loaded 360 panorama image. /0 Text is 0.8 meters in size and is centered three meters in front of you. return ( <View> <Pano source={asset('chess-world.jpg')}/? <Text style={{ fontSize: 0.8, layoutOrigin: [0.5, 0.5], transform: [{translate: [0, 0, -3]}], }}> hello <0Text> <0View> ); } }; AppRegistry.registerComponent('WelcomeToVR', () =? WelcomeToVR);

slide-128
SLIDE 128
slide-129
SLIDE 129
slide-130
SLIDE 130

πŸ’†styled-components for Sketch!

slide-131
SLIDE 131
slide-132
SLIDE 132
slide-133
SLIDE 133

Design systems shared between designers and developers!

slide-134
SLIDE 134
slide-135
SLIDE 135

Final thoughts

slide-136
SLIDE 136
slide-137
SLIDE 137

β€œCSS-in-JS enforces the best practices trough technology and shared knowledge.”

slide-138
SLIDE 138

βœŒπŸ’—πŸ¦…

slide-139
SLIDE 139

Thank you!

slide-140
SLIDE 140

Andrey Okonetchnikov

@okonetchnikov http://okonet.ru https://github.com/okonet

UI Engineer @ Feedly