css in react
TRANSCRIPT
CSSIN
React
Joe Sei� @joesei�
THE BADTHE GOODAND THE UGLY
Familiarity - (CSS Level 1 released 19 years ago)Optimized Browser parsing and layoutJavaScript DOM APIInheritance structure - JSON likeMedia Queries - size and feature detectionPseudo Selectors - browser statesBasic math via calc()
CSS3 (THE GOOD)
Flat - nested rules not supportedNeeds vendor pre�xesNo variables, no functionsSome dynamic updates still require JavaScript
CSS3 (THE BAD)
Global namespace pollutionImportance, speci�city wars, & eventually !importantNondeterministic, depends on source orderEncapsulation - sharing code across components is scaryChanges & dead code elimination are manualMissing rules and syntax errors at runtime
CSS3 (THE UGLY)
(like �ux for CSS)Object-Oriented CSS (OOCSS)Scalable and Modular Architecture for CSS (SMACSS)Block, Element, Modi�er (BEM)ATOMIC CSSSUIT CSS
METHODOLOGIES
(like babel for CSS)SASSLESSStylusPostCSSAutopre�xer / cssnext
PRE/POST PROCESSORS
a like buttonEXAMPLE:
HTML<button class="btn btn‐primary"> Like <span class="badge">9</span> </button>
OR
JSX & REACTconst LikeButton = ({ likes }) => { return ( <button className="btn btn‐primary"> Like <span className="badge">{likes}</span> </button> ) }
DOM API
1. const LikeButton = ({ likes }) => { 2. return ( 3. <button className="btn btn-primary"> 4. Like <span className="badge">{likes}</span> 5. </button> 6. ) 7. } 8.
AND
CSS3.btn {
display: inline‐block;
border: 0;
padding: 6px 12px;
}
.btn.btn‐primary {
color: #fff;
background‐color: #f74A27;
}
.btn.btn‐primary:hover {
background‐color: #ff7857;
}
.btn.btn‐primary > .badge {
color: #f74A27;
background‐color: #fff;
}
.btn > .badge {
display: inline‐block;
border‐radius: 10px;
padding: 3px 6px;
}
SASS.btn {
display: inline‐block;
border: 0;
padding: 6px 12px;
&.btn‐primary {
color: $text‐color;
background‐color: $button‐color;
&:hover {
background‐color: $button‐color‐hover;
}
.badge {
color: $button‐color;
background‐color: $text‐color;
}
}
.badge {
display: inline‐block;
border‐radius: 10px;
padding: 3px 6px;
}
}
RESULTLike 9
NOW LET'S TRY THE SAMEWITH INLINE STYLES
in React
JSONconst styles = {
'btn': {
'display': 'inline‐block',
'border': '0',
'padding': '6px 12px'
},
'btn_primary': {
'color': '#fff',
'backgroundColor': '#f74A27'
},
'btn_primary_hover': {
'backgroundColor': '#ff7857'
},
'btn_primary__badge': {
'color': '#f74A27',
'backgroundColor': '#fff'
}
'btn__badge': {
'display': 'inline‐block',
'borderRadius': '10px',
'padding': '3px 6px'
}
}
REACTimport React, { Component } from 'react'
import { styles } from './styles'
export const LikeButton = ({ likes }) => {
return (
<button style={{
...styles.btn,
...styles.btn_primary
}}>
Like
<span
style={{
...styles.btn__badge,
...styles.btn_primary__badge
}}>
{likes}
</span>
</button>
)
}
CSS IN JAVASCRIPT
1. const styles = { 2. 'btn': { 3. 'display': 'inline-block', 4. 'border': '0', 5. 'padding': '6px 12px' 6. }, 7. 8. 'btn_primary': { 9. 'color': '#fff', 10. 'backgroundColor': '#f74A27' 11. }, 12. 'btn_primary_hover': { 13. 'backgroundColor': '#ff7857' 14. },
14. },
IN YOUR COMPONENT
1. import React, { Component } from 'react' 2. 3. import { styles } from './styles' 4. 5. export const LikeButton = ({ likes }) => { 6. return ( 7. <button style={{ 8. ...styles.btn, 9. ...styles.btn_primary 10. }}> 11. Like 12. <span 13. style={{ 14. ...styles.btn__badge,
14. ...styles.btn__badge,
RESULT WITH JSONLike 9
No pseudo selectors :hover :before etc.No media queries @media viewport etc.No rule nestingNo auto pre�xingNo CSS extractionFOUC
ISSUES WITH USING THE PLAIN
JSON object
Radiumreact-css-modulesstyled-componentsaphrodite, jss, cxs, csjs, glamor, so many more
FRAMEWORKS FOR
CSS in JS
RADIUMexport const styles = {
btn: {
display: 'inline‐block',
border: '0',
padding: '6px 12px',
btn_primary: {
color: '#fff',
backgroundColor: '#f74A27',
':hover': {
backgroundColor: '#ff7857'
},
badge: {
color: '#f74A27',
backgroundColor: '#fff'
}
}
badge: {
display: 'inline‐block',
borderRadius: '10px',
padding: '3px 6px'
}
}
}
REACTimport React, { Component } from 'react'
import Radium from 'radium'
import { styles } from './styles'
@Radium
class LikeButton extends Component {
render () {
const { likes } = this.props
return (
<button style={[
styles.btn,
styles.btn.btn_primary
]}>
Like <span style={[
styles.btn.badge,
styles.btn.btn_primary.badge
]}>{likes}</span>
</button>
)
}
}
export default LikeButton
RADIUM STYLE SYNTAX
1. export const styles = { 2. btn: { 3. display: 'inline-block', 4. border: '0', 5. padding: '6px 12px', 6. 7. btn_primary: { 8. color: '#fff', 9. backgroundColor: '#f74A27', 10. 11. ':hover': { 12. backgroundColor: '#ff7857' 13. }, 14.
14.
RADIUM REACT SYNTAX
1. import React, { Component } from 'react' 2. import Radium from 'radium' 3. import { styles } from './styles' 4. 5. @Radium 6. class LikeButton extends Component { 7. render () { 8. const { likes } = this.props 9. return ( 10. <button style={[ 11. styles.btn, 12. styles.btn.btn_primary 13. ]}> 14. Like <span style={[
14. Like <span style={[
Wraps your function or component with @decoratorsCreates a class to manage state for :hover :active :focusRadium.getState(this.state, 'btnPrimary', ':hover')
Style similar child elements with .map()matchMedia for media queries - IE poly�ll, server-side?Styles are inline, extract into CSS for production?
RADIUM NOTES
No globals (with caveats)Built in dead code elimination, only used componentsPresentation logic is in your view, �nd and editState, constantsComposition, loops, computationDistribute via import and exportDynamic styling, app & DOM state e.g. data attributesSome :pseudo selectors re-implemented in JavaScriptFor example :last-child becomes i === arr.length - 1
INLINE STYLES (THE GOOD)
No ::after ::before ::selection
Media queries have to use window.matchMedia()
Autopre�xing display: -webkit-flex; display: flex;
Animations via @keyframes re-implemented in JSHighest priority before !important No Speci�city CascadingPerformanceDebugging in devtools is a painDuplicate markup for similar elements
INLINE STYLES (THE BAD)
CSS MODULES
Based on Interoperable CSS - loadable, linkable CSSWorks with SASS, PostCSS etc.Broken CSS = compile errorUsing an unde�ned CSS Module = no warning
REACT-CSS-MODULES
SASS@import "variables.scss";
.btn {
display: inline‐block;
border: 0;
padding: 6px 12px;
&.btn‐primary {
color: $text‐color;
background‐color: $button‐color;
&:hover {
background‐color: $button‐color‐hover;
}
.badge {
color: $button‐color;
background‐color: $text‐color;
}
}
.badge {
display: inline‐block;
border‐radius: 10px;
padding: 3px 6px;
}
}
REACTimport React, { Component } from 'react'
import CSSModules from 'react‐css‐modules'
import styles from '../styles/likebutton.scss'
@CSSModules(styles, {allowMultiple: true})
class LikeButton extends Component {
render () {
const { likes } = this.props
return (
<button styleName="btn btn‐primary">
Like <span styleName="badge">{likes}</span>
</button>
)
}
}
export default LikeButton
REACT-CSS-MODULES SYNTAX
1. import React, { Component } from 'react' 2. import CSSModules from 'react-css-modules' 3. import styles from '../styles/likebutton.scss' 4. 5. @CSSModules(styles, {allowMultiple: true}) 6. class LikeButton extends Component { 7. render () { 8. const { likes } = this.props 9. return ( 10. <button styleName="btn btn-primary"> 11. Like <span styleName="badge">{likes}</span> 12. </button> 13. ) 14. }
14. }
styles object or this.props.styles[yourClasslassName]Con�gure your component classnames via localIdentName
Webpack CSS loader [path]___[name]__[local]___[hash:base64:5]
Generated classname styles-___likebutton__btn-primary___HYx7V
No overruling, intentionally nor unintentionallyComposition composes: parentClass same as @extend in SassOthers from ICSS :global :export :import
Use extract text plugin in production
REACT-CSS-MODULES NOTES
STYLED COMPONENTS
STYLEDimport styled from 'styled‐components'
const StyledLikeButton = styled.button`
display: inline‐block;
border: 0;
padding: 6px 12px,
&.btn‐primary {
color: #fff;
background‐color: #f74A27;
&:hover {
background‐color: #ff7857;
}
.badge {
color: #f74A27;
background‐color: ${THEME.bgColor};
}
}
.badge {
display: inline‐block;
border‐radius: 10px;
padding: 3px 6px;
}
`
export default StyledLikeButton
REACTimport React, { Component } from 'react'
import StyledLikeButton from './StyledLikeButton'
class LikeButton extends Component {
render () {
const { likes } = this.props
return (
<StyledLikeButton className="btn‐primary">
Like <span className="badge">{likes}</span>
</StyledLikeButton>
)
}
}
export default LikeButton
STYLED COMPONENTS SYNTAX
1. import styled from 'styled-components' 2. 3. const StyledLikeButton = styled.button` 4. display: inline-block; 5. border: 0; 6. padding: 6px 12px, 7. &.btn-primary { 8. color: #fff; 9. background-color: #f74A27; 10. &:hover { 11. background-color: #ff7857; 12. } 13. .badge { 14. color: #f74A27;
14. color: #f74A27;
STYLED COMPONENTS USAGE
1. import React, { Component } from 'react' 2. import StyledLikeButton from './StyledLikeButton' 3. 4. class LikeButton extends Component { 5. 6. render () { 7. const { likes } = this.props 8. return ( 9. <StyledLikeButton className="btn-primary"> 10. Like <span className="badge">{likes}</span> 11. </StyledLikeButton> 12. ) 13. } 14.
14.
Autopre�xing included for freeWrite plain CSS, no weird poly�lls neededGenerated classnames are namespaced btn-primary gjkSC
Injects style tags into the document headSupports server-side rendering, but not extract text pluginkeyframes helper keeps your rules local to your componentTheming is built in
STYLED COMPONENTS NOTES
Web Components and Shadow DOMcssnextCSS4¿¡ !?
WHAT'S NEXT