Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Tu chiamalo se vuoi EmotionJS

Tu chiamalo se vuoi EmotionJS

Nella lotta ai vari modi di scrivere CSS, tra gemme ruby e utility atomiche, io ho trovato il mio vincitore. EmotionJS è un tool CSS-in-JS che permette in semplicità di scrivere 'stile in linea' e trasformarlo 'automagicamente' in classi univoche. Con un sacco di idee prese dai concorrenti come styled component, pieno supporto a TypeScript e un ecosistema ormai maturo, vedremo un paio di use case e come mai lo reputo il vincitore... per ora. Perché altri concorrenti come Vanilla-Extract potrebbero presto prendere il suo posto.

Davide Di Pumpo

April 01, 2022
Tweet

More Decks by Davide Di Pumpo

Other Decks in Technology

Transcript

  1. Chi sono Mi trovate ovunque col nick: @makhbeth Frontend @Tot.money

    CSS enthusiast Father of one (the best one)
  2. Agenda 1. Intro - già fatta 2. Come mai? -

    ma soprattutto perché? 3. Cos'è? - oltre al readme c'è di più 4. Trick AND treats! 5. È tutto oro quello che luccica?- lessons learned 6. Cosa c'è lì fuori? - il prossimo tool!
  3. 1 1 2 2 3 3 4 4 5 5

    6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19 20 20 21 21 22 22 23 23 export export const const neutral neutral: : Colors Colors = = { { main main: : { { lowest lowest: : '#1FB8A1' '#1FB8A1', , low low: : '#70EEDB' '#70EEDB', , neutral neutral: : '#28EBCD' '#28EBCD', , } }, , neutral neutral: : { { lowest lowest: : '#202020' '#202020', , low low: : '#202020' '#202020', , neutral neutral: : '#DEDEDE' '#DEDEDE', , high high: : '#F7F7F7' '#F7F7F7', , highest highest: : '#ffffff' '#ffffff', , } }, , skin skin: : { { lowest lowest: : '#BA926F' '#BA926F', , low low: : '#F3DCBC' '#F3DCBC', , neutral neutral: : '#FFEEDC' '#FFEEDC', , accent accent: : '#EDA6B4' '#EDA6B4', , } }, , accent accent: : { { neutral neutral: : '#F6D65D' '#F6D65D', , low low: : '#CCAA3E' '#CCAA3E', , } }
  4. There are only two hard things in Computer Science: cache

    invalidation and naming things. -- Phil Karlton
  5. 1 1 2 2 3 3 4 4 5 5

    6 6 7 7 8 8 9 9 10 10 11 11 12 12 const const style style = = css css` ` color color: : pink pink; ; padding padding: : 1 1rem rem; ; justify-content justify-content: : center center; ; align-items align-items: : center center; ; font-weight font-weight: : bold bold; ; font-size font-size: : 3 3rem rem; ; ` ` const const element element = = document document. .createElement createElement( ("div" "div") ) element element. .innerText innerText = = "CSS DAY!!!" "CSS DAY!!!" element element. .classList classList. .add add( (style style) ) document document. .body body. .appendChild appendChild( (element element) ) CSS DAY!!!
  6. 1 1 2 2 3 3 4 4 5 5

    6 6 7 7 8 8 9 9 10 10 11 11 < <div div className className= ={ {css css` ` color color: : pink pink; ; padding padding: : 1 1rem rem; ; justify-content justify-content: : center center; ; align-items align-items: : center center; ; font-weight font-weight: : bold bold; ; font-size font-size: : 3 3rem rem; ; ` `} }> > CSS DAY!!! CSS DAY!!! </ </div div> > CSS DAY!!!
  7. 1 1 2 2 3 3 4 4 5 5

    6 6 7 7 8 8 9 9 10 10 11 11 12 12 < <div div className className= ={ {css css` ` label label: : CSSDAY CSSDAY; ; color color: : pink pink; ; padding padding: : 1 1rem rem; ; justify-content justify-content: : center center; ; align-items align-items: : center center; ; font-weight font-weight: : bold bold; ; font-size font-size: : 3 3rem rem; ; ` `} }> > CSS DAY!!! CSS DAY!!! </ </div div> > CSS DAY!!!
  8. 1 1 2 2 3 3 4 4 5 5

    const const CSSDAY CSSDAY = = css css` `... ...` ` < <div div className className= ={ {CSSDAY CSSDAY} }> > CSS DAY!!! CSS DAY!!! </ </div div> > CSS DAY!!!
  9. Il senso non era non dare un nome alle cose?

    Ma c'è un plugin per tutto! https://emotion.sh/docs/@emotion/babel-plugin#labelformat const const brownStyles brownStyles = = css css( ({ { color color: : 'brown' 'brown' } }) ) ⬇ const const brownStyles brownStyles = = /*#__PURE__*/ /*#__PURE__*/ css css( ({ { color color: : 'brown' 'brown' } }, , 'label:brownStyles;' 'label:brownStyles;') )
  10. REACT! 1 1 2 2 3 3 4 4 5

    5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 /** @jsxImportSource @emotion/react */ /** @jsxImportSource @emotion/react */ < <div div css css= ={ {css css` ` color color: : pink pink; ; padding padding: : 1 1rem rem; ; justify-content justify-content: : center center; ; align-items align-items: : center center; ; font-weight font-weight: : bold bold; ; font-size font-size: : 3 3rem rem; ; ` `} }> > CSS DAY!!! CSS DAY!!! </ </div div> > CSS DAY!!!
  11. Object styles! 1 1 2 2 3 3 4 4

    5 5 6 6 7 7 8 8 9 9 10 10 11 11 < <div div css css= ={ {{ { color color: : 'pink' 'pink', , padding padding: : '1rem' '1rem', , justifyContent justifyContent: : 'center' 'center', , alignItems alignItems: : 'center' 'center', , fontWeight fontWeight: : 'bold' 'bold', , fontSize fontSize: : '3rem' '3rem', , } }} }> > CSS DAY!!! CSS DAY!!! </ </div div> > CSS DAY!!!
  12. Styled components 1 1 2 2 3 3 4 4

    5 5 6 6 7 7 8 8 9 9 const const Styled Styled = = styled styled. .div div` ` color color: : pink pink; ; padding padding: : 1 1rem rem; ; justify-content justify-content: : center center; ; align-items align-items: : center center; ; font-weight font-weight: : bold bold; ; font-size font-size: : 3 3rem rem; ; ` ` < <Styled Styled> >CSS DAY CSS DAY</ </Styled Styled> > CSS DAY!
  13. Composition 1 1 2 2 3 3 4 4 5

    5 6 6 7 7 8 8 9 9 10 10 < <Styled Styled className className= =' 'qualcosa qualcosa' ' css css= ={ {[ [ css css` ` 💲 💲{ {CSSDAY CSSDAY} } color color: : green green; ; ` `, , css css` `color color: : blue blue; ;` `, , CSSDAY CSSDAY ] ]} }> > CSS DAY CSS DAY </ </Styled Styled> > CSS DAY
  14. What about... cascading? Emotion className > Emotion prop Le className

    fuori dall'ecosistema Emotion vengono semplicemente aggiunte Una nuova classe viene forgiata!
  15. 1 1 2 2 3 3 4 4 const const

    a a = = css css` `color color: : red red; ; border border: : 1 1px px solid pink solid pink; ; const const b b = = css css` `color color: : pink pink; ; padding padding: : 1 1rem rem; ;` ` < <div div css css= ={ {[ [a a, , b b] ]} }> >CSSDAY CSSDAY</ </div div> > < <div div css css= ={ {css css` ` 💲 💲{ {a a} } 💲 💲{ {b b} }` `} }> >CSSDAY CSSDAY</ </div div> > CSSDAY CSSDAY
  16. 1 1 2 2 3 3 4 4 5 5

    6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 < <div div css css= ={ {css css` ` font-size font-size: : 2 2rem rem; ; text-align text-align: : center center; ; color color: : pink pink; ; section, span section, span { { display display: : inline inline; ; } } div div { { color color: : white white; ; & &:first-of-type :first-of-type { { font-size font-size: : 1 1rem rem; ; } } } } ` `} }> > < <div div> >This is This is</ </div div> > < <section section> >CSS CSS</ </section section> > < <span span> >DAY!!! DAY!!!</ </span span> > </ </div div> > This is CSSDAY!!!
  17. Animation 1 1 2 2 3 3 4 4 5

    5 6 6 7 7 8 8 9 9 10 10 11 11 const const rotate rotate = = keyframes keyframes` ` from from { { transform transform: : rotateX rotateX( (0 0deg deg) ); ; } } to to { { transform transform: : rotateX rotateX( (360 360deg deg) ); ; } } ` ` < <Styled Styled css css= ={ {css css` ` animation: 💲 animation: 💲{ {rotate rotate} } 2 2s s linear infinite linear infinite; ; ` `} }> >CSS DAY! CSS DAY!</ </Styled Styled> > CSS DAY!
  18. Media Queries 1 1 2 2 3 3 4 4

    5 5 6 6 < <Styled Styled css css= ={ {css css` ` color color: : red red; ; @media @media ( (min-width min-width: : 20 20rem rem) ) { { color color: : white white; ; } } ` `} }> >CSS DAY! CSS DAY!</ </Styled Styled> > CSS DAY!
  19. 1 1 2 2 3 3 4 4 5 5

    6 6 7 7 8 8 9 9 const const size size = = born born ? ? 40 40 : : 60 60 export export const const Cockade Cockade: : React React. .FunctionComponent FunctionComponent = = ( () ) => => ( ( < <div div css css= ={ {css css` ` max-height: 💲 max-height: 💲{ {size size} }vh vh; ; max-width: 💲 max-width: 💲{ {size size} }vh vh; ; ` `} } /> /> ) )
  20. 1 1 2 2 3 3 4 4 5 5

    6 6 7 7 8 8 9 9 const const generateAppearCss generateAppearCss = = ( (delay delay: : number number, , moreCss moreCss? ?: : string string) ) => => css css` ` animation: 💲 animation: 💲{ {appear appear} } 0.5 0.5s s; ; animation-delay: 💲 animation-delay: 💲{ {delay delay} }ms ms; ; animation-fill-mode animation-fill-mode: : backwards backwards; ; animation-timing-function animation-timing-function: : cubic-bezier cubic-bezier( (0.175 0.175, , 0.885 0.885, , 0.32 0.32, , 1.275 1.275) ); ; transform-origin transform-origin: : center center center center; ; will-change will-change: : transform transform, , opacity opacity; ; 💲 💲{ {moreCss moreCss} } ` `
  21. 1 1 2 2 3 3 4 4 5 5

    6 6 7 7 8 8 9 9 10 10 11 11 12 12 export export const const breakpoints breakpoints = = { { min min: : 0 0, , xxxs xxxs: : 480 480, , xxs xxs: : 600 600, , xs xs: : 720 720, , sm sm: : 840 840, , md md: : 960 960, , lg lg: : 1024 1024, , xl xl: : 1248 1248, , xxl xxl: : 1440 1440, , max max: : 1920 1920 } } https://github.com/MakhBeth/js-to-scss
  22. 1 1 2 2 3 3 4 4 5 5

    6 6 7 7 8 8 9 9 10 10 11 11 export export const const emBreakpoints emBreakpoints = = Object Object. .keys keys( (breakpoints breakpoints) ) . .reduce reduce( (( (aggr aggr, , key key) ) => => { { aggr aggr[ [key key] ] = = emCalc emCalc( (breakpoints breakpoints[ [key key] ]) ) return return aggr aggr } }, , { {} } ) ) // FP-TS version // FP-TS version export export const const emBreakpoints emBreakpoints = = pipe pipe( (breakpoints breakpoints, , R R. .map map( (( (value value) ) => => emCalc emCalc( (value value) )) ) ) )
  23. 1 1 2 2 3 3 4 4 5 5

    < <div css div css= ={ {css css` ` 💲 💲{ {mq mq. .xs xs} } { { display display: : none none; ; } } ` `} }/ /> >
  24. 1 1 2 2 3 3 4 4 5 5

    6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 export export function function useMedia useMedia ( (query query: : string string) ): : boolean boolean { { const const [ [matches matches, , setMatches setMatches] ] = = useState useState( (false false) ) const const [ [media media, , setMedia setMedia] ] = = useState useState< <MediaQueryList MediaQueryList | | null null> >( (null null) ) useEffect useEffect( (( () ) => => { { const const media media = = window window. .matchMedia matchMedia( (query query) ) setMedia setMedia( (media media) ) } }, , [ [] ]) ) useEffect useEffect( (( () ) => => { { if if ( (! !media media || || ! !media media. .addEventListener addEventListener) ) return return if if ( (media media. .matches matches !== !== matches matches) ) setMatches setMatches( (media media. .matches matches) ) const const listener listener = = ( () ) => => { { setMatches setMatches( (media media. .matches matches) ) } } media media. .addEventListener addEventListener( ('change' 'change', , listener listener) ) return return ( () ) => => media media. .removeEventListener removeEventListener( ('change' 'change', , listener listener) ) } }, , [ [matches matches, , query query, , media media] ]) ) return return matches matches } }
  25. 1 1 2 2 3 3 4 4 5 5

    6 6 7 7 8 8 9 9 10 10 11 11 12 12 import import { { mq mq, , useMedia useMedia } } from from './previousSlide' './previousSlide' export export function function useMediaQuery useMediaQuery ( (bp bp: : keyof keyof typeof typeof mq mq) ): : boolean boolean { { const const query query = = mq mq[ [bp bp] ]. .replace replace( ('@media ' '@media ', , '' '') ) return return useMedia useMedia( (query query) ) } } // use it like: // use it like: const const Component Component: : VFC VFC = = ( () ) => => { { const const mq mq = = useMediaQuery useMediaQuery( ('md' 'md') ) return return < <div div> >{ {mq mq ? ? 1 1 : : 2 2} }< </ /div div> > } }
  26. 1 1 2 2 3 3 4 4 5 5

    6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19 const const friends friends = = [ ['Bruce Wayne' 'Bruce Wayne', ,'Michele Brucia' 'Michele Brucia', ,'Way Home' 'Way Home', ,'Michele Wayne' 'Michele Wayne', ,'Bruce Banner' 'Bruce Banner', ,'Bruco Lì 'Bruco Lì const const mkSearchable mkSearchable = = ( (e e: : string string) ) => => e e. .replace replace( (/ /s s/ /g g, , '' '') ). .toLowerCase toLowerCase( () ) const const Search Search = = ( () ) => => { { const const [ [s s, , setS setS] ] = = useState useState( ('' '') ) return return < <div div css css= ={ {css css` ` ul li ul li[ [data-searchablefor data-searchablefor*= *=" 💲{mkSearchable(s)}" " 💲{mkSearchable(s)}"] ] { {color color: : pink pink; ; text-decoration text-decoration: : underline underline; ;} } ` `} }> > < <input input type type= =" "search search" " placeholder placeholder= =" "cerca cerca" " onChange onChange= ={ {( ({ {target target} }) ) => => setS setS( (target target. .value value) )} } /> /> < <UnorderedList UnorderedList> > { {friends friends. .map map( (e e => => < <ListItem ListItem key key= ={ {e e} } data-searchablefor data-searchablefor= ={ {mkSearchable mkSearchable( (e e) )} }> >{ {e e} }</ </ListItem ListItem> >) ) } } </ </UnorderedList UnorderedList> > </ </div div> > } }
  27. Cosa non mi è piaciuto? 1. Runtime: veloce ma presente

    2. Updates: fragile 3. Labels non sempre perfette
  28. Per cosa non lo userei? 1. Siti editoriali con poche

    pagine mastro 2. Design Systems generici 3. Ambienti non JS centrici
  29. Ma allora perchè lo usi? 1. Landing page 2. SSR/SSG

    (Next, Nuxt, Gatsby ecc...) 3. React CRUD app con sezioni "atomiche"
  30. Grazie Matteo per avermi fatto uscire dalla comfort zone e

    tornare sul palco Claudia per avermi fatto uscire dalla comfort zone e dato una figlia Gaia per avermi fatto uscire dalle comfort zone, tutte le comfort zone