{"id":13431548,"url":"https://github.com/cssobj/cssobj","last_synced_at":"2025-04-07T06:07:33.813Z","repository":{"id":58244720,"uuid":"63534124","full_name":"cssobj/cssobj","owner":"cssobj","description":"Runtime CSS manager, Turn CSS into dynamic JS module, Stylesheet CRUD (Create, Read, Update, Delete) in CSSOM, name space (local) class names","archived":false,"fork":false,"pushed_at":"2018-03-25T00:09:56.000Z","size":671,"stargazers_count":272,"open_issues_count":2,"forks_count":13,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-03-31T05:04:21.773Z","etag":null,"topics":["crud","css-crud","css-in-js","cssobj","cssom","dynamic-style","stylesheet-crud","stylesheets"],"latest_commit_sha":null,"homepage":"https://cssobj.github.io/cssobj-demo/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cssobj.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-07-17T13:48:33.000Z","updated_at":"2024-12-24T13:52:02.000Z","dependencies_parsed_at":"2022-08-31T04:40:10.693Z","dependency_job_id":null,"html_url":"https://github.com/cssobj/cssobj","commit_stats":null,"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cssobj%2Fcssobj","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cssobj%2Fcssobj/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cssobj%2Fcssobj/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cssobj%2Fcssobj/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cssobj","download_url":"https://codeload.github.com/cssobj/cssobj/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247601448,"owners_count":20964864,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crud","css-crud","css-in-js","cssobj","cssom","dynamic-style","stylesheet-crud","stylesheets"],"created_at":"2024-07-31T02:01:03.970Z","updated_at":"2025-04-07T06:07:33.792Z","avatar_url":"https://github.com/cssobj.png","language":"JavaScript","readme":"\u003cimg align=\"right\" title=\"cssobj logo\" alt=\"cssobj logo\" align=\"bottom\" src=\"https://avatars0.githubusercontent.com/u/20465580?v=3\u0026s=132\" border=\"30\" hspace=\"0\" vspace=\"20\"\u003e\n\n# 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)\n\nRuntime CSS manager, Turn CSS into dynamic JS module, Stylesheet [CRUD][] (Create, Read, Update, Delete) in CSSOM, Solve common problems of CSS-in-JS.\n\n - ~4K min.gz, simple API\n - Nested rules, support any CSS selector/value\n - Minimal work to migrate\n - [Work with DOM Frameworks](https://github.com/cssobj/cssobj/wiki/Work-with-popular-JS-Lib)\n - [CSS Rules CRUD][CRUD]\n - [Put class names into local space **No Conflict**](https://cssobj.github.io/cssobj-demo/#demo4)\n - [Use JS function as CSS value](https://github.com/cssobj/cssobj/wiki/Function-as-CSS-Value)\n - [Conditional Apply CSS](https://cssobj.github.io/cssobj-demo/test/test.html)\n - [Server Rendering][server]\n\n[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)\n\n[![Build Status](https://travis-ci.org/cssobj/cssobj.svg?branch=master)](https://travis-ci.org/cssobj/cssobj)\n[![npm](https://img.shields.io/npm/v/cssobj.svg \"Version\")](https://www.npmjs.com/package/cssobj)\n[![Coverage Status](https://coveralls.io/repos/github/cssobj/cssobj-core/badge.svg?branch=master)](https://coveralls.io/github/cssobj/cssobj-core?branch=master)\n[![dependencies Status](https://david-dm.org/cssobj/cssobj/status.svg)](https://david-dm.org/cssobj/cssobj)\n[![Standard - JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/)\n\n\n## Install:\n\n#### npm\n\n``` bash\nnpm install cssobj  # the lib\n\n# When use Babel\nnpm install babel-plugin-transform-cssobj\n\n# When **NOT** use Babel, install the converter\nnpm install -g cssobj-converter\n```\n\n#### browser\n\n``` html\n\u003cscript src=\"https://unpkg.com/cssobj\"\u003e\u003c/script\u003e\n```\n\n## Usage\n\nFirst see this [SIMPLE DEMO](http://jsbin.com/cibetuc/edit?html,js,output)\n\nIn the example, `cssobj` will create `\u003cstyle\u003e` tag in HEAD, render CSS rules inside\n\n```javascript\nimport cssobj from 'cssobj'\n\nconst obj = {\n  div: {\n    backgroundColor: 'yellow',\n    color: 'red',\n    // simulate 50vh in CSS3\n    height: () =\u003e window.innerHeight/2 + 'px'\n  }\n}\nconst result = cssobj(obj)\n\n// dynamic update height when resize\nwindow.onresize = () =\u003e result.update()\n```\n\nThe rendered CSS (`height` is **dynamically** set to 50% of window height)\n\n``` css\ndiv { background-color: yellow; color: red; height: 600px; }\n```\n\nIf you read the code, you've learned the API already:\n\n**Only One** top level method: `cssobj( obj, [config] )`, all other things using `result.someMethods`, that's all, really.\n\n## Stylesheet CRUD\n\nThe power of cssobj is CSS CRUD (Create, Read, Update, Delete), **dynamically change above CSS**, see below:\n\n### 1. Update property values\n\nYou want to change color to `'blue'`\n\n```javascript\n\n// using static value:\nobj.div.color = 'blue'\nresult.update()  // color is now 'blue'\n\n\n// using function as value:\nobj.div.color = function(v){\n  return randomColor()\n}\nresult.update()  // color is now random\n\n```\n\n### 2. Delete/Remove properties\n\nYou want to remove `backgroundColor`\n\nIt's just work as you expected:\n\n```javascript\n\ndelete obj.div.backgroundColor\nresult.update()\n\n```\n\n### 3. Create/Add new properties\n\nYou want to add `'float'` and `'clear'`\n\nIt's just work as you expected:\n\n```javascript\nobj.div.float = 'left'\nobj.div.clear = 'both'\nresult.update()\n```\n\n### 4. Create/Add new rules\n\nYou want to add `':after'` rule, and `div span` rule\n\n```javascript\nobj.div['\u0026:after'] = { fontSize:'10px', content:'\"---\"' }\nobj.div.span = { fontSize: '18px' }\nresult.update()\n```\n\n### 5. Update/Replace rules\n\nYou want to replace the whole rule\n\n```javascript\nobj.div.span = { color: 'green', fontSize: '20px' }\nresult.update()\n```\n\n**All the above can use `function` instead**\n\n```javascript\nobj.div.span = function() {\n  return { color: randomColor(), fontSize: currentSize + 'px' }\n}\nresult.update()\n```\n\n### 6. Delete/Remove rules\n\nYou want to remove `div span` rule\n\n```javascript\ndelete obj.div.span\nresult.update()\n```\n\n### 7. Read a rule\n\nAlthough `cssobj` can manage everything, you read the rule in stylesheet manually\n\n```javascript\nconst rule = result.root.children.div.omRule[0]\n// =\u003e CSSStyleRule\nrule.color = 'red'\n```\n\n### 8. Delete/Destroy cssobj\n\nCurrently, `cssobj` don't provide `result.destroy()` or similar method, you should manually destroy things:\n\n```javascript\n// remove \u003cstyle\u003e tag\nresult.cssdom.parentNode.removeChild(el)\n// GC result\nresult = null\n```\n\nThink of this: one `cssobj` instance === A `\u003cstyle\u003e` tag with rules \u003ckbd\u003e+\u003c/kbd\u003e `A manager from JS`\n\n## At-Rules\n\nAll `@-rules` work as expected, and `@media` can be nested at any level:\n\n```javascript\ncssobj({\n  '.nav':{\n    width: '1024px',\n    '@media print': {\n      display: 'none'\n    }\n  }\n})\n```\nAbove will hide `.nav` when print.\n\nYou can **emit** any `@media` rule by `cssom.media` option:\n\n```javascript\nconst result = cssobj({\n  '.nav':{\n    width: '1024px',\n    '@media print': {\n      color: 'red'\n    }\n  }\n}, { cssom: { media:'' } })\n\nresult.config.cssom.media = 'print'\nresult.update()\n\n```\n\nAbove will switch to `print` view, with below CSS:\n\n```css\nnav {width: 1024px;}\nnav {color: red;}\n```\n\nThen switch back:\n\n```js\nresult.config.cssom.media = ''\nresult.update()\n```\n\n\n``` javascript\ncssobj({\n  '@keyframes changeColor': {\n    '0%': { backgroundColor: 'green' },\n    '100%': { backgroundColor: 'yellow' }\n  },\n  '.nav': {\n    backgroundColor: 'red',\n    animation: '5s infinite changeColor'\n  }\n})\n```\n\nNotice above `@keyframes`, it **have to be in top level** of your source object, aka cannot be nested into `.nav`,\nthat is different from `@media` rule, which allow nested at any level, or nested into another `@media`:\n\n``` javascript\ncssobj({\n  h3:{\n    color: 'blue',\n    '@media (min-width: 400px)': {\n      color: 'red',\n      '@media (max-width: 500px)': {\n          color: 'green'\n      }\n    },\n    '@media (min-width: 500px)': {\n      color: 'purple'\n    }\n  }\n})\n```\n\nAbove, what's the color will be? You can take a try and see what's the final CSS will be.\n\nThere's a hidden [JS Bin](https://jsbin.com/lavatit/edit?html,js,output)...\n\n## Localize class names\n\nPassing `local: true` as option, cssobj will add a random `name space` into all **class names**, this is called `localize`:\n\n``` javascript\nconst result = cssobj(\n  {\n    '.nav': {color: 'red'}\n  },\n  { local: true }\n)\n```\n\nRendered CSS:\n\n``` css\n.nav_1lwyllh4_ {color: red;}\n```\n\nYou can get this `name space` using `result.space`, or using below methods:\n\n``` javascript\n// As HTML class attribute\nresult.mapClass('nav active')  // [string] 'nav_1lwyllh4_ active_1lwyllh4_'\n\n// As CSS selector\nresult.mapSel('.nav li.item')  // [string] '.nav_1lwyllh4_ li.item_1lwyllh4_'\n```\n\n## React\n\nYou can use [react-cssobj](https://github.com/futurist/react-cssobj) with React, like below:\n\n\n```js\nimport React from 'react'\nimport ReactCSS from 'react-cssobj'\n\nconst {css, mapClass} = ReactCSS({\n  '.app': {\n    background: 'red'\n  }\n})\n\nexport default class App extends React.Component {\n  render(){\n    return mapClass (\u003cdiv className = 'app'\u003eApp\u003c/div\u003e)\n  }\n}\n```\n\n## Work Flow with Babel, See also [Without Babel Version](https://github.com/cssobj/cssobj#work-flow-without-babel)\n\nIf use [Babel](http://babeljs.io/docs/usage/cli/), recommended the [babel-plugin-transform-cssobj](https://github.com/cssobj/babel-plugin-transform-cssobj)\n\n```javascript\n// create \u003cstyle\u003e in \u003chead\u003e, insert CSS rules, random namespace: _1jkhrb92_\n\n// The babel-plugin only transform: CSSOBJ `text`\n\nconst result = CSSOBJ `\n---\n# cssobj config\nlocal: true\nplugins:\n  - default-unit: px\n---\n// SCSS style (nested)\n.nav {\n  color: blue;\n  height: 100;\n\n  // font-size is a function\n  .item { color: red; font-size: ${v =\u003e v.raw ? v.raw + 1 : 12} }\n\n  // nested @media\n  @media (max-width: 800px) {\n    color: #333;\n    // \u0026 = parent selector = .nav\n    \u0026:active {\n      color: #666;\n    }\n  }\n\n}\n`\nconst html = result.mapClass(\u003cul class='nav'\u003e\u003cli class='item active'\u003eITEM\u003c/li\u003e\u003c/ul\u003e)\n// \u003cul class=\"nav_1jkhrb92_\"\u003e\u003cli class=\"item_1jkhrb92_ active_1jkhrb92_\"\u003e\u003c/li\u003e\u003c/ul\u003e\n```\n\nRendered result as below:\n\n``` Javascript\nimport cssobj from \"cssobj\";\nimport cssobj_plugin_default_unit from \"cssobj-plugin-default-unit\";\nconst result = cssobj({\n  '.nav': {\n    color: 'blue',\n    height: 100,\n    '.item': {\n      color: 'red',\n      fontSize: v =\u003e v.raw ? v.raw + 1 : 12\n    },\n    '@media (max-width: 800px)': {\n      color: '#333',\n      '\u0026:active': {\n        color: '#666'\n      }\n    }\n  }\n}, {\n  local: true,\n  plugins: [cssobj_plugin_default_unit('px')]\n});\n\nconst html = \u003cul class={result.mapClass('nav')}\u003e\u003cli class={result.mapClass('item active')}\u003e\u003c/li\u003e\u003c/ul\u003e\n```\n\nFor this first time render,\nall class names add a random suffix `_1jkhrb92_`,\nthe `font-size` is `12px`,\nthe `\u003cstyle\u003e` tag which `cssobj` created now contains:\n\n``` css\n.nav_1jkhrb92_ { color: blue; height: 100px; }\n.nav_1jkhrb92_ .item_1jkhrb92_ { color: red; font-size: 12px; }\n@media (max-width: 800px) {\n  .nav_1jkhrb92_ { color: rgb(51, 51, 51); }\n  .nav_1jkhrb92_:active { color: rgb(102, 102, 102); }\n}\n```\n\n#### Update CSS Value\n\nSince we already have a function as the value:\n\n  `fontSize: v =\u003e v.raw ? v.raw + 1 : 12`\n\n - the value (===`v.raw`) initialised with `12` (`default-unit` plugin will add `px` when rendering, that is `v.cooked` === `12px`)\n\n - each call of the function will increase `font-size` by 1\n\nSo, just need call `result.update`, the function invoked, stylesheet updated, automatically:\n\n``` javascript\nresult.update()\n// font-size  -\u003e  13px\n\nresult.update()\n// font-size  -\u003e  14px\n```\n\nAbove, only `font-size` changed, all other things **keep untouched**\n\n#### CRUD (Create, Read, Update, Delete) stylesheet from JS\n\nWhen the source JS Object (`first arg of cssobj()`) have no changes,\n`result.update` only invoke the value function (here, the above `font-size` function),\n\nOtherwise, it will look into the source JS Object, find which part have been changed (**diff**),\nand update stylesheet accordingly. See below:\n\n```javascript\n// result.obj === reference of the source js object\n\n// change a css property\nresult.obj['.nav'].color = 'orange'\n\n// remove a css property\ndelete result.obj['.nav'].height\n\n// add a new css property\nresult.obj['.nav'].width = 200\n\n// add a new rule\nresult.obj['.nav'].a = { color: 'blue', '\u0026:hover': {textDecoration: 'none'} }\n\n// delete a rule\ndelete result.obj['.nav']['.item']\n\nresult.update()\n\n// color      -\u003e  'orange' (PROP CHANGED)\n// height     -\u003e   (PROP REMOVED)\n// width      -\u003e   200px (PROP ADDED)\n// a, a:hover -\u003e   (RULE ADDED)\n// .item      -\u003e   (RULE REMOVED)\n\n```\n\nAbove, **only** diffed part updated, other rules and props will **keep untouched**\n\nNow, the stylesheet becomes:\n\n``` css\n.nav_1jkhrb92_ { color: orange; width: 200px; }\n@media (max-width: 800px) {\n  .nav_1jkhrb92_ { color: #333; }\n  .nav_1jkhrb92_:active { color: #666; }\n}\n.nav_1jkhrb92_ a { color: blue; }\n.nav_1jkhrb92_ a:hover { text-decoration: none; }\n```\n\n#### Diff with NEW JS Object\n\n``` javascript\nconst newObj = { '.nav': { width: 100, a: { color: 'blue' } } }\nresult.update(newObj)\n// cssobj will DIFF with old obj, keep same part, change diffed part in stylesheet!\n// .nav, .nav a   rules keeped\n// width -\u003e 100px, drop all other rules/props\n```\n\nNow, the stylesheet becomes:\n\n``` css\n/* below 2 rules keeped */\n.nav_1jkhrb92_ { width: 100px; }\n.nav_1jkhrb92_ a { color: blue; }\n\n/* other rules gone */\n```\n\nThat's it, see more [Usage \u0026 Example](https://github.com/cssobj/cssobj/blob/master/docs/usage-example.md)\n\n## Work Flow (Without Babel)\n\nFirst install [cssobj-converter](https://github.com/cssobj/cssobj-converter)\n\n``` javascript\nnpm install -g cssobj-converter\n```\n\n- **Step 1**\n\nWrite your CSS as normal (e.g. *index.css*)\n\n``` css\n// file: index.css\n.nav { color: blue; font-size: 12px; }\n```\n\n- **Step 2**\n\nTurn it into JS module, from `cssobj-converter` CLI\n\n``` bash\n# in command line, run cssobj-converter\ncssobj index.css -o index.css.js\n```\n\nThe result\n\n``` javascript\n// file: index.css.js\nmodule.exports = {\n  '.nav': { color: 'blue', fontSize: '12px' }\n}\n```\n\n- **Step 3**\n\nLet's rock:\n\n``` javascript\n// import your css module\nconst obj = require('./index.css')\n\n// create \u003cstyle\u003e tag in \u003chead\u003e, with rules in obj.\n// `local: true` will put class names into local space\nconst result = cssobj(obj, {local: true})\n\nresult.mapClass(\u003cJSX\u003e)  // with Babel\nresult.mapClass('classA')  // without Babel\n\n// update some rule\nobj['.nav'].color = 'red'\nobj['.nav'].fontSize = v =\u003e parseInt(v.cooked) + 1  // increase font-size by 1\nresult.update()\n\n```\n\n#### [Documented API](https://github.com/cssobj/cssobj/blob/master/docs/api.md)\n\n\n#### More to read:\n\n  - **!important** [CSSOBJ Format](https://github.com/cssobj/cssobj/wiki/Input-Object-Format)\n\n  - [Understand Localization](https://github.com/cssobj/cssobj/wiki/Understand-Localization)\n\n  - [Working with Babel/JSX](https://github.com/cssobj/cssobj/wiki/Working-with-Babel-JSX)\n\n  - [Application Structure](https://github.com/cssobj/cssobj/wiki/Application-Module-Structure)\n\n  - [Merge multiple objects](https://github.com/cssobj/cssobj/wiki/Merge-Multiple-Objects)\n\n  - [Working with popular libs](https://github.com/cssobj/cssobj/wiki/Work-with-popular-JS-Lib)\n\n  - [Working with Stream](https://github.com/cssobj/cssobj/wiki/Working-With-Stream)\n\n  - [Server side rendering][server]\n\n## How it worked?\n\n1. **cssobj** first parse js object into **Virtual CSSOM** middle format.\n\n2. The internal [cssom](https://github.com/cssobj/cssobj-plugin-cssom) plugin will create stylesheet dom, and apply rules from middle format.\n\n3. When the js object changed, **cssobj** will diff CSSOM rules (**add/delete/change**) accordingly. (see [demo](https://cssobj.github.io/cssobj-demo/#demo1))\n\n## Tools\n\n  Convert existing style sheet into *cssobj*:\n\n  - [CLI Converter](https://github.com/cssobj/cssobj-converter) **Recommended** CLI tools to convert CSS. Run `npm -g cssobj-converter`\n\n  - [Online Converter](http://convertcssobj-futurist.rhcloud.com/) It's free node server, slow, and unstalbe, not recommended\n\n## Debug\n\n  - [cssobj-helper-showcss](https://github.com/cssobj/cssobj-helper-showcss) Display css string from style tag, for DEBUG\n\n## Plugins\n\n  About writing a plugin, See: [plugin-guide](https://github.com/cssobj/cssobj/wiki/Plugin-Guide)\n\n  - **(already in core)** [cssobj-plugin-localize](https://github.com/cssobj/cssobj-plugin-localize) Localize class names\n\n  - **(already in core)** [cssobj-plugin-cssdom](https://github.com/cssobj/cssobj-plugin-cssom) Inject style to DOM and diff update\n\n  - [cssobj-plugin-default-unit](https://github.com/cssobj/cssobj-plugin-default-unit) Add default unit to numeric values, e.g. width / height\n\n  - [cssobj-plugin-flexbox](https://github.com/cssobj/cssobj-plugin-flexbox) Make flexbox working right with auto prefixer/transform\n\n  - [cssobj-plugin-replace](https://github.com/cssobj/cssobj-plugin-replace) Merge cssobj Key/Value with new object\n\n  - [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\n\n  - [cssobj-plugin-keyframes](https://github.com/cssobj/cssobj-plugin-keyframes) Make keyframe names localized, and apply to `animation` and `animation-name`\n\n  - [cssobj-plugin-gencss](https://github.com/cssobj/cssobj-plugin-gencss) Generate css text from Virtual CSS Node, for **Server Rendering**\n\n## Helpers\n\n  - [babel-plugin-transform-cssobj][babel] Work with React, Vue etc. that can use babel+jsx\n\n  - [cssobj-mithril](https://github.com/cssobj/cssobj-mithril) Help cssobj to work with [mithril](https://github.com/lhorie/mithril.js)\n\n  - [cssobj-helper-stylize](https://github.com/cssobj/cssobj-helper-stylize) Add css string into style dom\n\n## Demos\n\n  - [cssobj-demo](https://github.com/cssobj/cssobj-demo)\n\n## Test\n\nUsing [phantom](http://phantomjs.org/) 2.0 to test with CSSOM. Please see **test/** folder.\n\n## Remark\n\ncssobj 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).\n\n## License\n\nMIT\n\n[babel]: https://github.com/cssobj/babel-plugin-transform-cssobj\n[server]: https://github.com/cssobj/cssobj/wiki/Server-Side-Rendering\n[CRUD]: https://github.com/cssobj/cssobj/wiki/Dynamically-update-css\n[CSSOM]: http://dev.w3.org/csswg/cssom/\n","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcssobj%2Fcssobj","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcssobj%2Fcssobj","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcssobj%2Fcssobj/lists"}