Australis
What is this?
australis
is a small and simple tool to generate CSS from plain JavaScript.
No superpowers, it does only one thing, and does it well.In this simplicity spirit, the output is not even validated. But this can easily be achieved by piping its results to a tool like csslintcsslint.
Why does it exist?
Because:- Writing CSS by hand is quite tedious a task (no variables, no functions,
- Chances are that anybody working on web frontend development can get by in JavaScript.
- The current CSS generators based on JavaScript do not fit IMHO the sweet spot between
Example
This is an example of a style sheet defined inaustralis
:// Value definition
const blue = '#00F'
export default {
'.class1': {
minWidth: '40px',
zIndex: 10,
// Nested selector
'.class2': {
minHeight: '300px',
color: blue,
},
// Nested media query
'@media screen': {
paddingTop: '10px',
// Deeper nesting of media query
'@media (max-width: 1000px)': {
paddingLeft: '20px',
}
}
},
'.class3': {
backgroundColor: blue,
},
}
And the generated style sheet will look like this:
@media screen {
.class1 {
padding-top: 10px;
}
}
@media screen and (max-width: 1000px) {
.class1 {
padding-left: 20px;
}
}
.class1 {
min-width: 40px;
z-index: 10;
}
.class1 .class2 {
color: #00F;
min-height: 300px;
}
.class3 {
background-color: #00F;
}
How to get it?
This package is onnpm
so just:npm install australis --save-dev
How to use it?
As seen in the example, the style has to be defined in a plain JavaScript object, and then it has to beexport default
'ed (or exports.default = ...
if using CommonJS)These are the rules to be learnt:
- If an object is defined within an object, it is understood as nesting and results in
@media
, @document
or @supports
are
merged). The merging always has an "and" meaning. Therefore if .class2
is nested within .class1
, the
selector for the declaration block defined within .class2
will be .class1 .class2
. Same goes for at-rules
although these will be bubbled up and show up before the normal selectors.- Properties containing a dash can be defined in camelCase and they will be automatically
minWidth
will result in min-width
- If a property contains a comment in the form
/* comment */
, the comment itself will be not be in the
Then, to generate the style sheet, just call
australis path/to/style.css.js
, optionally
passing an output path as well.While the previously explained is the core of
australis
and it is enough to get the ball rolling,
there are a few tools defined in the tools
module that will help you with typical CSS tasks. Those
are described in the API sectionFor any problem or suggestions, please do not hesitate to open an issue on github.
API
australis.generateCSS(style)
This function is the core of the package. It receives aaustralis
style object and returns the generated
CSS string. The CLI API is just a wrapper around this.The result will be sorted in the following order:
@charset
at-rules@include
at-rules- Rest of at-rules sorted alphabetically
- Rest sorted alphabetically
If this package is to be used on the browser, this method must be called and its return value appended to a style tag (a bundling engine like
browserify
or webpack
is needed to bring this
to the browser)tools.mix(...objects)
Function to perform mixins. Receives any number of objects, and returns a shallow merge of all of them. If falsy values are passed, they will be ignored, so that it is easy to conditionally include mixins.Usage example:
import { mix } from 'australis/tools'
// This is the mixin
const square = {
width: '50px',
height: '50px',
}
const condition = false
export default {
'.class1': mix(
square,
{
backgroundColor: 'red',
}
),
'.class2': mix(
square & condition,
{
position: 'float',
padding: '1px 1px 3px 10px',
}
)
}
Output:
.class1 {
background-color: red;
height: 50px;
width: 50px;
}
.class2 {
padding: 1px 1px 3px 10px;
position: float;
}
tools.changeLight(col, factor)
Givencol
as a hex string (e.g. #aabbcc
or #abc
), and factor
as number, each channel
of the color is multiplied by the factor, and the result is returned as a hex string.If any channel goes out of the
0-ff
range, it will be capped to 0
or ff
.Example:
import { changeLight } from '../tools'
const color = '#aabbcc'
export default {
'.bright': {
backgroundColor: changeLight(color, 1.5)
},
'.dark': {
backgroundColor: changeLight(color, 0.5)
},
}
Result:
.bright {
background-color: #ffffff;
}
.dark {
background-color: #555e66;
}
tools.prefix(prop, value, prefixes = 'webkit', 'moz', 'ms', 'o')
Given a propertyprop
, a value value
and optionally an array of prefixes,
a new object will be returned, having the original property and all its prefixed variants as keys,
and value
for each value (it can be used with at-rules as well, like key-frames
)Example:
import { prefix } from 'australis/tools'
export default {
'.animated': prefix('animation', 'slide')
}
Result:
.animated {
-moz-animation: slide;
-ms-animation: slide;
-o-animation: slide;
-webkit-animation: slide;
animation: slide;
}
tools.multivalue(prop, values)
Given a property and an array of values, it returns an object that will be rendered as if the property was defined for each value.Example:
import { multivalue } from 'australis/tools'
export default {
'.my-flex-box': multivalue('display', ['-ms-flexbox', '-webkit-flex', 'flex']),
}
Result:
.my-flex-box {
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
}
Note: this takes profit of the
/* comment */
stripping.