Styling 
Components 
with JavaScript 
@bensmithett
I already gave this talk at MelbJS 
Sorry if you're sitting through it again!
Warning: 
This talk is about writing CSS...
IN
JAVASCRIPT
Explore some new ideas and 
challenge best practices
CSS is not lacking Best Practices™ 
Sass • Less • Stylus • Myth • Autoprefixer 
OOCSS • BEM • SMACSS • SUIT • AMCSS 
No IDs • No inline styles • Use meaningful class 
names • Mobile first • Repetition is OK • 
Repetition is the devil • Avoid complex selectors 
• Use @extends • Don't use @extends • Don't 
write CSS in JavaScript
COMPONENTS!
The Profile component: 
views/ 
profile.html 
stylesheets/ 
profile.css 
javascripts/ 
profile.js
structure 
<div class="profile"> 
<img class="profile__avatar" src="{{user.avatar}}"> 
<strong>{{user.username}}</strong> 
</div>
style 
.profile { 
border: 1px solid #ddd; 
overflow: hidden; 
} 
.profile__avatar { 
float: left; 
margin-right: 10px; 
}
behaviour 
$(".profile").on("click", function(){ 
alert("hi"); 
});
Best practice: 
Separate HTML, CSS & JS
Why? 
Why is separating HTML, CSS & JS a best 
practice?
When we were building pages 
CSS classes loosely coupled to HTML 
.important { 
color: red; 
font-weight: bold; 
} 
JS behaviour loosely coupled to HTML 
$(".foo").fancyParallaxSlider()
Now... 
BEM Blocks, SMACSS Modules, SUIT 
Components 
Tightly couple styles to a very particular HTML 
structure 
Backbone Views, Angular Directives, Ember & 
React Components 
Tightly couple JS behaviour to a very particular 
HTML structure
views/ 
profile.html 
stylesheets/ 
profile.css 
javascripts/ 
profile.js
components/ 
profile/ 
profile.html 
profile.css 
profile.js
Component: 
A tightly coupled little bundle of HTML, 
CSS & JS
React is a library for building components
A React component 
• Describes the HTML structure given a 
particular application state 
• Reacts to user events (click, dragenter etc) 
that originate within the component
<div class="profile"> 
<img class="profile__avatar" src="{{user.avatar}}"> 
<strong>{{user.username}}</strong> 
</div>
$(".profile").on("click", function(){ 
alert("hi"); 
});
var Profile = React.createClass({ 
render: function () { 
return( 
<div className="profile" onClick={this.handleClick}> 
<img className="profile__avatar" 
src={this.props.avatarUrl} /> 
<strong>{this.props.username}</strong> 
</div> 
); 
}, 
handleClick: function () { 
alert("hi"); 
} 
});
components/ 
profile/ 
profile.html 
profile.css 
profile.js
components/ 
profile/ 
profile.jsx 
profile.css
The only real connection: a class name 
// JS 
render: function () { 
return ( 
<div className="profile"> 
// ... 
</div> 
) 
} 
/* CSS */ 
.profile 
border: 1px solid #ddd 
It's a crappy, vague connection.
Also, our CSS builds are a bit backwards 
/* app.scss */ 
@import vendor/Normalize.css; 
@import base; 
@import components/header; 
@import components/profile; 
@import components/footer;
Can't we do better?
What if our build process automatically 
built a stylesheet based only on the JS 
components we actually use?
Webpack 
// ComponentA.js 
require("./componentA.css"); 
// ComponentB.js 
require("./componentB.css"); 
// Javascript build generates app.css: 
// .component-a { ... } 
// .component-b { ... }
components/ 
profile/ 
profile.jsx 
profile.css
React can do inline styles 
var profileStyles = { 
border: "1px solid #ddd", 
overflow: "hidden" 
}; 
var Profile = React.createClass({ 
render: function () { 
return <div style={profileStyles} />; 
} 
}); 
<!-- DOM generated by React --> 
<div style="border: 1px solid #ddd; overflow: hidden"><div>
NOBODY LIKES 
INLINE STYLES
What we really want: 
• Declare styles in the component file, using 
JavaScript, like we do with inline styles 
• Build process that: 
• converts those styles to a CSS class 
• bundles up all generated CSS classes into a 
shiny CSS file 
• JS component magically knows which class 
name to use for a given element
react-style + webpack 
• github.com/SanderSpies/react-style 
• andreypopp.com/posts/2014-08-06-react-style. 
html 
• webpack.github.io
var Profile = React.createClass({ 
styles: ReactStyle({ 
backgroundColor: "green", 
border: "1px solid #ddd" 
}), 
render: function () { 
return <div styles={this.styles()} /> 
} 
})
/* app.css generated by react-style & webpack */ 
.a { 
background-color: green; 
border: 1px solid #ddd; 
} 
<!-- DOM generated by React --> 
<div class="a"> 
... 
</div>
Best practice: 
Use meaningful class 
names & a naming 
convention like BEM or 
SUIT
Why? 
We need a sensible class name that we can 
follow across seperate HTML, CSS & JS files 
Nope. All that stuff is in one file now.
var Profile = React.createClass({ 
styles: ReactStyle({ 
backgroundColor: "green", 
border: "1px solid #ddd" 
}), 
render: function () { 
return <div styles={this.styles()} /> 
} 
})
Why? 
We want to be able to inspect an element in the 
browser dev tools & see which component it 
belongs to. 
Yeah, this one is valid. 
But we can still automate it!
Automatically generate a BEM class name 
className = path.basename(fileName).split('.')[0].toLowerCase() + 
'__' + 
styleName; 
or a SUIT class name 
className = path.basename(fileName).split('.')[0] + 
'-' + 
styleName.charAt(0).toUpperCase() + 
styleName.slice(1);
CSS class naming conventions are a project 
setting, not an inherent property of the 
component. 
• Dev: BEM class names for easy debugging 
• Prod: Tiny minified class names
I <3 Sass
What is a preprocessor? 
A language that helps us generate blocks of 
key: value pairs. 
selector { 
property: value; 
other-property: other-value; 
}
What is a preprocessor? 
A language that helps us generate blocks of 
key: value pairs. 
selector = { 
property: "value", 
otherProperty: "other-value" 
}; 
OMG JavaScript can do that!
JS already has lots of Real Programming 
Things™ 
• Variables 
• Functions 
• Arrays & Objects 
• Loops 
• Maths 
• String manipulation 
• Dependency management
Things we can do in JS 
instead of a preprocessor 
Warning: everything beyond here is totally pseudocode that may or 
may not actually work
Example: Color variables 
var colors = require("color_palette"); 
var styles = { 
color: colors["primary"] 
} 
var Profile = React.createClass({ 
render: function () { 
return <div style={styles} />; 
} 
});
Example: Generate a grid 
var gridColumns = 12; 
var gridDefinitions = {}; 
for (var i = 1; i <= gridColumns; i++) { 
gridDefinitions["span-" + i] = { 
float: left, 
width: ((i / gridColumns) * 100) + "%" 
} 
} 
var GridColumn = React.createClass({ 
render: function () { 
var columns = "span-" + this.props.columnCount; 
return <div style={gridDefinitions[columns]} /> 
} 
})
2015 HIPSTER PREPROCESSOR 
JAVASCRIPT?!
Give it 5 minutes
the end :) 
@bensmithett

