Unistyle
Write modular and scalable CSS using the next version of ECMAScript
Install / Use
/learn @joakimbeng/UnistyleREADME
unistyle
[![Build status][travis-image]][travis-url] [![NPM version][npm-image]][npm-url] [![XO code style][codestyle-image]][codestyle-url]
Write modular and scalable CSS using the next version of ECMAScript.
Why?
Using ES2015 (and some ES2016) features to write CSS in JavaScript makes it really modular, scalable and gives you in practice all the features of a good CSS pre- or postprocessor, without resorting to a new language. See the example section for use together with React for how to avoid the annoying cascading feature of CSS, which is troublesome in large scale CSS.
Unistyle?
The name is an abbreviation of Uniform Stylesheets. It is also somewhat related to Universal JavaScript or what you want to call it, because of the ability to share the same CSS code written in JavaScript between your frontend component's inline styles and the application's complete CSS.
Installation
Install unistyle using npm:
npm install --save unistyle
CLI Usage
$> unistyle --help
Write modular and scalable CSS using the next version of ECMAScript.
Usage:
unistyle [options] <path to module>
Options:
-o, --output Output compiled CSS to specified file instead of to stdout [string]
-h, --help Show help [boolean]
-v, --version Show version number [boolean]
Examples:
unistyle -o app.css src/styles.js Compile src/styles.js to app.css
Examples
Note: All examples below assumes you're already using Babel in your project. Or perhaps unistyle-loader together with a Babel loader and Webpack.
The examples source code can be found in ./examples and their compiled counterparts in ./examples-es5.
Using modules and variables
You can use either CommonJS modules or the new ES2015 modules syntax.
In examples/vars/vars.js:
export const padding = '15px';
export const dark = '#333';
In examples/vars/button.js:
import {padding, dark} from './vars';
export default {
'.btn': {
padding,
border: `1px solid ${dark}`
}
};
In examples/vars/index.js:
import {padding} from './vars';
import button from './button';
export default {
body: {
padding
},
...button
};
Compiling to CSS with unistyle examples-es5/vars will give the following result:
body, .btn {
padding: 15px;
}
.btn {
border: 1px solid #333;
}
Extending declarations
Every preprocessor I can think of (e.g. LESS, Sass and Stylus) have the ability to extend one CSS declaration with another, for reusability. They all have their own syntax, however with Unistyle you can use the object rest spread syntax (which you should already be using if Babel is your thing):
In examples/extend/common.js:
export const bigAndPadded = {
fontSize: 100,
padding: 50
};
In examples/extend/button.js:
import {bigAndPadded} from './common';
export default {
button: {
...bigAndPadded,
border: '5px solid black'
}
};
Compiling to CSS with unistyle examples-es5/extend/button will give the following:
button {
font-size: 100px;
padding: 50px;
border: 5px solid black;
}
Media queries
Using media queries (which bubbles up to the root) is easier then ever using the computed property names syntax:
In examples/mediaqueries/breakpoints.js:
export const palm = '@media only screen and (max-width: 700px)';
export const small = '@media only screen and (max-width: 1000px)';
In examples/mediaqueries/index.js:
import {palm} from './breakpoints';
export default {
body: {
fontSize: 20,
[palm]: {
fontSize: 16
}
}
};
Compiling with unistyle examples-es5/mediaqueries will give:
body {
font-size: 20px;
}
@media only screen and (max-width: 700px) {
body {
font-size: 16px;
}
}
Multiple @font-face declarations
You can specify multiple @font-face declarations using arrays.
In examples/font-faces/index.js:
export default {
'@font-face': [
font('my-web-font', 'webfont'),
font('my-other-font', 'otherfont')
]
};
function font(family, filename) {
return {
fontFamily: `"${family}"`,
src: [
`url("${filename}.eot")`,
[
`url("${filename}.eot?#iefix") format("embedded-opentype")`,
`url("${filename}.woff2") format("woff2")`,
`url("${filename}.woff") format("woff")`,
`url("${filename}.ttf") format("truetype")`,
`url("${filename}.svg?#svgFontName") format("svg")`
].join(', ')
]
};
}
Compiling with unistyle examples-es5/font-faces will give:
@font-face {
font-family: "my-web-font";
src: url("webfont.eot");
src: url("webfont.eot?#iefix") format("embedded-opentype"), url("webfont.woff2") format("woff2"), url("webfont.woff") format("woff"), url("webfont.ttf") format("truetype"), url("webfont.svg?#svgFontName") format("svg");
}
@font-face {
font-family: "my-other-font";
src: url("otherfont.eot");
src: url("otherfont.eot?#iefix") format("embedded-opentype"), url("otherfont.woff2") format("woff2"), url("otherfont.woff") format("woff"), url("otherfont.ttf") format("truetype"), url("otherfont.svg?#svgFontName") format("svg");
}
Using Unistyle with React
As inline style
A CSS module written for Unistyle is already compatible with React inline styles, so you could just import/require it like so:
In examples/react/inline/button-style.js:
export default {
padding: 15,
border: '2px solid black'
};
In examples/react/inline/button.js:
import React from 'react';
import buttonStyle from './button-style';
export default class Button extends React.Component {
render() {
return <button style={buttonStyle}>My button</button>;
}
}
No compilation step is needed here...
Keeping the CSS in a separate file
Note: this is not limited to React but works with almost any frontend framework/library, if you're using Browserify, Webpack or similar.
Using the modules cngen and classnameify respectively makes it possible to keep all CSS for your React components in its own file. As a bonus you get round the biggest problem with large scale CSS, i.e. the fact that it cascades.
In examples/react/separate/button-style.js:
export default {
'padding': 15,
'border': '2px solid black',
':hover': {
borderColor: 'green'
}
};
In examples/react/separate/button.js:
import React from 'react';
import cngen from 'cngen';
import buttonStyle from './button-style';
export default class Button extends React.Component {
render() {
const buttonClass = cngen(buttonStyle);
return <button className={buttonClass}>My button</button>;
}
}
In examples/react/separate/styles.js:
import classnameify from 'classnameify';
import buttonStyle from './button-style';
export default classnameify({
buttonStyle
});
Compiling to CSS with unistyle examples-es5/react/separate/styles.js, gives the following CSS:
._cf2b82a {
padding: 15px;
border: 2px solid black;
}
._cf2b82a:hover {
border-color: green;
}
Publishing Unistyle modules to npm
Because Unistyle CSS modules are JavaScript only, they are easily reused if you publish them to npm after which they can be installed and imported/required. Babel module best practices still applies though, i.e. you should transpile your code before publishing.
When publishing a Unistyle CSS module to npm I recommend adding "unistyle" as a keyword in your package.json for easier discoverability.
Using third party modules
When adding third party modules to your app's Unistyle CSS you should export an array instead of an object, for instance with normalize-unistyle:
import normalize from 'normalize-unistyle';
import myStyles from './my-styles';
export default [
normalize,
myStyles
];
This is to have colliding selectors in normalize-unistyle and myStyles merged instead of overwritten.
E.g. compiling this (examples/third-party/object.js):
const thirdParty = {
body: {
color: 'black'
}
};
const myStyles = {
body: {
backgroundColor: 'white'
}
};
export default {
...thirdParty,
...myStyles
};
Will yield the unexpected result:
body {
background-color: white;
}
And instead compiling this (examples/third-party/array.js):
const thirdParty = {
body: {
color: 'black'
}
};
const myStyles = {
body: {
backgroundColor: 'white'
}
};
export default [
thirdParty,
myStyles
];
Will yield the expected result:
body {
color: black;
background-color: white;
}
What about minification or autoprefixing?
Use existing modules for this.
Using cssmin for minification
npm
Related Skills
node-connect
352.5kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
111.3kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
352.5kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
352.5kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
