Senior FED
Maintainer
2010
2014
2008
2015
2010
2014
2002
1991
1995
2005
2008
2011
2013
2015
<Template/>
JS Logic
CSS/SCSS
Component
CSS/SCSS
Component
CSS/SCSS
CSS-in-JS
CSS/SCSS
Just why???
Yippee!
The Good
The Bad
& The Ugly
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>
OOCSS & SMACSS
BEM
CSS processors
NOT pure CSS
HARD to migrate
NAMING !
STILL NOT scalable
(that HUGE CSS file!)
var()
JavaScript
😰 Performance
😰 Complexity
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;
//...
/* 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
Scoped CSS per component
Extendable CSS in global scope
Full CSS support
SSR (Static CSS extraction)
Debuggable
Syntax highlighting
Free of dead CSS code
Themes
import "./button.css";
//will become
import styles from "./button.css";
/* button.css */
:local(.button) {
/* by default */
/*...*/
}
//is the same as
.button { /*...*/ }
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
not really
NOT Full extendable CSS in global scope
NO EASY way for theming
NAMING (not name collisions)
<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>
);
};
/* 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!
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
Parse CSS
Inject to Stylesheet
stylesheet.insertRule
HTML Paint
load
download
Dev
Des
Des
CoolJS
/*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};
//...
`;
The Good
The Bad
The Ugly
The Good
The Bad
The Ugly
CSS-in-JS
CSS
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