CSS Components in Practice
Andrey Sitnik, Evil Martians
Russia
Our Projects
Russia
Components
Components
everywhere
Component is a small and isolated
part of an interface
Project Structure
compontents/
Why small components
are a big deal?
Programming ≠ Frameworks
jQuery
Backbone
Angular
React
Backbone
Angular
React
?
Programming ≠ Code
“Controlling complexity
is the essence
of computer programming”
— Brian Kernighan
3 objects
6 objects
3 connections
15 connections
Complexity Grows Fast
“Divide and Conquer”
No components
With components
2. Tools
.window {
…
}
.name {
background: red;
}
.popup {
…
}
.name {
border-color: blue;
}
.window {
…
}
.name {
background: red;
}
← Conflict →
.popup {
…
}
.name {
border-color: blue;
}
BEM?
.popup_name {
background: red;
}
.window_name {
border-color: blue;
}
Versions Conflict
header
search-field 2.0
legacy-page
search-field 1.0
Prefixes Conflict
@import "bankform";
@import "../bankform";
“Autoprefixer” for BEM?
.name {
…
}
.popup_name_hv65 {
…
}
.block_element_hash { }
CSS Modules — AutoBEM
import style from "./popup.css";
export default Popup = (props) => (
<div class={ style.popup }>
<h1 style={ style.name }>
{ props.name }
</h1>
</div>
);
No React?
CSS Modules
PostCSS plugin 1
PostCSS plugin 3
PostCSS plugin 2
PostCSS plugin 4
postcss-modules
PostCSS
PostCSS plugin 1
PostCSS plugin 3
PostCSS plugin 2
PostCSS plugin 4
.name {
…
}
.Logo_name_6gj5 {
…
}
{
name: "Logo_name_6gj5"
}
Ruby on Rails
- style = load_json('logo.css.json');
%div{ class: style.name }
Problem
CSS Modules
Another way?
Inline CSS?
const style = {
color: 'blue'
};
return <a style={ style }></a>;
Bad Performance
No native
:hover
No native
@media
JSS
jss.createStyleSheet({
name: {
color: 'blue',
'&:hover': {
color: 'red'
}
}
}).attach();
.name--jss-0-0 {
color: blue;
}
.name--jss-0-0:hover {
color: red;
}
CSS Modules
Server-side render
CSS syntax
JSS
Dynamic values
JS syntax
<Header>
<Logo />
</Header>
<Footer>
<Logo />
</Footer>
Problem 2
<Header>
<Logo />
</Header>
<Footer>
<Logo />
</Footer>
.header {
line-height: 1.4;
}
.footer {
line-height: 1;
}
.logo {
}
.logo {
}
Inherited properties
.header
.logo
a
{ line-height: 1.4; }
line-height: 1.4
line-height: 1.4
.header {
line-height: 1.4;
}
.footer {
line-height: 1;
}
.logo {
}
.logo {
}
line-height: 1.4;
line-height: 1;
Conflict
<Logo />
Project 1
Project 2
/* Reset */
* {
padding: 0;
}
/* Reset */
* {
box-sizing: border-box;
}
Local Reset
h1, h2, …, div {
/* Reset */
}
.header {
}
.logo {
}
.header, .logo {
/* Reset */
}
.header {
}
.logo {
}
Global Reset
Reset
Header
Logo
Reset
Header
Reset
Local Reset
Global Reset
Logo
.header
.logo
a
line-height: 1.4
line-height: default
line-height: default
Isolated
Explicit Inherit
.button {
font: inherit;
}
Isolates from this Too
h1 {
padding-bottom: 10px;
}
.article div {
background: blue;
}
postcss-autoreset
require('postcss-autoreset')({
reset: {
all: 'initial',
font: 'inherit',
boxSizing: 'border-box'
}
})
jss-isolate
require('jss-isolate')({
reset: {
all: 'initial',
font: 'inherit',
boxSizing: 'border-box'
}
})
Isolation Overview
Selectors: CSS Modules or JSS
Properties: postcss-autoreset or jss-isolate
Open Questions
3. Practice
Best Tools ≠ Good Code
Problem 1
.logo {
&.is-small { }
&.is-smaller { }
&.is-super-small { }
&.is-super-small-but-no-so-small { }
}
Size in Container
.logo {
width: 100%;
height: 100%;
}
.headerLogo {
position: relative;
width: 32px;
height: 32px;
margin: 10px 0;
}
<div style={ s.headerLogo }>
<Logo></Logo>
</div>
Scale by Font Size
.button {
height: 3em;
}
.formSubmit {
font-size: 20px;
}
.formBack {
font-size: 14px;
}
Container Queries
.form:container(width >= 100px) {
flex-direction: column;
}
CQ Prolyfills
Problem 2
.button_icon {
&.is-ok { }
&.is-back { }
&.is-remove { }
&.is-time { }
&.is-close { }
…
}
Use Component’s Children
<Button text="Remove">
<RemoveIcon></RemoveIcon>
</Button>
Animation Components
<AnimakitRotator
side={ this.state.loading ? 1 : 0 }
>
<SubmitButton>
<Loader>
</Rotator>
React Shuffle
<ReactShuffle>
<Icon key="1"></Icon>
<Icon key="2"></Icon>
<Icon key="3"></Icon>
<Icon key="4"></Icon>
<Icon key="5"></Icon>
<Icon key="6"></Icon>
</ReactShuffle>
Open Questions
4. Benefits
Widgets
<link rel="stylesheet"
src="/💩💩💩.css">
<link rel="stylesheet"
src="https://a.com/widget.css">
Components from npm
<BillingForm color={ colors.main }
onPay={ this.pay.bind(this) }>
</BillingForm>
Shared Components
<UIKitButton></UIKitButton>
Project 1
Project 2
Big Company
Less Tests
Better Tools
.LogoText {
font-wight: bold;
color: blue;
}
.HeaderName {
font-wight: bold;
color: blue;
}
.LogoText, .HeaderName {
font-wight: bold;
color: blue;
}
Links