Cssobj
Runtime CSS manager, Turn CSS into dynamic JS module, Stylesheet CRUD (Create, Read, Update, Delete) in CSSOM, name space (local) class names
Install / Use
/learn @cssobj/CssobjREADME
CSSOBJ 
Runtime CSS manager, Turn CSS into dynamic JS module, Stylesheet [CRUD][] (Create, Read, Update, Delete) in CSSOM, Solve common problems of CSS-in-JS.
- ~4K min.gz, simple API
- Nested rules, support any CSS selector/value
- Minimal work to migrate
- Work with DOM Frameworks
- [CSS Rules CRUD][CRUD]
- Put class names into local space No Conflict
- Use JS function as CSS value
- Conditional Apply CSS
- [Server Rendering][server]
Usage - Wiki - API - Demo - React - Babel
Install:
npm
npm install cssobj # the lib
# When use Babel
npm install babel-plugin-transform-cssobj
# When **NOT** use Babel, install the converter
npm install -g cssobj-converter
browser
<script src="https://unpkg.com/cssobj"></script>
Usage
First see this SIMPLE DEMO
In the example, cssobj will create <style> tag in HEAD, render CSS rules inside
import cssobj from 'cssobj'
const obj = {
div: {
backgroundColor: 'yellow',
color: 'red',
// simulate 50vh in CSS3
height: () => window.innerHeight/2 + 'px'
}
}
const result = cssobj(obj)
// dynamic update height when resize
window.onresize = () => result.update()
The rendered CSS (height is dynamically set to 50% of window height)
div { background-color: yellow; color: red; height: 600px; }
If you read the code, you've learned the API already:
Only One top level method: cssobj( obj, [config] ), all other things using result.someMethods, that's all, really.
Stylesheet CRUD
The power of cssobj is CSS CRUD (Create, Read, Update, Delete), dynamically change above CSS, see below:
1. Update property values
You want to change color to 'blue'
// using static value:
obj.div.color = 'blue'
result.update() // color is now 'blue'
// using function as value:
obj.div.color = function(v){
return randomColor()
}
result.update() // color is now random
2. Delete/Remove properties
You want to remove backgroundColor
It's just work as you expected:
delete obj.div.backgroundColor
result.update()
3. Create/Add new properties
You want to add 'float' and 'clear'
It's just work as you expected:
obj.div.float = 'left'
obj.div.clear = 'both'
result.update()
4. Create/Add new rules
You want to add ':after' rule, and div span rule
obj.div['&:after'] = { fontSize:'10px', content:'"---"' }
obj.div.span = { fontSize: '18px' }
result.update()
5. Update/Replace rules
You want to replace the whole rule
obj.div.span = { color: 'green', fontSize: '20px' }
result.update()
All the above can use function instead
obj.div.span = function() {
return { color: randomColor(), fontSize: currentSize + 'px' }
}
result.update()
6. Delete/Remove rules
You want to remove div span rule
delete obj.div.span
result.update()
7. Read a rule
Although cssobj can manage everything, you read the rule in stylesheet manually
const rule = result.root.children.div.omRule[0]
// => CSSStyleRule
rule.color = 'red'
8. Delete/Destroy cssobj
Currently, cssobj don't provide result.destroy() or similar method, you should manually destroy things:
// remove <style> tag
result.cssdom.parentNode.removeChild(el)
// GC result
result = null
Think of this: one cssobj instance === A <style> tag with rules <kbd>+</kbd> A manager from JS
At-Rules
All @-rules work as expected, and @media can be nested at any level:
cssobj({
'.nav':{
width: '1024px',
'@media print': {
display: 'none'
}
}
})
Above will hide .nav when print.
You can emit any @media rule by cssom.media option:
const result = cssobj({
'.nav':{
width: '1024px',
'@media print': {
color: 'red'
}
}
}, { cssom: { media:'' } })
result.config.cssom.media = 'print'
result.update()
Above will switch to print view, with below CSS:
nav {width: 1024px;}
nav {color: red;}
Then switch back:
result.config.cssom.media = ''
result.update()
cssobj({
'@keyframes changeColor': {
'0%': { backgroundColor: 'green' },
'100%': { backgroundColor: 'yellow' }
},
'.nav': {
backgroundColor: 'red',
animation: '5s infinite changeColor'
}
})
Notice above @keyframes, it have to be in top level of your source object, aka cannot be nested into .nav,
that is different from @media rule, which allow nested at any level, or nested into another @media:
cssobj({
h3:{
color: 'blue',
'@media (min-width: 400px)': {
color: 'red',
'@media (max-width: 500px)': {
color: 'green'
}
},
'@media (min-width: 500px)': {
color: 'purple'
}
}
})
Above, what's the color will be? You can take a try and see what's the final CSS will be.
There's a hidden JS Bin...
Localize class names
Passing local: true as option, cssobj will add a random name space into all class names, this is called localize:
const result = cssobj(
{
'.nav': {color: 'red'}
},
{ local: true }
)
Rendered CSS:
.nav_1lwyllh4_ {color: red;}
You can get this name space using result.space, or using below methods:
// As HTML class attribute
result.mapClass('nav active') // [string] 'nav_1lwyllh4_ active_1lwyllh4_'
// As CSS selector
result.mapSel('.nav li.item') // [string] '.nav_1lwyllh4_ li.item_1lwyllh4_'
React
You can use react-cssobj with React, like below:
import React from 'react'
import ReactCSS from 'react-cssobj'
const {css, mapClass} = ReactCSS({
'.app': {
background: 'red'
}
})
export default class App extends React.Component {
render(){
return mapClass (<div className = 'app'>App</div>)
}
}
Work Flow with Babel, See also Without Babel Version
If use Babel, recommended the babel-plugin-transform-cssobj
// create <style> in <head>, insert CSS rules, random namespace: _1jkhrb92_
// The babel-plugin only transform: CSSOBJ `text`
const result = CSSOBJ `
---
# cssobj config
local: true
plugins:
- default-unit: px
---
// SCSS style (nested)
.nav {
color: blue;
height: 100;
// font-size is a function
.item { color: red; font-size: ${v => v.raw ? v.raw + 1 : 12} }
// nested @media
@media (max-width: 800px) {
color: #333;
// & = parent selector = .nav
&:active {
color: #666;
}
}
}
`
const html = result.mapClass(<ul class='nav'><li class='item active'>ITEM</li></ul>)
// <ul class="nav_1jkhrb92_"><li class="item_1jkhrb92_ active_1jkhrb92_"></li></ul>
Rendered result as below:
import cssobj from "cssobj";
import cssobj_plugin_default_unit from "cssobj-plugin-default-unit";
const result = cssobj({
'.nav': {
color: 'blue',
height: 100,
'.item': {
color: 'red',
fontSize: v => v.raw ? v.raw + 1 : 12
},
'@media (max-width: 800px)': {
color: '#333',
'&:active': {
color: '#666'
}
}
}
}, {
local: true,
plugins: [cssobj_plugin_default_unit('px')]
});
const html = <ul class={result.mapClass('nav')}><li class={result.mapClass('item active')}></li></ul>
For this first time render,
all class names add a random suffix _1jkhrb92_,
the font-size is 12px,
the <style> tag which cssobj created now contains:
.nav_1jkhrb92_ { color: blue; height: 100px; }
.nav_1jkhrb92_ .item_1jkhrb92_ { color: red; font-size: 12px; }
@media (max-width: 800px) {
.nav_1jkhrb92_ { color: rgb(51, 51, 51); }
.nav_1jkhrb92_:active { color: rgb(102, 102, 102); }
}
Update CSS Value
Since we already have a function as the value:
fontSize: v => v.raw ? v.raw + 1 : 12
-
the value (===
v.raw) initialised with12(default-unitplugin will addpxwhen rendering, that isv.cooked===12px) -
each call of the function will increase
font-sizeby 1
So, just need call result.update, the function invoked, stylesheet updated, a
