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
- Put class names into local space No Conflict
- Use JS function as CSS value
- Conditional Apply CSS
- Server Rendering
Usage - Wiki - API - Demo - React - Babel
Install:
npm
npm install cssobj # the lib# When use Babelnpm install babel-plugin-transform-cssobj# When **NOT** use Babel, install the converternpm install -g cssobj-converter
browser
Usage
First see this SIMPLE DEMO
In the example, cssobj
will create <style>
tag in HEAD, render CSS rules inside
const obj = div: backgroundColor: 'yellow' color: 'red' // simulate 50vh in CSS3 windowinnerHeight/2 + 'px' const result = // dynamic update height when resizewindow result
The rendered CSS (height
is dynamically set to 50% of window height)
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:objdivcolor = 'blue'result // color is now 'blue' // using function as value:objdiv{ return }result // color is now random
2. Delete/Remove properties
You want to remove backgroundColor
It's just work as you expected:
delete objdivbackgroundColorresult
3. Create/Add new properties
You want to add 'float'
and 'clear'
It's just work as you expected:
objdivfloat = 'left'objdivclear = 'both'result
4. Create/Add new rules
You want to add ':after'
rule, and div span
rule
objdiv'&:after' = fontSize:'10px' content:'"---"' objdivspan = fontSize: '18px' result
5. Update/Replace rules
You want to replace the whole rule
objdivspan = color: 'green' fontSize: '20px' result
All the above can use function
instead
objdiv { return color: fontSize: currentSize + 'px' }result
6. Delete/Remove rules
You want to remove div span
rule
delete objdivspanresult
7. Read a rule
Although cssobj
can manage everything, you read the rule in stylesheet manually
const rule = resultrootchildrendivomRule0// => CSSStyleRulerulecolor = 'red'
8. Delete/Destroy cssobj
Currently, cssobj
don't provide result.destroy()
or similar method, you should manually destroy things:
// remove <style> tagresultcssdomparentNode// GC resultresult = null
Think of this: one cssobj
instance === A <style>
tag with rules + A manager from JS
At-Rules
All @-rules
work as expected, and @media
can be nested at any level:
Above will hide .nav
when print.
You can emit any @media
rule by cssom.media
option:
const result = resultconfigcssommedia = 'print'result
Above will switch to print
view, with below CSS:
Then switch back:
resultconfigcssommedia = ''result
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
:
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 =
Rendered CSS:
You can get this name space
using result.space
, or using below methods:
// As HTML class attributeresult // [string] 'nav_1lwyllh4_ active_1lwyllh4_'// As CSS selectorresult // [string] '.nav_1lwyllh4_ li.item_1lwyllh4_'
React
You can use react-cssobj with React
Without Babel Version
Work Flow with Babel, See alsoIf 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 configlocal: trueplugins: - default-unit: px---// SCSS style (nested).nav { color: blue; height: 100; // font-size is a function .item { color: red; font-size: } // nested @media @media (max-width: 800px) { color: #333; // & = parent selector = .nav &:active { color: #666; } } }`const html = result// <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:
{}
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-unit
plugin will addpx
when rendering, that isv.cooked
===12px
) -
each call of the function will increase
font-size
by 1
So, just need call result.update
, the function invoked, stylesheet updated, automatically:
result// font-size -> 13pxresult// font-size -> 14px
Above, only font-size
changed, all other things keep untouched
CRUD (Create, Read, Update, Delete) stylesheet from JS
When the source JS Object (first arg of cssobj()
) have no changes,
result.update
only invoke the value function (here, the above font-size
function),
Otherwise, it will look into the source JS Object, find which part have been changed (diff), and update stylesheet accordingly. See below:
// result.obj === reference of the source js object // change a css propertyresultobj'.nav'color = 'orange' // remove a css propertydelete resultobj'.nav'height // add a new css propertyresultobj'.nav'width = 200 // add a new ruleresultobj'.nav'a = color: 'blue' '&:hover': textDecoration: 'none' // delete a ruledelete resultobj'.nav''.item' result // color -> 'orange' (PROP CHANGED)// height -> (PROP REMOVED)// width -> 200px (PROP ADDED)// a, a:hover -> (RULE ADDED)// .item -> (RULE REMOVED)
Above, only diffed part updated, other rules and props will keep untouched
Now, the stylesheet becomes:
{}
Diff with NEW JS Object
const newObj = '.nav': width: 100 a: color: 'blue'result// cssobj will DIFF with old obj, keep same part, change diffed part in stylesheet!// .nav, .nav a rules keeped// width -> 100px, drop all other rules/props
Now, the stylesheet becomes:
/* below 2 rules keeped *//* other rules gone */
That's it, see more Usage & Example
Work Flow (Without Babel)
First install cssobj-converter
npm install -g cssobj-converter
- Step 1
Write your CSS as normal (e.g. index.css)
//
- Step 2
Turn it into JS module, from cssobj-converter
CLI
# in command line, run cssobj-convertercssobj index.css -o index.css.js
The result
// file: index.css.jsmoduleexports ='.nav': color: 'blue' fontSize: '12px'
- Step 3
Let's rock:
// import your css moduleconst obj =// create <style> tag in <head>, with rules in obj.// `local: true` will put class names into local spaceconst result =result // with Babelresult // without Babel// update some ruleobj'.nav'color = 'red'obj'.nav' + 1 // increase font-size by 1result
Documented API
More to read:
-
!important CSSOBJ Format
How it worked?
-
cssobj first parse js object into Virtual CSSOM middle format.
-
The internal cssom plugin will create stylesheet dom, and apply rules from middle format.
-
When the js object changed, cssobj will diff CSSOM rules (add/delete/change) accordingly. (see demo)
Tools
Convert existing style sheet into cssobj:
-
CLI Converter Recommended CLI tools to convert CSS. Run
npm -g cssobj-converter
-
Online Converter It's free node server, slow, and unstalbe, not recommended
Debug
- cssobj-helper-showcss Display css string from style tag, for DEBUG
Plugins
About writing a plugin, See: plugin-guide
-
(already in core) cssobj-plugin-localize Localize class names
-
(already in core) cssobj-plugin-cssdom Inject style to DOM and diff update
-
cssobj-plugin-default-unit Add default unit to numeric values, e.g. width / height
-
cssobj-plugin-flexbox Make flexbox working right with auto prefixer/transform
-
cssobj-plugin-replace Merge cssobj Key/Value with new object
-
cssobj-plugin-extend Extend to another selector, like @extend in SCSS or :extend in LESS
-
cssobj-plugin-keyframes Make keyframe names localized, and apply to
animation
andanimation-name
-
cssobj-plugin-gencss Generate css text from Virtual CSS Node, for Server Rendering
Helpers
-
babel-plugin-transform-cssobj Work with React, Vue etc. that can use babel+jsx
-
cssobj-mithril Help cssobj to work with mithril
-
cssobj-helper-stylize Add css string into style dom
Demos
Test
Using phantom 2.0 to test with CSSOM. Please see test/ folder.
Remark
cssobj is wrapper for cssobj-core, plugin-localize and plugin-cssom.
License
MIT