Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Styling Components with JavaScript: MelbCSS Edition

1,273 views

Published on

A rehashed version of http://www.slideshare.net/bensmithett/presentation-38906546 that I presented at MelbCSS

Published in: Engineering
  • Be the first to comment

Styling Components with JavaScript: MelbCSS Edition

  1. 1. Styling Components with JavaScript @bensmithett
  2. 2. I already gave this talk at MelbJS Sorry if you're sitting through it again!
  3. 3. Warning: This talk is about writing CSS...
  4. 4. IN
  5. 5. JAVASCRIPT
  6. 6. Explore some new ideas and challenge best practices
  7. 7. 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
  8. 8. COMPONENTS!
  9. 9. The Profile component: views/ profile.html stylesheets/ profile.css javascripts/ profile.js
  10. 10. structure <div class="profile"> <img class="profile__avatar" src="{{user.avatar}}"> <strong>{{user.username}}</strong> </div>
  11. 11. style .profile { border: 1px solid #ddd; overflow: hidden; } .profile__avatar { float: left; margin-right: 10px; }
  12. 12. behaviour $(".profile").on("click", function(){ alert("hi"); });
  13. 13. Best practice: Separate HTML, CSS & JS
  14. 14. Why? Why is separating HTML, CSS & JS a best practice?
  15. 15. 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()
  16. 16. 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
  17. 17. views/ profile.html stylesheets/ profile.css javascripts/ profile.js
  18. 18. components/ profile/ profile.html profile.css profile.js
  19. 19. Component: A tightly coupled little bundle of HTML, CSS & JS
  20. 20. React is a library for building components
  21. 21. A React component • Describes the HTML structure given a particular application state • Reacts to user events (click, dragenter etc) that originate within the component
  22. 22. <div class="profile"> <img class="profile__avatar" src="{{user.avatar}}"> <strong>{{user.username}}</strong> </div>
  23. 23. $(".profile").on("click", function(){ alert("hi"); });
  24. 24. 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"); } });
  25. 25. components/ profile/ profile.html profile.css profile.js
  26. 26. components/ profile/ profile.jsx profile.css
  27. 27. 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.
  28. 28. 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;
  29. 29. Can't we do better?
  30. 30. What if our build process automatically built a stylesheet based only on the JS components we actually use?
  31. 31. Webpack // ComponentA.js require("./componentA.css"); // ComponentB.js require("./componentB.css"); // Javascript build generates app.css: // .component-a { ... } // .component-b { ... }
  32. 32. components/ profile/ profile.jsx profile.css
  33. 33. 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>
  34. 34. NOBODY LIKES INLINE STYLES
  35. 35. 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
  36. 36. react-style + webpack • github.com/SanderSpies/react-style • andreypopp.com/posts/2014-08-06-react-style. html • webpack.github.io
  37. 37. var Profile = React.createClass({ styles: ReactStyle({ backgroundColor: "green", border: "1px solid #ddd" }), render: function () { return <div styles={this.styles()} /> } })
  38. 38. /* app.css generated by react-style & webpack */ .a { background-color: green; border: 1px solid #ddd; } <!-- DOM generated by React --> <div class="a"> ... </div>
  39. 39. Best practice: Use meaningful class names & a naming convention like BEM or SUIT
  40. 40. 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.
  41. 41. var Profile = React.createClass({ styles: ReactStyle({ backgroundColor: "green", border: "1px solid #ddd" }), render: function () { return <div styles={this.styles()} /> } })
  42. 42. 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!
  43. 43. 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);
  44. 44. 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
  45. 45. I <3 Sass
  46. 46. What is a preprocessor? A language that helps us generate blocks of key: value pairs. selector { property: value; other-property: other-value; }
  47. 47. 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!
  48. 48. JS already has lots of Real Programming Things™ • Variables • Functions • Arrays & Objects • Loops • Maths • String manipulation • Dependency management
  49. 49. Things we can do in JS instead of a preprocessor Warning: everything beyond here is totally pseudocode that may or may not actually work
  50. 50. Example: Color variables var colors = require("color_palette"); var styles = { color: colors["primary"] } var Profile = React.createClass({ render: function () { return <div style={styles} />; } });
  51. 51. 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]} /> } })
  52. 52. 2015 HIPSTER PREPROCESSOR JAVASCRIPT?!
  53. 53. Give it 5 minutes
  54. 54. the end :) @bensmithett

×