• Stars
    star
    312
  • Rank 134,133 (Top 3 %)
  • Language
    JavaScript
  • Created about 9 years ago
  • Updated almost 9 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Write modular and scalable CSS using the next version of ECMAScript

unistyle

unistyle logo

Build status NPM version XO code style

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 install --save unistyle cssmin

Then you can add a build script to package.json like so:

{
  "scripts": {
    "build": "unistyle styles/ | cssmin > styles.min.css"
  }
}

And then run: npm run build to create styles.min.css.

Using autoprefixer for prefixing

npm install --save unistyle postcss-cli autoprefixer

Then you can add a build script to package.json like so:

{
  "scripts": {
    "build": "unistyle styles/ | postcss --use autoprefixer -o styles.css"
  }
}

And then run: npm run build to create styles.css.

How does it work?

Unistyle uses Babel and AbsurdJS under the hood. Unistyle does not use Babel or AbsurdJS anymore. It's up to you to use Babel if you want to, or stick with the ES2015 features currently in Node v4 or v5. Instead of AbsurdJS Unistyle uses unistyle-flat to allow nesting of styles and to-css to compile to CSS. This is because AbsurdJS had so many more features than are actually needed which makes Unistyle less magical now.

Unistyle also uses kebab-case and pixelify to be able to write CSS properties in camelCase (to lessen the need for quotes) and to append values with 'px' when appropriate, i.e. {fontSize: 10} => font-size: 10px;. This makes your Unistyle modules compatible with React inline styles.

Note: to-css's feature to set a property multiple times should not be used in your inline styles and only in your compiled stylesheet.

API

compile(obj)

Name Type Description
obj `Object Array`

Returns: Promise, which resolves to the compiled CSS string.

License

MIT @ Joakim Carlstein

More Repositories

1

react-swiper

Detects and triggers touch events for swiping such as onSwipeLeft, onSwipeDown, etc. with ReactJS
JavaScript
140
star
2

middl

A generic middleware library, inspired by Express and suitable for anything
JavaScript
97
star
3

relae

A Relay inspired library for React and RESTful backends
JavaScript
55
star
4

micro-compress

Compression for HTTP microservices built with Micro
JavaScript
43
star
5

to-css

Generate CSS from a JavaScript Object
JavaScript
25
star
6

kebab-case

Convert a string to kebab-case, i.e. its dash separated form
JavaScript
23
star
7

short-hash

Get a short hash from a string. Uses Bernstein's popular 'times 33' hash algorithm but returns a hex string instead of a number
JavaScript
13
star
8

npm-root

Get the node modules directory, a.k.a. npm root. Global or local.
JavaScript
8
star
9

pj2md

Generate a README in markdown from a package.json file
JavaScript
6
star
10

promise-fn

Wrap a function to be able to call it with promises as arguments, i.e. use promises as if they where non-promise values
JavaScript
6
star
11

promise-all

A Promise.all but for Objects as well as Arrays
JavaScript
5
star
12

create-file

Write to a file only if it does not exist
JavaScript
4
star
13

readability-from-string

Run mozilla/readability on an HTML string
JavaScript
4
star
14

spindel

A web crawler/spider
JavaScript
4
star
15

readdir-absolute

As fs.readdir but it returns absolute paths
JavaScript
4
star
16

systemet

Get data from Systembolaget
JavaScript
4
star
17

split-css-selector

Split a comma separated CSS selector list into an array of selectors
JavaScript
4
star
18

get-hrefs

Get all href urls from an HTML string
JavaScript
3
star
19

rulla

An opinionated preconfigured Rollup for easy bundling
JavaScript
3
star
20

hyperscript-string

Create HTML strings with JavaScript
JavaScript
3
star
21

iso-date

Get a ISO date string, i.e. 'YYYY-MM-DD', from a Date
JavaScript
3
star
22

promise-fncall

A Function.call that can deal with promise arguments
JavaScript
2
star
23

promise-get

Get a property from the object a promise resolves to, using a dot path
JavaScript
2
star
24

