@magic/css

@magic/css

parse/stringify/write css in js

NO dynamic css, css gets output as css file. whenever possible, use dynamic classes instead.

if there is absolute need for dynamic css, feel free to use the style property of the html tag / webcomponent you want to dynamically change, unfortunately, this library will not help you with that.

installation

npm install --save-exact @magic/css

usage:

cli:

@magic/css includes a cli script that can handle most usecases the internal javascript api allows.

to use this cli from any directory,

npm install -g @magic.css
is a useful shortcut. after the global install, you can just call `mcss` from anywhere in your terminal to see the help.

@magic/csscommands:stringify - convert css in js to cssparse     - convert css in js to an array of key value pairsfull      - get a full result object.flags:--minified - output minified css - alias: ["--m", "-m"]--help     - alias: ["-h"]--out      - directory to write output files to. omit to print to stdout - alias: ["--o", "-o"]--in       - directory with source files, needs index.js to exist - alias: ["--i", "-i"]examples:mcss parse --in ./css --out ./cssmcss stringify --in ./styles --out ./css

import

import css from '@magic/css'

api

css (full result)

import css from 'css'const style = {  body: {    color: 'green',  },  '.class': {    color: 'orange',  },  '#id': {    color: 'purple'  },}const result = await css(style)// returnsObject {  // nicely formatted css string  css: 'body {\n  color: green;\n}\n.class {\n  color: orange;\n}\n#id{\n  color: purple;\n}\n',  // minimal whitespace  minified: 'body{color:green}.class{color:orange}#id{color:purple}',  // array of used classes if any  classes: ['.class'],  // array of used ids if any  ids: ['#id'],  // array of used selectors  selectors: [],  //ast of this css object  parsed: [],}

parse

const style = {  '.className': {    '#id': {      color: 'orange',    },  },}const ast = css.parse(style)// ast[['.className #id', { color: 'orange' } ]]

stringify

const style = {  '.className': {    '#id': {      color: 'white',    },  },}await css.stringify(style)// minified string`.className #id{color:white;}`

write to filesystem

const style = {  '.className': {    '#id': {      color: opts.textColor,    },  },}// writes styles to ./out.csscss.write(style)// writes styles to ./outfile.csscss.write(style, { OUTFILE: './outfile.css' })

styles

styles are a javascript object. the keys are selectors and the values are nested objects of css rules, where the keys of the objects are assumed to be selectors unless the value associated with the key is not an object

const style = {'.className': {  color: 'green',},}await css.stringify(style)// .className { color:green; }

pseudo classes: (:hover, :active)

css pseudo classes in nested css get found if their object key starts with a &

const style = {'div': {  color: 'red',  '&:hover': {    color: 'green',  },},}await css.stringify(style)// div { color: red; }// div:hover { color: green; }

selector nesting

const style = {'div': {  'p, &:hover': {    color: 'red',  },},}await css.stringify(style)// div p, div:hover { color: red; }

prefix without space

to prefix the parent of the selector using the child selectors, add a & at the end of any selectors but the last one.

const style = {  '.class': {    'p&, :hover': {      color: 'orange',    },  },}await css.stringify(style)// p.class, .class:hover { color: orange; }

prefix all without space

if the & is at the end of a selector, the & will be applied to each of them.

const style = {  '.class': {    'div, p&': {      color: 'orange';    },  },}await css.stringify(style)// div.class, p.class { color: orange; }

prefix with space

to prefix the parent with a space, use a double && instead of a single &

const style = {  '#id': {    '.class2&&, .class3': {      color: 'orange';    },  },}await css.stringify(style)// .class2 #id, #id.class3 { color: orange; }

prefix all with space

if the && is at the end of a selector, the && will be applied to each of them.

const style = {  '.class': {    'div, p&&': {      color: 'orange';    },  },}await css.stringify(style)// div .class, p .class { color: orange; }

media queries

Mediaqueries can use the vars.widths object to determine appropriate breakpoint sizes.

Default widths:

vars.widths = {  tablet: '500px',  laptop: '900px',  desktop: '1200px',  agency: '1600px',}

Usage of the vars.widths in media queries:

const style = {  [`@media screen and(min-width: ${vars.widths?.tablet || '500px'})`]: {    '#id': {      color: opts.textColor,    },  },}await css.stringify(style)// css string`@media screen and (min-width: 500px) {  #id {    color: green;  }}`

keyframes for animations

const style = {'@keyframes anim-name': {  from: {    opacity: 0,  },  to: {    opacity: 1,  }}await css.stringify(style)// css string`@keyframes anim-name {  from {    opacity: 0;  }  to {    opacity: 1;  }}`

webfonts

Font V2

This approach allows definition of font-style, font-weight, and local font names.

Pseudocode
@font-face: {  family: 'name',  url: '/fonts/',  styles: {    (normal|italic): {      weight: ['LocalName', 'Local Name']    }  }}
const style = {    '@font-face': {      family: 'font-name',      url: '/fonts/',      styles: {        normal: {          400: ['FontName', 'Font Name'],          600: ['FontNameBold', 'Font Name Bold']        },        italic: {          400: ['FontNameItalic', 'Font Name Italic'],        },      },    },  }  const out = await css.stringify(style)  // out.css string  @font-face {    font-family: 'font-name';    font-style: normal;    font-weight: 400;    src:      local('FontName'),      local('Font Name'),      url('/fonts/font-name-400-normal.woff2') format('woff2');  }  @font-face {    font-family: 'font-name';    font-style: normal;    font-weight: 600;    src:      local('FontNameBold'),      local('Font Name Bold'),      url('/fonts/font-name-600-normal.woff2') format('woff2');  }  @font-face {    font-family: 'font-name';    font-style: italic;    font-weight: 400;    src:      local('FontNameItalic'),      local('Font Name Italic'),      url('/fonts/font-name-400-italic.woff2') format('woff2');  }

Font V1 - DEPRECATED

This approach does not allow definition of local fonts to load, and therefore is deprecated.

const style = {    '@font-face': {      family: 'font-name',      url: '/fonts/',      styles: ['normal', 'italic'],      weights: [400, 600],    },  }  const out = await css.stringify(style)  // out.css string  @font-face {    font-family: 'font-name';    font-style: normal;    font-weight: normal;    src: url('/fonts/font-name-400-normal.eot');    src: url('/fonts/font-name-400-normal.eot#iefix') format('embedded-opentype'),',    url('/fonts/font-name-400-normal.ttf') format('truetype'),',    url('/fonts/font-name-400-normal.woff') format('woff'),',    url('/fonts/font-name-400-normal.woff2') format('woff2'),',    url('/fonts/font-name-400-normal.svg#font-name') format('svg');',  }  // ... repeated for all styles and weights that were defined

css overload

Css allows overloads for props, to provide fallback values for old browsers

{  body: {    color: ['green', 'red'],  },}

turns into

body {  color: green;  color: red;}

source

the source for this page is in the example directory and gets built and published to github using @magic/core