{"id":21414880,"url":"https://github.com/magic/css","last_synced_at":"2025-07-14T04:31:17.920Z","repository":{"id":53508047,"uuid":"159618088","full_name":"magic/css","owner":"magic","description":"css in js","archived":false,"fork":false,"pushed_at":"2024-12-15T23:39:23.000Z","size":2047,"stargazers_count":4,"open_issues_count":3,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-26T10:18:58.454Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/magic.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-11-29T06:24:45.000Z","updated_at":"2025-06-09T19:02:47.000Z","dependencies_parsed_at":"2024-11-22T18:36:08.058Z","dependency_job_id":"f50e7a01-1cf8-4e86-af52-11f221379d0c","html_url":"https://github.com/magic/css","commit_stats":null,"previous_names":[],"tags_count":46,"template":false,"template_full_name":null,"purl":"pkg:github/magic/css","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magic%2Fcss","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magic%2Fcss/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magic%2Fcss/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magic%2Fcss/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/magic","download_url":"https://codeload.github.com/magic/css/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magic%2Fcss/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265240091,"owners_count":23732938,"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":[],"created_at":"2024-11-22T18:34:23.812Z","updated_at":"2025-07-14T04:31:17.530Z","avatar_url":"https://github.com/magic.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @magic/css\n\nparse/stringify/write css in js\n\n[html docs](https://magic.github.io/css/)\n\n[![NPM version][npm-image]][npm-url]\n[![Linux Build Status][travis-image]][travis-url]\n[![Windows Build Status][appveyor-image]][appveyor-url]\n[![Coverage Status][coveralls-image]][coveralls-url]\n[![Greenkeeper badge][greenkeeper-image]][greenkeeper-url]\n[![Known Vulnerabilities][snyk-image]][snyk-url]\n\n[npm-image]: https://img.shields.io/npm/v/@magic/css.svg\n[npm-url]: https://www.npmjs.com/package/@magic/css\n[travis-image]: https://api.travis-ci.com/magic/css.svg?branch=master\n[travis-url]: https://travis-ci.com/magic/css\n[appveyor-image]: https://img.shields.io/appveyor/ci/magic/css/master.svg\n[appveyor-url]: https://ci.appveyor.com/project/magic/css/branch/master\n[coveralls-image]: https://coveralls.io/repos/github/magic/css/badge.svg\n[coveralls-url]: https://coveralls.io/github/magic/css\n[greenkeeper-image]: https://badges.greenkeeper.io/magic/css.svg\n[greenkeeper-url]: https://badges.greenkeeper.io/magic/css.svg\n[snyk-image]: https://snyk.io/test/github/magic/css/badge.svg\n[snyk-url]: https://snyk.io/test/github/magic/css\n\n##### installation:\n\n```javascript\n  npm install --save-exact @magic/css\n```\n\n#### usage:\n\n##### cli:\n\n@magic/css includes a cli script that can handle most usecases the internal javascript api allows.\n\nto use this cli from any directory,\n`npm install -g @magic.css` is a useful shortcut.\nafter the global install, you can just call `mcss` from anywhere in your terminal.\n\nafter installation, add:\n`\"mcss\": \"mcss\"`\nto your package.json \"scripts\" section and then\n`npm run mcss`\nto see the help output below.\n\n```\n@magic/css\ncommands:\nstringify - convert css in js to css\nparse     - convert css in js to an array of key value pairs\nfull      - get a full result object.\n\nflags:\n--minified - output minified css - alias: [\"--m\", \"-m\"]\n--help     - alias: [\"-h\"]\n--out      - directory to write output files to. omit to print to stdout - alias: [\"--o\", \"-o\"]\n--in       - directory with source files, needs index.js to exist - alias: [\"--i\", \"-i\"]\n\nexamples:\nmcss parse --in ./styles --out ./css\nmcss stringify --in ./styles --out ./css\nmcss full --in ./styles --out ./css\n```\n\n#### library:\n\n##### init\n\n```javascript\nimport css from '@magic/css'\n```\n\n##### all in one\n\n```javascript\nimport css from '@magic/css'\n\nconst style = {\n  body: {\n    color: 'green',\n  },\n  '.class': {\n    color: 'orange',\n  },\n  '#id': {\n    color: 'purple',\n  },\n}\n\ncss(style)\n\n// returns\nObject {\n  // nicely formatted css string\n  css: 'body {\\n  color: green;\\n}\\n.class {\\n  color: orange;\\n}\\n#id{\\n  color: purple;\\n}\\n',\n  // minimal whitespace\n  minified: 'body{color:green}.class{color:orange}#id{color:purple}',\n  // array of used classes if any\n  classes: ['.class'],\n  // array of used ids if any\n  ids: ['#id'],\n  // array of used selectors\n  selectors: ['body', '.class', '.id'],\n  // ast of this css object\n  parsed: [\n    ['body', { color: 'green' }],\n    ['.class': { color: 'orange' }],\n    ['#id': { color: 'purple' }],\n  ],\n}\n```\n\n##### styles\n\n```javascript\nconst style = {\n  '.className': {\n    color: 'green',\n  },\n}\nawait css.stringify(style)\n\n// .className { color:green; }\n```\n\n##### hover/active etc\n\n```javascript\nconst style = {\n  div: {\n    color: 'red',\n    '\u0026:hover': {\n      color: 'green',\n    },\n  },\n}\n\nawait css.stringify(style)\n\n// div { color: red; }\n// div:hover { color: green; }\n```\n\n##### nesting / suffix\n\nto suffix some of the selectors, add a \u0026 to any of them except the first one\n\n```javascript\nconst style = {\n  div: {\n    '.class1, \u0026.class2': {\n      color: 'red',\n    },\n  },\n}\n\nawait css.stringify(style)\n\n// div .class1, div.class2 { color: red; }\n```\n\nif you add the \u0026 at the start of the string,\nall of the selectors will have it applied\n\n```javascript\nconst style = {\n  div: {\n    '\u0026.class1, .class2': {\n      color: 'orange',\n    },\n  },\n}\n\nawait css.stringify(style)\n\n// div.class1, div.class2 { color: orange; }\n```\n\n##### prefix without space\n\nto prefix the parent of the selector using the child selectors,\nadd a \u0026 at the end of any selectors but the last one.\n\n```javascript\nconst style = {\n  '.class': {\n    'p\u0026, :hover': {\n      color: 'orange',\n    },\n  },\n}\n\nawait css.stringify(style)\n\n// p.class, .class:hover { color: orange; }\n```\n\n##### prefix all without space\n\nif the \u0026 is at the end of a selector,\nthe \u0026 will be applied to each of them.\n\n```javascript\nconst style = {\n  '.class': {\n    'div, p\u0026': {\n      color: 'orange';\n    },\n  },\n}\n\nawait css.stringify(style)\n\n// div.class, p.class { color: orange; }\n```\n\n##### prefix with space\n\nto prefix the parent with a space, use a double \u0026\u0026 instead of a single \u0026\n\n```javascript\nconst style = {\n  '#id': {\n    '.class2\u0026\u0026, .class3': {\n      color: 'orange';\n    },\n  },\n}\n\nawait css.stringify(style)\n\n// .class2 #id, #id.class3 { color: orange; }\n```\n\n##### prefix all with space\n\nif the \u0026\u0026 is at the end of a selector,\nthe \u0026\u0026 will be applied to each of them.\n\n```javascript\nconst style = {\n  '.class': {\n    'div, p\u0026\u0026': {\n      color: 'orange';\n    },\n  },\n}\n\nawait css.stringify(style)\n\n// div .class, p .class { color: orange; }\n```\n\n##### parse\n\n```javascript\nconst style = {\n  '.className': {\n    '#id': {\n      color: 'orange',\n    },\n  },\n}\n\ncss.parse(style)\n\n// ast\n```\n\n##### stringify\n\n```javascript\nconst style = {\n  '.className': {\n    '#id': {\n      color: 'white',\n    },\n  },\n}\n\nawait css.stringify(\n  style,\n) // minified string\n`.className #id{color:white;}`\n```\n\n##### write to filesystem\n\n```javascript\nconst style = {\n  '.className': {\n    '#id': {\n      color: opts.textColor,\n    },\n  },\n}\n\n// writes styles to ./out.css\nawait css.write(style)\n\n// writes styles to ./outfile.css\nawait css.write(style, { OUTFILE: './outfile.css' })\n```\n\n##### media queries\n\nMediaqueries can use the vars.widths object to determine appropriate breakpoint sizes.\n\nDefault widths:\n\n```javascript\nopts.widths = {\n  tablet: '500px',\n  laptop: '900px',\n  desktop: '1200px',\n  agency: '1600px',\n}\n```\n\n```javascript\nconst style = {\n  [`@media screen and (min-width: ${vars.widths?.tablet || '500px'})`]: {\n    '#id': {\n      color: opts.textColor,\n    },\n  },\n}\n\nawait css.stringify(\n  style,\n) // css string\n`\n@media screen and (min-width: 500px) {\n  #id {\n    color: green;\n  }\n}\n`\n```\n\n##### webfonts\n\n```javascript\nconst style = {\n  '@font-face': {\n    family: 'font-name',\n    url: '/fonts/',\n    styles: ['normal', 'italic'],\n    weights: [400, 600],\n  },\n}\n\nawait css.stringify(\n  style,\n) // css string\n`\n@font-face {\n  font-family: \"font-name\";\n  font-style: normal;\n  font-weight: normal;\n  src: url('/fonts/font-name-400-normal.eot\\');\n  src: url('/fonts/font-name-400-normal.eot#iefix') format('embedded-opentype'),',\n  url('/fonts/font-name-400-normal.ttf') format('truetype'),',\n  url('/fonts/font-name-400-normal.woff') format('woff'),',\n  url('/fonts/font-name-400-normal.woff2') format('woff2'),',\n  url('/fonts/font-name-400-normal.svg#font-name') format('svg');',\n}\n`\n// ... repeated for all styles and weights that were defined\n```\n\n### CHANGELOG:\n\n#### 0.1.0\n\nreturn classes and ids as well\n\n#### 0.2.0:\n\nAdded media queries\n\n#### 0.3.0:\n\n- returns a promise! no longer sync.\n- autoprefixer and postcss added\n\n### 0.4.0:\n\nsupports @font-face declarations\n\n#### 0.4.1\n\nadded fontDir option to font-face declarations\n\n#### 0.4.2\n\nupdate deps to fix security issues\n\n#### 0.4.3\n\nadded @keyframes for animations\n\n#### 0.4.4\n\ncss.parse now converts deep arrays into one object before parsing\n\n#### 0.4.5\n\n- css.stringify now makes a bit nicer mediaquery and keyframe lines.\n- css.parse should now order media queries to the end of the css\n\n#### 0.4.6\n\ncss.parse does a better job of keeping order of incoming objects intact\n\n#### 0.4.7\n\n- FIX: multiple parent selectors 'h1,h2,h3' that should get appended\n  with a \u0026:hover etc now correctly append the suffix to every parent\n- FEATURE: \u0026 can be at the end of a selector,\n  in which case the selector gets prepended to it's parent.\n\n#### 0.5.0\n\nFIX: css gets returned in almost the same order it got passed in.\nturns out that javascript objects do not make this as easy as hoped.\n\n#### 0.6.0\n\nuse esmodules\n\n#### 0.7.0\n\nupdate @magic/types to not break if es modules get passed into the styles\n\n#### 0.7.1\n\n- update @magic/deep to use ecmascript module version\n- update postcss, autoprefixer\n\n#### 0.7.2\n\nupdate dependencies\n\n#### 0.7.3\n\nupdate dependencies\n\n#### 0.7.4\n\nadd @magic/log to dependencies\n\n#### 0.7.5\n\nupdate autoprefixer\n\n#### 0.7.6\n\nupdate postcss\n\n#### 0.7.7\n\nupdate postcss\n\n#### 0.7.8\n\nupdate @magic/deep\n\n#### 0.7.9\n\nrequire node \u003e= 13.5.0\n\n#### 0.7.10\n\nupdate postcss\n\n##### 0.7.11\n\nupdate autoprefixer\n\n##### 0.7.12\n\nupdate postcss\n\n##### 0.7.13\n\n- bump required node version to 14.2.0\n- write is async now\n\n##### 0.7.14\n\n- update autoprefixer, dependencies\n\n##### 0.7.15\n\n- update dependencies\n\n##### 0.7.16\n\nupdate autoprefixer\n\n##### 0.7.17\n\nupdate autoprefixer\n\n##### 0.7.18\n\n- move no-spy to devdeps\n- update dependencies\n\n##### 0.7.19\n\nupdate autoprefixer\n\n##### 0.7.20\n\nupdate dependencies\n\n##### 0.7.21\n\nupdate dependencies\n\n##### 0.7.22\n\nupdate dependencies\n\n##### 0.7.23\n\nupdate dependencies\n\n##### 0.7.24\n\nupdate dependencies\n\n##### 0.7.25\n\nupdate dependencies\n\n##### 0.7.26\n\nupdate dependencies\n\n##### 0.7.27\n\nupdate dependencies\nsimplify font-face handling\n\n##### 0.7.28\n\n- bump required node version to 14.15.4\n- update dependencies\n\n##### 0.7.29\n\n- font-face handles non-array weights, types and styles\n- font-face uses woff and woff2 as default font types\n- font-face uses weight 400 and styles 'normal' as defaults\n\n##### 0.7.30\n\nupdate dependencies\n\n##### 0.7.31\n\nupdate dependencies (@magic/fs)\n\n##### 0.7.32\n\n- update dependencies\n- css.selectors returns arrays instead of strings\n\n##### 0.7.33\n\nupdate dependencies\n\n##### 0.7.34\n\nupdate dependency autoprefixer\n\n##### 0.7.35\n\nupdate dependency @magic/fs\n\n##### 0.7.36\n\nremove local implementation of camel2kebab, use @magic/cases instead\n\n#### 0.7.37\n\nupdate dependencies\n\n#### 0.7.38\n\n**FIX**: update @magic/cases, which fixes overflow-x and other css props that end with an uppercase character\noverflowX is output as overflowx in earlier versions, the regex expected lowercase characters after the uppercase char\n\n#### 0.7.39\n\nupdate dependencies\n\n#### 0.7.40\n\nupdate dependencies\n\n#### 0.7.41\n\nupdate dependencies\n\n#### 0.7.42\n\nupdate dependencies\n\n#### 0.7.43\n\n- update dependencies\n- added font v2 to allow handling of local() fonts (see https://magic.github.io/css/#styles-webfonts)\n- woff2 files are placed before woff files\n- use single quotes in output css\n- add cli\n\n#### 0.7.44\n\n- css props can be arrays to provide css overloads `{ color: ['green', 'red'] }` turns into `color: green; color: red;`\n- update dependencies\n\n#### 0.7.45\n\nupdate dependencies\n\n#### 0.7.46\n\nupdate dependencies\n\n#### 0.7.47\n\nupdate dependencies\n\n#### 0.7.48\n\nupdate dependencies\n\n#### 0.7.49\n\nupdate dependencies\n\n#### 0.7.50\n\nupdate dependencies\n\n#### 0.7.51\n\nupdate dependencies\n\n#### 0.7.52\n\nupdate dependencies\n\n#### 0.7.53\n\n- update dependencies\n- update docs to reflect usage of vars.widths.{tablet|laptop|desktop}\n- add defaults for opts.widths, to make sure we can use media queries at all times.\n\n```javascript\nopts.widths = {\n  tablet: '500px',\n  laptop: '900px',\n  desktop: '1200px',\n  agency: '1600px',\n}\n```\n\n#### 0.7.54\n\nupdate dependencies\n\n#### 0.7.55\n\nupdate dependencies\n\n#### 0.7.56\n\nupdate dependencies\n\n#### 0.7.57 - unreleased\n\n...\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmagic%2Fcss","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmagic%2Fcss","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmagic%2Fcss/lists"}