Overview
- History
- Composition
- Code reuse
- Vendor prefixing
- CSS globals
- Sharing values
- Overhead
- More optimizations
Javascript Style Sheets
<style type="text/javascript">
tags.H1.color = "blue";
</style>
Cascades and Composition
Lets create a component "A" with a button.
component-a button {
background: red;
}
Lets create a component "B" with a button.
component-b button {
color: green;
}
Now lets compose them.
Lets use component B within component A.
<component-a>
<button>Button A</butotn>
<component-b>
<button>Button B</butotn>
</component-b>
</component-a>
Is this what we
want to get?
2 problems
1. Cascading
Is only useful when you are never going to
compose components.
2. Global selectors
Is a bad practice and we all know why, right?
Lets rewrite it using JS
// component-a.js
module.exports = {
button: {
background: 'red'
}
}
// component-b.js
module.exports = {
button: {
color: 'green'
}
}
// app.js
var a = require('./component-a')
var b = require('./component-b')
jss.createStyleSheet(a, true).attach()
jss.createStyleSheet(b, true).attach()
Both problems solved.
- We don't rely on cascading
- Selectors are generated and are unique
<style>
.jss-0 {
background: red;
}
</style>
<style>
.jss-1 {
color: green;
}
</style>
Code reuse in CSS
- Multiple classes on one element
- Global selectors
Code reuse in JSS
Is infinitely flexible.
- Truly reusable css components
- Save up to 30% in size
Inheritance
Done by "extend" plugin.
// base-button.js
module.exports = {
color: 'red'
}
// styles.js
var baseButton = require('./base-button')
module.exports = {
'.button': {
extend: baseButton,
float: 'left'
}
}
// app.js
var styles = require('./styles')
jss.createStyleSheet(styles).attach()
<style>
.button {
color: red;
float: left;
}
</style>
Nesting
Done by "nested" plugin.
// styles.js
module.exports = {
'.button': {
float: 'left',
'&:hover': {
color: 'red'
},
'& .icon': {
border: '1px solid red'
}
}
}
// app.js
var styles = require('./styles')
jss.createStyleSheet(styles).attach()
<style>
.button {
float: left;
}
.button:hover {
color: red;
}
.button .icon {
width: 20px;
height: 20px
}
</style>
Vendor prefixes
Done by "vendorPrefixer" plugin.
Added very efficiently at runtime.
// styles.js
module.exports = {
'.button': {
transform: 'translateX(100px)'
}
}
// app.js
var styles = require('./styles')
jss.createStyleSheet(styles).attach()
<style>
.button {
-webkit-transform: translate(100px);
}
</style>
Sharing values
Now it's really easy to reuse and access constants.
// vars.js
module.exports = {
color: '#fff',
height: 20
}
// styles.js
var vars = require('./vars')
module.exports = {
button: {
color: vars.color,
height: vars.height + 'px'
}
}
// app.js
var vars = require('./vars')
// Do something usefull
$('something').height(vars.height)
Direct injection
// styles.js
module.exports = {
button: {
padding: '20px',
background: 'blue'
}
}
// app.js
var styles = require('./styles')
var sheet = jss.createStyleSheet(styles, true)
sheet.rules.button.applyTo($('button')[0])
Why share values?
- DOM round trip is expensive
- get initial value directly
- calculate relative values
- use values in different places e.g. inline
JS layout engines will love it!
Overhead?
bootstrap css (134kb) vs. bootstrap jss:
http://jsstyles.github.io/jss/bench/bootstrap/css.html
http://jsstyles.github.io/jss/bench/bootstrap/jss.html
Jss overall overhead ~10-15ms on desktop chrome.
More optimizations?
Critical path
You might want to convert critical path
jss to css and inline it.
var ss = jss.createStyleSheet({
'a': {
color: 'red'
}
})
console.log(ss.toString())
// Output
a {
color: red;
}
Unused CSS
-
Render jss styles only for components which are in the render tree.
-
Remove jss styles when components are detached.
JSS
By Oleg Isonen
JSS
Dynamic stylesheets for web components.
- 25,981