Who?
Senior FED
Maintainer
Back to the past (1991)
1995
2002
2005
2011
2010
2014
2008
2015
2010
2014
2002
1991
1995
2005
2008
2011
2013
2015
<Template/>
JS Logic
CSS/SCSS
Component
CSS/SCSS
2013
2017
Component
CSS/SCSS
CSS-in-JS
CSS/SCSS
Just why???
Yippee!
CSS in JS
The Good
The Bad
& The Ugly
The Fear
...of CSS
CSS is awesome
BUT
Chris
Chris
Chris
/* style.css */
.chris {
color:'blue';
}
/* style.css */
.chris {
color:'gold';
}
/* style.css */
.chris {
color:'green';
}
<div class="my-awesome-container">
<button class="chris">
Chris!
</button>
</div>
Chris!
😰
!important
Scaling
Global namespace
Implicit dependencies
Code Maintenance (DEAD code)
Scaling
Minification
Sharing constants
Non deterministic order of source
<h2 class="42">
I'm happy!
</h2>
You are. But I'm not 🤦♀️
The (not) old style
OOCSS & SMACSS
BEM
CSS processors
NOT pure CSS
HARD to migrate
NAMING !
STILL NOT scalable
(that HUGE CSS file!)
Real-time CSS modifiers ?
var()
😍
😱
JavaScript
😰 Performance
😰 Complexity
CSS has fundamental flaws at scale that can be solved by writing styles in JS .
@VJEUX — NOVEMBER 2014
SS-in-JS
<Component/>
JS
CSS
React Inline Style
import React from "react";
import { Image } from "cloudinary-react";
import { cloudName } from "../settings";
const avatarStyle = {
display: "flex",
position: "relative",
alignItems: "center",
width: "150px",
height: "150px"
};
const Avatar = props => {
return (
<div style={avatarStyle}>
<Image
cloudName={cloudName}
publicId={props.publicId}
alt={props.title}
width={150}
height={150}
crop="thumb"
radius="max"
opacity={50}
/>
</div>
);
};
export default Avatar;
React INLINE Style
//...
/* style of container */
const avatarStyle = {
/*...*/
};
/* style of avatar initials */
const titleStyle = {
position: "absolute",
display: "flex",
fontSize: "40px",
width: "inherit",
alignItems: "center",
justifyContent: "center"
};
const Avatar = props => {
return (
<div style={avatarStyle}>
<Image
cloudName={cloudName}
publicId={props.publicId}
alt={props.title}
width={150}
height={150}
crop="thumb"
radius="max"
opacity={50}
/>
<div style={titleStyle}>
{props.title[0].toUpperCase()}
</div>
</div>
);
};
//...
Animations
Scalability
Media queries
🙄
Readability
How about
INLINE but NOT INLINE?
Ideal concepts
Scoped CSS per component
Extendable CSS in global scope
Full CSS support
SSR (Static CSS extraction)
The EXTEND
Debuggable
Syntax highlighting
Free of dead CSS code
Themes
40+
libraries
2015
<Component/>
JS
CSS
.css
import "./button.css";
//will become
import styles from "./button.css";
/* button.css */
:local(.button) {
/* by default */
/*...*/
}
//is the same as
.button { /*...*/ }
<Component/>
JS
CSS
Scoped
Composition
Share-able
Full CSS support
Pre-processor support
Dynamic modifiers
Reusable CSS
/*Item.module.css*/
.itemCard {
width: 220px;
padding: 5px;
box-shadow: 0 1px 2px rgba(0,0,0,.2);
border: 1px solid lightgray;
}
.itemCard:hover {
background-color: #d3d3d363;
cursor: pointer;
}
.itemTitle {
color: rebeccapurple;
margin: 0;
padding: 0.8rem 0;
border-top: 1px solid lightgray;
}
/*Item.js*/
import React from "react";
import { Image } from "cloudinary-react";
import { cloudName } from "../../settings";
import styles from "./Item.module.css";
const Item = props => {
return (
<div className={styles.itemCard}>
<Image
cloudName={cloudName}
publicId={props.id}
width="200"
crop="scale"
/>
<h3 className={styles.itemTitle}>
{props.title}
</h3>
</div>
);
};
export default Item;
npm install node-sass --save
/*Item.module.scss*/
.itemCard {
width: 220px;
padding: 5px;
box-shadow: 0 1px 2px rgba(0,0,0,.2);
border: 1px solid lightgray;
&:hover {
background-color: #d3d3d363;
cursor: pointer;
}
}
.itemTitle {
color: rebeccapurple;
margin: 0;
padding: 0.8rem 0;
border-top: 1px solid lightgray;
}
/* Item.js */
import React from "react";
import { Image } from "cloudinary-react";
import { cloudName } from "../../settings";
import styles from "./Item.module.scss";
const Item = props => {
return (
<div
className={props.isGrid
? styles.itemCard
: styles.itemRow}>
<Image
cloudName={cloudName}
publicId={props.id}
width={props.isGrid ? "200" : ""}
height={props.isGrid ? "" : "60"}
crop="scale"
/>
<h3 className={styles.itemTitle}>
{props.title}
</h3>
</div>
);
};
export default Item;
/* Item.module.scss */
.item{
border: 1px solid lightgray;
padding: 5px;
&:hover {
background-color: #d3d3d363;
cursor: pointer;
}
}
.itemCard {
composes: item;
width: 220px;
box-shadow: 0 1px 2px rgba(0,0,0,.2);
}
.itemRow {
composes: item;
min-height: 60px;
display: flex;
.itemTitle {
border:none;
font-size: 18px;
margin-left: 10px;
line-height: 2;
}
}
/* .css */
.container {...}
/* will be mapped to */
<div
class="elements__Container-l1fwko0zmfBG">
...
</div>
Random class generator
BUT
CSS in JS
not really
It's still
NOT Full extendable CSS in global scope
NO EASY way for theming
NAMING (not name collisions)
THE CSS-in-JS
The challenge
<Item/>
List-view
Grid-view
/* Item.css */
.item{
border: 1px solid lightgray;
padding: 5px;
&:hover {
/* Hover styles */
}
}
.itemCard {
composes: item;
margin-right:10px;
margin-bottom: 10px;
width: 220px;
box-shadow: 0 1px 2px rgba(0,0,0,.2);
}
.itemRow {
composes: item;
min-height: 60px;
display: flex;
.itemTitle {
border:none;
font-size: 18px;
margin-left: 10px;
line-height: 2;
}
}
/* Item.js */
import styled, {css} from "styled-components";
const rowStyle = css`
/* styles for row view */
`;
const cardStyle = css`
/* styles for card view */
`;
const ItemContainer = styled.div`
/* default styles*/
${props => props.isGrid
? rowStyle : cardStyle}
`;
const Item = props => {
return (
<ItemContainer isGrid={props.isGrid}>
<Image
/*...*/
/>
<ItemTitle>{props.title}</ItemTitle>
</ItemContainer>
);
};
/* Item.js */
import styled, {css} from "styled-components";
const rowStyle = css`
/* styles for row view */
`;
const cardStyle = css`
/* styles for card view */
`;
const ItemContainer = styled.div`
/* default styles*/
${props => props.isGrid
? rowStyle : cardStyle}
`;
const Item = props => {
return (
<ItemContainer isGrid={props.isGrid}>
<Image
/*...*/
/>
<ItemTitle>{props.title}</ItemTitle>
</ItemContainer>
);
};
/* Item.js */
import styled from "@emotion/styled";
const ItemContainer = styled.div(
`
/* default styles */
`,
props =>
props.isGrid
? {
/* card styles */
}
: {
/* row styles */
}
);
const Item = props => {
return (
<ItemContainer isGrid={props.isGrid}>
<Image
/*...*/
/>
<ItemTitle>{props.title}</ItemTitle>
</ItemContainer>
);
};
The GOOD
Easy to theme
NO Dead code
Extendable
Super scoped
/* Item.js */
import styled from "styled-components";
const Item = props => {
return (
<ItemContainer isGrid={props.isGrid}>
<Image
/*...*/
/>
<ItemTitle>{props.title}</ItemTitle>
</ItemContainer>
);
};
const ExtendedItem = styled(Item)`
/* extended styled*/
`
Themes
NO more CSS file!
It's awesome!
Or is it really ? 😏
The NOT so good (and ugly)
Fragmentation
Stylex coming soon... (better & faster)
Box
/* Box.js */
import React from "react";
import styled from "@emotion/styled";
const StyledBox = styled.div(props => ({
width: `${props.size}px`,
height: `${props.size}px`,
background: "grey",
marginLeft: "auto",
marginRight: "auto",
marginTop: "10px"
}));
const Box = props => <StyledBox {...props} />;
export default Box;
Input size of box
Interactive Comp
😱
JS
CSS
Parse CSS
Inject to Stylesheet
stylesheet.insertRule
Browser
HTML Paint
load
😮 Accessibility?
NO Cache
download
How about
Scaling & Sharing ?
Scaling & Sharing ?
CSS
JS
CSS
Dev
Des
Des
Scaling & Sharing ?
CoolJS
CSS
🤯
How about
Re-render problem?
Re-render problem
/*index.js*/
import { ThemeProvider } from "emotion-theming";
function App() {
const [theme, changeTheme] = useState({
color: "rebeccapurple"
});
return (
<StyledApp>
<h1>The Pokemons</h1>
<select
defaultValue={theme.color}
onChange={e => changeTheme({
color: e.target.value
})}
>
<option value="orange">Orange</option>
<option value="lime">Lime</option>
<option value="pink">Pink</option>
<option value="yellow">Yellow</option>
<option value="rebeccapurple">Purple</option>
</select>
<ThemeProvider theme={theme}>
<StyledLayout />
</ThemeProvider>
</StyledApp>
);
}
/*Item.js*/
const ItemTitle = styled.h3`
color: ${props => props.theme.color};
//...
`;
How about
Security?
Security?
CSS-in-JS means
It's still CSS! (not JS)
Learning CSS is still required! 😆
Should we use CSS-in-JS?
Yes, but with caution
So
Easy to theme
NO Dead code
Nested class
Scoped
Extra re-render
Styles on run time
Security
Portability
One standard?
Context switch
Messy code
CSS-in-JS
The Good
The Bad
The Ugly
Themeable
One standard
Portable
No scope
Non deterministic
Bundle size
Dead code (somewhere)
Naming
Private to JS code
Re-usable?
Load once
No re-render
CSS-in-CSS
The Good
The Bad
The Ugly
React Native
"Use the right tool for the right job"
And naming is not a good enough reason...
CSS-in-JS
CSS
When?
React Native App
CSS modules
CSS consistency between projects
Same technology (React) for all projects
Simple and isolated component
Full control over component styling
Theme is critical (IE included)
Support dynamic styling via props
Complex and large apps
Medium size apps / third-party libs
Security is a concern
IE 11 is not a concern
Basic scope
NO dynamic styling via props
CSS/SCSS (global)
Styled component (component)
My choice
BEM (naming)
Resources
Thank you
Copy of CSS in JS - the good, the bad and the ugly
By Maya Shavin
Copy of CSS in JS - the good, the bad and the ugly
The rise of modern JS frameworks brought in more efficient concept of Front End programming. These inspired new approaches, such as CSS Module and CSS-in-JS, more scoped in working with CSS. It’s always a debate which is the best practice among these approaches. Some claimed CSS-in-JS eliminates developer’s most fear when dealing with CSS (the CSS file) with more dynamic approach. Some disagreed. If you are keen to know about CSS-in-JS and what should be considered when it comes to work with CSS, this talk is for you.
- 149