hyperscript-normalize-args

A hyperscript helper to normalize component arguments, for easier creation of reusable components
JavaScript
2
star
25

classnameify

Generate classname selectors for CSS components, works splendid together with e.g. React
JavaScript
2
star
26

function-params

Get parameter names for a given function (with ES6 arrow syntax support)
JavaScript
2
star
27

handle-path

A simple route handling tool. Mapping a URL to a handler
JavaScript
2
star
28

node-red-contrib-rethinkdb

WIP: A Node-RED RethinkDB node
HTML
2
star
29

get-api

Get API information from a module
JavaScript
2
star
30

get-feeds

Get RSS/Atom/ActivityStream feeds from an HTML string
JavaScript
2
star
31

kudo

A simple Kudo Card generator
HTML
2
star
32

frrb

Fat Responsive Radiobutton
JavaScript
2
star
33

cngen

Generate CSS classnames from declarations, works splendid together with e.g. React
JavaScript
2
star
34

unistyle-flat

Unnest/flatten a Unistyle Object to a structure which resembles real CSS
JavaScript
2
star
35

promise-or

The OR (||) operator for promises
JavaScript
1
star
36

promise-not

The NOT (!) operator for promises
JavaScript
1
star
37

promise-if

The if statement (or unary operator) for promises
JavaScript
1
star
38

docker-java-node

A Dockerfile for a Java+Node image
1
star
39

docker-php

A Docker image with Apache+PHP+Composer and some more tools
1
star
40

frcb

Fat Responsive Checkbox
JavaScript
1
star
41

docker-gcloud-node

A gcloud docker image with kubectl, docker and nodejs
1
star
42

docker-node-git

mhart/alpine-node with git installed
1
star
43

the-argv

The part of argv you want
JavaScript
1
star
44

docker-node-python

A Docker image with NodeJS and Python
1
star
45

promise-and

The AND (&&) operator for promises
JavaScript
1
star
46

is-existing-folder

Check if a certain path exists and is a folder (i.e. not a file)
JavaScript
1
star
47

docker-code-server

Dockerfile
1
star
48

hash-props

Get a hash of an object calculated from certain properties
JavaScript
1
star
49

katalog

A service catalog and discovery application for use with Docker containers
JavaScript
1
star
50

docker-node-zeromq

A Dockerfile for a Node+ZeroMQ image
1
star
51

docker-docker-node-yarn

A Docker image with Docker, NodeJS and Yarn preinstalled
Dockerfile
1
star
52

is-existing-file

Check if a certain path exists and is a file (i.e. not a folder)
JavaScript
1
star
53

slush-n

A Slush generator for creating Node modules
JavaScript
1
star
54

to-predictable-string

Stringify anything in a predictable manner, i.e. two objects with equal keys in different order gets the same result
JavaScript
1
star
55

compose-funcs

Compose functions (i.e. f(g(x)) -> (f ∘ g)(x)). Returns a function with correct length and a descriptive name
JavaScript
1
star
56

gh-repo-to-user

Get GitHub username from a repo, accepting repos like package.json's repository field
JavaScript
1
star
57

docker-gcloud

A gcloud docker image with kubectl and docker
1
star
58

hyperscript-string-async

An async/promisified version of hyperscript-string
JavaScript
1
star
59

module-finder

Finds and filters locally and/or globally installed modules using MongoDB like queries.
JavaScript
1
star
60

joakimbeng.github.io

My landing page
CSS
1
star
61

klient

A client for Katalog, the simple Docker service catalog and discovery application
JavaScript
1
star
62

merge-all

Merge all Objects in an Array
JavaScript
1
star
63

nginx-site-watcher

An nginx Docker container which automatically reloads nginx when sites-enabled configs change
Nginx
1
star
64

pixelify

Convert numbers in a JavaScript CSS declaration to pixel values, where it's appropriate
JavaScript
1
star
65

readdirs-absolute

As readdir-absolute but for an array of directories
JavaScript
1
star
66

assign-all

Object.assign for all objects in an array
JavaScript
1
star