9. 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
16. Why?
Why is separating HTML, CSS & JS a best
practice?
17. 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()
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
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
30. 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.
31. 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;
38. 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
45. 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!
46. 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);
47. 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
49. What is a preprocessor?
A language that helps us generate blocks of
key: value pairs.
selector {
property: value;
other-property: other-value;
}
50. 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!
51. JS already has lots of Real Programming
Things™
• Variables
• Functions
• Arrays & Objects
• Loops
• Maths
• String manipulation
• Dependency management
52. Things we can do 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 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]} />
}
})