Styling Components with JavaScript: MelbCSS Edition

  • 1.
    Styling Components withJavaScript @bensmithett
  • 2.
    I already gavethis talk at MelbJS Sorry if you're sitting through it again!
  • 3.
    Warning: This talkis about writing CSS...
  • 4.
  • 5.
  • 8.
    Explore some newideas and challenge best practices
  • 9.
    CSS is notlacking Best Practices™ Sass • Less • Stylus • Myth • Autoprefixer OOCSS • BEM • SMACSS • SUIT • AMCSS No IDs • No inline styles • Use meaningful class names • Mobile first • Repetition is OK • Repetition is the devil • Avoid complex selectors • Use @extends • Don't use @extends • Don't write CSS in JavaScript
  • 10.
  • 11.
    The Profile component: views/ profile.html stylesheets/ profile.css javascripts/ profile.js
  • 12.
    structure <div class="profile"> <img class="profile__avatar" src="{{user.avatar}}"> <strong>{{user.username}}</strong> </div>
  • 13.
    style .profile { border: 1px solid #ddd; overflow: hidden; } .profile__avatar { float: left; margin-right: 10px; }
  • 14.
  • 15.
  • 16.
    Why? Why isseparating HTML, CSS & JS a best practice?
  • 17.
    When we werebuilding pages CSS classes loosely coupled to HTML .important { color: red; font-weight: bold; } JS behaviour loosely coupled to HTML $(".foo").fancyParallaxSlider()
  • 18.
    Now... BEM Blocks,SMACSS Modules, SUIT Components Tightly couple styles to a very particular HTML structure Backbone Views, Angular Directives, Ember & React Components Tightly couple JS behaviour to a very particular HTML structure
  • 19.
    views/ profile.html stylesheets/ profile.css javascripts/ profile.js
  • 20.
    components/ profile/ profile.html profile.css profile.js
  • 21.
    Component: A tightlycoupled little bundle of HTML, CSS & JS
  • 23.
    React is alibrary for building components
  • 24.
    A React component • Describes the HTML structure given a particular application state • Reacts to user events (click, dragenter etc) that originate within the component
  • 25.
    <div class="profile"> <imgclass="profile__avatar" src="{{user.avatar}}"> <strong>{{user.username}}</strong> </div>
  • 26.
  • 27.
    var Profile =React.createClass({ render: function () { return( <div className="profile" onClick={this.handleClick}> <img className="profile__avatar" src={this.props.avatarUrl} /> <strong>{this.props.username}</strong> </div> ); }, handleClick: function () { alert("hi"); } });
  • 28.
    components/ profile/ profile.html profile.css profile.js
  • 29.
  • 30.
    The only realconnection: a class name // JS render: function () { return ( <div className="profile"> // ... </div> ) } /* CSS */ .profile border: 1px solid #ddd It's a crappy, vague connection.
  • 31.
    Also, our CSSbuilds are a bit backwards /* app.scss */ @import vendor/Normalize.css; @import base; @import components/header; @import components/profile; @import components/footer;
  • 32.
    Can't we dobetter?
  • 33.
    What if ourbuild process automatically built a stylesheet based only on the JS components we actually use?
  • 34.
    Webpack // ComponentA.js require("./componentA.css"); // ComponentB.js require("./componentB.css"); // Javascript build generates app.css: // .component-a { ... } // .component-b { ... }
  • 35.
  • 36.
    React can doinline styles var profileStyles = { border: "1px solid #ddd", overflow: "hidden" }; var Profile = React.createClass({ render: function () { return <div style={profileStyles} />; } }); <!-- DOM generated by React --> <div style="border: 1px solid #ddd; overflow: hidden"><div>
  • 37.
  • 38.
    What we reallywant: • Declare styles in the component file, using JavaScript, like we do with inline styles • Build process that: • converts those styles to a CSS class • bundles up all generated CSS classes into a shiny CSS file • JS component magically knows which class name to use for a given element
  • 39.
    react-style + webpack • github.com/SanderSpies/react-style • andreypopp.com/posts/2014-08-06-react-style. html • webpack.github.io
  • 40.
    var Profile =React.createClass({ styles: ReactStyle({ backgroundColor: "green", border: "1px solid #ddd" }), render: function () { return <div styles={this.styles()} /> } })
  • 41.
    /* app.css generatedby react-style & webpack */ .a { background-color: green; border: 1px solid #ddd; } <!-- DOM generated by React --> <div class="a"> ... </div>
  • 42.
    Best practice: Usemeaningful class names & a naming convention like BEM or SUIT
  • 43.
    Why? We needa sensible class name that we can follow across seperate HTML, CSS & JS files Nope. All that stuff is in one file now.
  • 44.
    var Profile =React.createClass({ styles: ReactStyle({ backgroundColor: "green", border: "1px solid #ddd" }), render: function () { return <div styles={this.styles()} /> } })
  • 45.
    Why? We wantto be able to inspect an element in the browser dev tools & see which component it belongs to. Yeah, this one is valid. But we can still automate it!
  • 46.
    Automatically generate aBEM class name className = path.basename(fileName).split('.')[0].toLowerCase() + '__' + styleName; or a SUIT class name className = path.basename(fileName).split('.')[0] + '-' + styleName.charAt(0).toUpperCase() + styleName.slice(1);
  • 47.
    CSS class namingconventions are a project setting, not an inherent property of the component. • Dev: BEM class names for easy debugging • Prod: Tiny minified class names
  • 48.
  • 49.
    What is apreprocessor? A language that helps us generate blocks of key: value pairs. selector { property: value; other-property: other-value; }
  • 50.
    What is apreprocessor? A language that helps us generate blocks of key: value pairs. selector = { property: "value", otherProperty: "other-value" }; OMG JavaScript can do that!
  • 51.
    JS already haslots of Real Programming Things™ • Variables • Functions • Arrays & Objects • Loops • Maths • String manipulation • Dependency management
  • 52.
    Things we cando in JS instead of a preprocessor Warning: everything beyond here is totally pseudocode that may or may not actually work
  • 53.
    Example: Color variables var colors = require("color_palette"); var styles = { color: colors["primary"] } var Profile = React.createClass({ render: function () { return <div style={styles} />; } });
  • 54.
    Example: Generate agrid var gridColumns = 12; var gridDefinitions = {}; for (var i = 1; i <= gridColumns; i++) { gridDefinitions["span-" + i] = { float: left, width: ((i / gridColumns) * 100) + "%" } } var GridColumn = React.createClass({ render: function () { var columns = "span-" + this.props.columnCount; return <div style={gridDefinitions[columns]} /> } })
  • 55.
  • 56.
    Give it 5minutes
  • 57.
    the end :) @bensmithett