Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/cssobj/cssobj
Runtime CSS manager, Turn CSS into dynamic JS module, Stylesheet CRUD (Create, Read, Update, Delete) in CSSOM, name space (local) class names
https://github.com/cssobj/cssobj
crud css-crud css-in-js cssobj cssom dynamic-style stylesheet-crud stylesheets
Last synced: 3 days ago
JSON representation
Runtime CSS manager, Turn CSS into dynamic JS module, Stylesheet CRUD (Create, Read, Update, Delete) in CSSOM, name space (local) class names
- Host: GitHub
- URL: https://github.com/cssobj/cssobj
- Owner: cssobj
- License: mit
- Created: 2016-07-17T13:48:33.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2018-03-25T00:09:56.000Z (over 6 years ago)
- Last Synced: 2024-12-12T17:23:39.604Z (10 days ago)
- Topics: crud, css-crud, css-in-js, cssobj, cssom, dynamic-style, stylesheet-crud, stylesheets
- Language: JavaScript
- Homepage: https://cssobj.github.io/cssobj-demo/
- Size: 655 KB
- Stars: 270
- Watchers: 12
- Forks: 13
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Changelog: ChangeLog
- License: LICENSE
Awesome Lists containing this project
README
# CSSOBJ [![Join the chat at https://gitter.im/css-in-js/cssobj](https://badges.gitter.im/css-in-js/cssobj.svg)](https://gitter.im/css-in-js/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](https://github.com/cssobj/cssobj/wiki/Work-with-popular-JS-Lib)
- [CSS Rules CRUD][CRUD]
- [Put class names into local space **No Conflict**](https://cssobj.github.io/cssobj-demo/#demo4)
- [Use JS function as CSS value](https://github.com/cssobj/cssobj/wiki/Function-as-CSS-Value)
- [Conditional Apply CSS](https://cssobj.github.io/cssobj-demo/test/test.html)
- [Server Rendering][server][Usage](https://github.com/cssobj/cssobj#usage) - [Wiki](https://github.com/cssobj/cssobj/wiki) - [API](https://github.com/cssobj/cssobj/blob/master/docs/api.md) - [Demo](https://cssobj.github.io/cssobj-demo/) - [React](https://github.com/cssobj/cssobj#react) - [Babel](https://github.com/cssobj/cssobj#work-flow-with-babel-see-also-without-babel-version)
[![Build Status](https://travis-ci.org/cssobj/cssobj.svg?branch=master)](https://travis-ci.org/cssobj/cssobj)
[![npm](https://img.shields.io/npm/v/cssobj.svg "Version")](https://www.npmjs.com/package/cssobj)
[![Coverage Status](https://coveralls.io/repos/github/cssobj/cssobj-core/badge.svg?branch=master)](https://coveralls.io/github/cssobj/cssobj-core?branch=master)
[![dependencies Status](https://david-dm.org/cssobj/cssobj/status.svg)](https://david-dm.org/cssobj/cssobj)
[![Standard - JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/)## Install:
#### npm
``` bash
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
``` html
```
## Usage
First see this [SIMPLE DEMO](http://jsbin.com/cibetuc/edit?html,js,output)
In the example, `cssobj` will create `` tag in HEAD, render CSS rules inside
```javascript
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)
``` css
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'`
```javascript
// 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:
```javascript
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:
```javascript
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
```javascript
obj.div['&:after'] = { fontSize:'10px', content:'"---"' }
obj.div.span = { fontSize: '18px' }
result.update()
```### 5. Update/Replace rules
You want to replace the whole rule
```javascript
obj.div.span = { color: 'green', fontSize: '20px' }
result.update()
```**All the above can use `function` instead**
```javascript
obj.div.span = function() {
return { color: randomColor(), fontSize: currentSize + 'px' }
}
result.update()
```### 6. Delete/Remove rules
You want to remove `div span` rule
```javascript
delete obj.div.span
result.update()
```### 7. Read a rule
Although `cssobj` can manage everything, you read the rule in stylesheet manually
```javascript
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:
```javascript
// 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:
```javascript
cssobj({
'.nav':{
width: '1024px',
'@media print': {
display: 'none'
}
}
})
```
Above will hide `.nav` when print.You can **emit** any `@media` rule by `cssom.media` option:
```javascript
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:
```css
nav {width: 1024px;}
nav {color: red;}
```Then switch back:
```js
result.config.cssom.media = ''
result.update()
`````` javascript
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`:``` javascript
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](https://jsbin.com/lavatit/edit?html,js,output)...
## Localize class names
Passing `local: true` as option, cssobj will add a random `name space` into all **class names**, this is called `localize`:
``` javascript
const result = cssobj(
{
'.nav': {color: 'red'}
},
{ local: true }
)
```Rendered CSS:
``` css
.nav_1lwyllh4_ {color: red;}
```You can get this `name space` using `result.space`, or using below methods:
``` javascript
// 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](https://github.com/futurist/react-cssobj) with React, like below:
```js
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](https://github.com/cssobj/cssobj#work-flow-without-babel)
If use [Babel](http://babeljs.io/docs/usage/cli/), recommended the [babel-plugin-transform-cssobj](https://github.com/cssobj/babel-plugin-transform-cssobj)
```javascript
// 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:
``` Javascript
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:``` css
.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 with `12` (`default-unit` plugin will add `px` when rendering, that is `v.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:
``` javascript
result.update()
// font-size -> 13pxresult.update()
// 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:```javascript
// result.obj === reference of the source js object// change a css property
result.obj['.nav'].color = 'orange'// remove a css property
delete result.obj['.nav'].height// add a new css property
result.obj['.nav'].width = 200// add a new rule
result.obj['.nav'].a = { color: 'blue', '&:hover': {textDecoration: 'none'} }// delete a rule
delete result.obj['.nav']['.item']result.update()
// 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:
``` css
.nav_1jkhrb92_ { color: orange; width: 200px; }
@media (max-width: 800px) {
.nav_1jkhrb92_ { color: #333; }
.nav_1jkhrb92_:active { color: #666; }
}
.nav_1jkhrb92_ a { color: blue; }
.nav_1jkhrb92_ a:hover { text-decoration: none; }
```#### Diff with NEW JS Object
``` javascript
const newObj = { '.nav': { width: 100, a: { color: 'blue' } } }
result.update(newObj)
// 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:
``` css
/* below 2 rules keeped */
.nav_1jkhrb92_ { width: 100px; }
.nav_1jkhrb92_ a { color: blue; }/* other rules gone */
```That's it, see more [Usage & Example](https://github.com/cssobj/cssobj/blob/master/docs/usage-example.md)
## Work Flow (Without Babel)
First install [cssobj-converter](https://github.com/cssobj/cssobj-converter)
``` javascript
npm install -g cssobj-converter
```- **Step 1**
Write your CSS as normal (e.g. *index.css*)
``` css
// file: index.css
.nav { color: blue; font-size: 12px; }
```- **Step 2**
Turn it into JS module, from `cssobj-converter` CLI
``` bash
# in command line, run cssobj-converter
cssobj index.css -o index.css.js
```The result
``` javascript
// file: index.css.js
module.exports = {
'.nav': { color: 'blue', fontSize: '12px' }
}
```- **Step 3**
Let's rock:
``` javascript
// import your css module
const obj = require('./index.css')// create <style> tag in <head>, with rules in obj.
// `local: true` will put class names into local space
const result = cssobj(obj, {local: true})result.mapClass(<JSX>) // with Babel
result.mapClass('classA') // without Babel// update some rule
obj['.nav'].color = 'red'
obj['.nav'].fontSize = v => parseInt(v.cooked) + 1 // increase font-size by 1
result.update()```
#### [Documented API](https://github.com/cssobj/cssobj/blob/master/docs/api.md)
#### More to read:
- **!important** [CSSOBJ Format](https://github.com/cssobj/cssobj/wiki/Input-Object-Format)
- [Understand Localization](https://github.com/cssobj/cssobj/wiki/Understand-Localization)
- [Working with Babel/JSX](https://github.com/cssobj/cssobj/wiki/Working-with-Babel-JSX)
- [Application Structure](https://github.com/cssobj/cssobj/wiki/Application-Module-Structure)
- [Merge multiple objects](https://github.com/cssobj/cssobj/wiki/Merge-Multiple-Objects)
- [Working with popular libs](https://github.com/cssobj/cssobj/wiki/Work-with-popular-JS-Lib)
- [Working with Stream](https://github.com/cssobj/cssobj/wiki/Working-With-Stream)
- [Server side rendering][server]
## How it worked?
1. **cssobj** first parse js object into **Virtual CSSOM** middle format.
2. The internal [cssom](https://github.com/cssobj/cssobj-plugin-cssom) plugin will create stylesheet dom, and apply rules from middle format.
3. When the js object changed, **cssobj** will diff CSSOM rules (**add/delete/change**) accordingly. (see [demo](https://cssobj.github.io/cssobj-demo/#demo1))
## Tools
Convert existing style sheet into *cssobj*:
- [CLI Converter](https://github.com/cssobj/cssobj-converter) **Recommended** CLI tools to convert CSS. Run `npm -g cssobj-converter`
- [Online Converter](http://convertcssobj-futurist.rhcloud.com/) It's free node server, slow, and unstalbe, not recommended
## Debug
- [cssobj-helper-showcss](https://github.com/cssobj/cssobj-helper-showcss) Display css string from style tag, for DEBUG
## Plugins
About writing a plugin, See: [plugin-guide](https://github.com/cssobj/cssobj/wiki/Plugin-Guide)
- **(already in core)** [cssobj-plugin-localize](https://github.com/cssobj/cssobj-plugin-localize) Localize class names
- **(already in core)** [cssobj-plugin-cssdom](https://github.com/cssobj/cssobj-plugin-cssom) Inject style to DOM and diff update
- [cssobj-plugin-default-unit](https://github.com/cssobj/cssobj-plugin-default-unit) Add default unit to numeric values, e.g. width / height
- [cssobj-plugin-flexbox](https://github.com/cssobj/cssobj-plugin-flexbox) Make flexbox working right with auto prefixer/transform
- [cssobj-plugin-replace](https://github.com/cssobj/cssobj-plugin-replace) Merge cssobj Key/Value with new object
- [cssobj-plugin-extend](https://github.com/cssobj/cssobj-plugin-extend) Extend to another selector, like [@extend](https://sass-lang.com/documentation/file.SASS_REFERENCE.html#extend) in SCSS or [:extend](http://lesscss.org/features/#extend-feature) in LESS
- [cssobj-plugin-keyframes](https://github.com/cssobj/cssobj-plugin-keyframes) Make keyframe names localized, and apply to `animation` and `animation-name`
- [cssobj-plugin-gencss](https://github.com/cssobj/cssobj-plugin-gencss) Generate css text from Virtual CSS Node, for **Server Rendering**
## Helpers
- [babel-plugin-transform-cssobj][babel] Work with React, Vue etc. that can use babel+jsx
- [cssobj-mithril](https://github.com/cssobj/cssobj-mithril) Help cssobj to work with [mithril](https://github.com/lhorie/mithril.js)
- [cssobj-helper-stylize](https://github.com/cssobj/cssobj-helper-stylize) Add css string into style dom
## Demos
- [cssobj-demo](https://github.com/cssobj/cssobj-demo)
## Test
Using [phantom](http://phantomjs.org/) 2.0 to test with CSSOM. Please see **test/** folder.
## Remark
cssobj is wrapper for [cssobj-core](https://github.com/cssobj/cssobj-core), [plugin-localize](https://github.com/cssobj/cssobj-plugin-localize) and [plugin-cssom](https://github.com/cssobj/cssobj-plugin-cssom).
## License
MIT
[babel]: https://github.com/cssobj/babel-plugin-transform-cssobj
[server]: https://github.com/cssobj/cssobj/wiki/Server-Side-Rendering
[CRUD]: https://github.com/cssobj/cssobj/wiki/Dynamically-update-css
[CSSOM]: http://dev.w3.org/csswg/cssom/