Giter VIP home page Giter VIP logo

stylis's Introduction

STYLIS

stylis

A Light–weight CSS Preprocessor.

Coverage Size Licence NPM

Installation

  • Use a Direct Download: <script src=stylis.js></script>
  • Use a CDN: <script src=unpkg.com/stylis></script>
  • Use NPM: npm install stylis --save

Features

  • nesting a { &:hover {} }
  • selector namespacing
  • vendor prefixing (flex-box, etc...)
  • minification
  • esm module compatible
  • tree-shaking-able

Abstract Syntax Structure

const declaration = {
	value: 'color:red;',
	type: 'decl',
	props: 'color',
	children: 'red',
	line: 1, column: 1
}

const comment = {
	value: '/*@noflip*/',
	type: 'comm',
	props: '/',
	children: '@noflip',
	line: 1, column: 1
}

const ruleset = {
	value: 'h1,h2',
	type: 'rule',
	props: ['h1', 'h2'],
	children: [/* ... */],
	line: 1, column: 1
}

const atruleset = {
	value: '@media (max-width:100), (min-width:100)',
	type: '@media',
	props: ['(max-width:100)', '(min-width:100)'],
	children: [/* ... */],
	line: 1, column: 1
}

Example:

import {compile, serialize, stringify} from 'stylis'

serialize(compile(`h1{all:unset}`), stringify)

Compile

compile('h1{all:unset}') === [{value: 'h1', type: 'rule', props: ['h1'], children: [/* ... */]}]
compile('--foo:unset;') === [{value: '--foo:unset;', type: 'decl', props: '--foo', children: 'unset'}]

Tokenize

tokenize('h1 h2 h3 [h4 h5] fn(args) "a b c"') === ['h1', 'h2', 'h3', '[h4 h5]', 'fn', '(args)', '"a b c"']

Serialize

serialize(compile('h1{all:unset}'), stringify)

Vendor Prefixing

import {compile, serialize, stringify, middleware, prefixer } from 'stylis';

serialize(compile('div{display:flex;}'), middleware([prefixer, stringify]))

Middleware

The middleware helper is a convenient helper utility, that for all intents and purposes you can do without if you intend to implement your own traversal logic. The stringify middleware is one such middleware that can be used in conjunction with it.

Elements passed to middlewares have a root property that is the immediate root/parent of the current element in the compiled output, so it references the parent in the already expanded CSS-like structure. Elements have also parent property that is the immediate parent of the current element from the input structure (structure representing the input string).

Traversal

serialize(compile('h1{all:unset}'), middleware([(element, index, children) => {
	assert(children === element.root.children && children[index] === element.children)
}, stringify])) === 'h1{all:unset;}'

The abstract syntax tree also includes an additional return property for more niche uses.

Prefixing

serialize(compile('h1{all:unset}'), middleware([(element, index, children, callback) => {
	if (element.type === 'decl' && element.props === 'all' && element.children === 'unset')
		element.return = 'color:red;' + element.value
}, stringify])) === 'h1{color:red;all:unset;}'
serialize(compile('h1{all:unset}'), middleware([(element, index, children, callback) => {
	if (element.type === 'rule' && element.props.indexOf('h1') > -1)
		return serialize([{...element, props: ['h2', 'h3']}], callback)
}, stringify])) === 'h2,h3{all:unset;}h1{all:unset;}'

Reading

serialize(compile('h1{all:unset}'), middleware([stringify, (element, index, children) => {
	assert(element.return === 'h1{all:unset;}')
}])) === 'h1{all:unset;color:red;}'

The middlewares in src/Middleware.js dive into tangible examples of how you might implement a middleware, alternatively you could also create your own middleware system as compile returns all the nessessary structure to fork from.

Variables

CSS variables are supported but a note should be made about the exotic use of css variables. The css spec mentions the following

The allowed syntax for custom properties is extremely permissive. The production matches any sequence of one or more tokens, so long as the sequence does not contain , , unmatched <)-token>, <]-token>, or <}-token>, or top-level tokens or tokens with a value of "!".

That is to say css variables according to the spec allows: --foo: if(x > 5) this.width = 10; and while this value is obviously useless as a variable, and would be invalid in any normal property, it still might be read and acted on by JavaScript and this is supported by Stylis, however things become slightly undefined when we start to include the { and } productions in our use of exotic css variables.

For example consider the following: --foo: {};

While this is valid CSS and supported. It is unclear what should happen when the rule collides with the implicit block termination rule that allows i.e h1{color:red}(notice the omitted semicolon) to also be a valid CSS production. This results in the following contradiction in: h1{--example: {} is it to be treated as h1{--foo:{;} or h1{--foo:{} the later of which is an unterminated block or in the following: h1{--foo:{} h1{color:red;} should it be h1 {--foo:{}h1{color:red;}; where {}h1{color:red; is part of the css variable --foo and not a new rule or should it be something else?

Nevertheless Stylis still supports the exotic forms highlighted in the spec, however you should consider it as a general rule to delimit such exotic uses of variables in strings or parentheses i.e: h1{--foo:'{'} or h1{--foo:({)}.

Benchmark

Stylis is at-least 2X faster than its predecesor.

License

Stylis is MIT licensed.

stylis's People

Contributors

thysultan avatar andarist avatar sukkaw avatar renbaoshuo avatar graphmaxer avatar emmatown avatar evenchange4 avatar simonkberg avatar cheeaun avatar felixmosh avatar quantizor avatar datadanne avatar oliverjam avatar maciej-ka avatar fatfisz avatar dnakov avatar lunaris avatar willheslam avatar ghostd avatar lucianoayres avatar kripod avatar ailrun avatar artskydj avatar jdreesen avatar isbatak avatar gbhasha avatar deadb17 avatar plxity avatar lifeiscontent avatar

Stargazers

Philip Mac avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.