Research
Security News
Malicious npm Package Targets Solana Developers and Hijacks Funds
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
The stylis npm package is a lightweight CSS preprocessor that allows developers to write nested CSS, use mixins, and perform other transformations before the CSS is compiled. It is particularly designed to be used with CSS-in-JS libraries and offers a middleware architecture to extend its capabilities.
CSS Preprocessing
Stylis allows you to write nested CSS rules, which it will then flatten into valid CSS. The code sample demonstrates how to preprocess a nested CSS string.
const stylis = require('stylis');
const css = `
.parent {
color: red;
.child {
color: blue;
}
}
`;
const output = stylis('.parent', css);
console.log(output);
Prefixing
Stylis automatically adds vendor prefixes to CSS rules when necessary. The code sample shows how to automatically prefix the 'display: flex;' rule.
const stylis = require('stylis');
const css = `display: flex;`;
const output = stylis('', css);
console.log(output);
Middleware
Stylis supports middleware, allowing you to intercept and transform CSS at various stages of processing. The code sample demonstrates a middleware that changes the color property for elements with the class '.button'.
const stylis = require('stylis');
stylis.use((context, content, selectors, parents, line, column, length) => {
if (context === 2 && selectors[0] === '.button') {
return content.replace('color: red', 'color: blue');
}
});
const css = `.button { color: red; }`;
const output = stylis('', css);
console.log(output);
PostCSS is a tool for transforming CSS with JavaScript plugins. It is more established and has a larger ecosystem of plugins compared to stylis. PostCSS can be used for a wide range of tasks including linting, optimization, and applying polyfills.
Sass is a mature and feature-rich CSS extension language that allows for variables, nesting, mixins, and more. Unlike stylis, Sass has its own syntax and requires compilation to CSS, but it offers a more comprehensive set of features for styling.
Less is another CSS pre-processor that extends the capabilities of CSS with variables, mixins, functions, and more. It is similar to Sass and offers a different syntax and feature set compared to stylis.
light – weight css preprocessor
<script src=stylis.min.js></script>
<script src=https://unpkg.com/stylis@latest/stylis.min.js></script>
npm install stylis --save
:global(selector)
a { &:hover {} }
color: red; h1 { color: red; }
stylis('#id', `
font-size: 2em;
// line comments
/* block comments */
:global(body) {background:red}
h1 {
h2 {
h3 {
content:'nesting'
}
}
}
@media (max-width: 600px) {
& {display:none}
}
&:before {
animation: slide 3s ease infinite
}
@keyframes slide {
from { opacity: 0}
to { opacity: 1}
}
& {
display: flex
}
&::placeholder {
color:red
}
`);
#id {font-size: 2em;}
body {background:red}
h1 h2 h3 {content: 'nesting'}
@media (max-width: 600px) {
#id {display:none}
}
#id:before {
-webkit-animation: slide-id 3s ease infinite;
animation: slide-id 3s ease infinite;
}
@-webkit-keyframes slide-id {
from { opacity: 0}
to { opacity: 1}
}
@keyframes slide-id {
from { opacity: 0}
to { opacity: 1}
}
#id {
display:-webkit-box;
display:-webkit-flex;
display:-ms-flexbox;
display:flex;
}
#id::-webkit-input-placeholder {color:red;}
#id::-moz-placeholder {color:red;}
#id:-ms-input-placeholder {color:red;}
#id::placeholder {color:red;}
stylis(selector: {String}, css: {String})
// factory pattern
var stylis = new stylis(options)
// singleton pattern
var stylis = stylis
When using the factory pattern the if an object is passed as optional options
argument, this will be passed to stylis.set(options)
// all options except compress and cascade are enabled by default
stylis.set({
// (dis/en)able :global selectors
global: {Boolean}
// (dis/en)able aggressive cascade isolation
// true for normal cascade(default) false for no cascading
cascade: {Boolean}
// (dis/en)able namespace keyframes + animations
keyframe: {Boolean}
// (dis/en)able vendor prefixing
prefix: {Boolean|Function(key: string, value: string, context: number)}
// (dis/en)able aggressive minification
compress: {Boolean}
// (dis/en)able (no)semicolon support
// false to enable no-semicolons (default)
semicolon: {Boolean},
// tell stylis to make an effort to preserve empty rules,
// i.e `.selector{ }`
preserve: {Boolean}
})
By default vendor is enabled, however there is an option to disable vendor prefixing, either completely or dynamically.
The following would disable prefixing.
stylis.set({prefix: false})
Alternatively you can disable prefixing on a case by case basis by providing a function that returns a boolean
indiciating whether to prefixing that particular rule.
stylis.set({
prefix: (key, value, context) => {
return false
}
})
The arguments correspond to the rule that is about to be vendor prefixed. For example:
// transform: none;
key = 'transform'
value = 'none'
context = 1
// :read-only {...}
key = ':read-only'
value = '...'
context = 2
// @keyframes {...}
key = '@keyframes'
value = '...'
context = 3
stylis.use(plugin: {Function|Array<Function>|null})
The use function is chainable ex. stylis.use()()()
The optional middleware function accepts four arguments with this
pointing to a reference of the current stylis instance.
(context, content, selectors, parent, line, column, length)
Plugins are executed in stages identified by an context
interger value.
-2 /* post-process context */
-1 /* preparation context */
0 /* newline context */
1 /* property context */
2 /* selector block context */
3 /* @at-rule block context */
Note: Since the newline context is intended for source-map plugins by default stylis will not execute plugins in this context unless enabled, this can be done through
stylis.use(true)
or disabled after that throughstylis.use(false)
.
-2
post processed context, before the compiled css output is returned-1
preparation context, before the compiler starts0
after every newline1
on a property declaration ex. color: red;
2
after a selector block of css has been processed ex. .foo {color:red;}
3
after a @at-rule
block of css has been processed ex. @media {h1{color:red;}}
If at any context(except 0) that the middleware returns a different string the content of css will be replaced with the return value.
To remove all plugins just call .use
with null/no arguments.
// removes all previously added plugins, then adds one
stylis.use(null)(ctx => {})
For example we can add a feature random()
to our css that when used prints a random number.
/**
* plugin
*
* @param {number} context
* @param {Array<string>} selector
* @param {Array<string>} parent
* @param {string} content
* @param {number} line
* @param {number} column
* @param {number} length
* @return {(string|void)?}
*/
const plugin = (context, content, selectors, parent, line, column, length) => {
switch (context) {
case 1: return content.replace(/random\(\)/g, Math.random())
}
}
/**
* use
*
* @param {(Array<function>|function|null|boolean)} plugin
* @return {Function} use
*/
stylis.use(plugin)
stylis(``, `h1 { width: calc(random()*10); }`)
This will replace all instances of random()
with a random number.
Internally Before stylis processes calc(random()*10);
it passes it to the plugin if a plugin exists; If in turn the plugin returns something different from what it received stylis will replace the content of the property with the return value and continue processing that.
The same can be said for a selector block, in both contexts an argument selector
is passed that contains the current array of selectors that the block of css/property stylis is working on.
This array of selectors is mutable and will reflect the output of selectors if changed.
Stylis is fast, and though it does not generate an AST you can with a plugin create an AST out of the resulting input, this and other aspects allow it to be very small(3KB).
The benchmark results are using https://github.com/postcss/benchmark
Note that the benchmark is not a one-2-one comparison because each library was developed for different goals and different set of features.
Stylis appears in all the benchmarks because by default stylis both parsers, processes and auto prefixes in one pass.
Stylis x 54.28 ops/sec ±4.45% (58 runs sampled)
CSSTree x 39.73 ops/sec ±9.18% (56 runs sampled)
PostCSS x 21.11 ops/sec ±8.46% (57 runs sampled)
CSSOM x 19.20 ops/sec ±6.53% (36 runs sampled)
Mensch x 17.85 ops/sec ±13.39% (37 runs sampled)
Rework x 12.80 ops/sec ±4.42% (36 runs sampled)
PostCSS Full x 8.15 ops/sec ±7.79% (45 runs sampled)
Gonzales x 5.21 ops/sec ±7.75% (18 runs sampled)
Gonzales PE x 3.99 ops/sec ±10.37% (15 runs sampled)
Stylecow x 3.97 ops/sec ±9.48% (15 runs sampled)
ParserLib x 1.79 ops/sec ±8.58% (9 runs sampled)
Fastest test is Stylis at 1.37x faster than CSSTree
Stylis x 26.26 ops/sec ±5.95% (49 runs sampled)
PostCSS x 16.23 ops/sec ±11.21% (47 runs sampled)
Rework x 10.65 ops/sec ±3.86% (55 runs sampled)
libsass x 6.83 ops/sec ±2.29% (22 runs sampled)
Less x 4.75 ops/sec ±9.14% (29 runs sampled)
Stylus x 3.67 ops/sec ±28.12% (25 runs sampled)
Stylecow x 2.15 ops/sec ±6.36% (15 runs sampled)
Ruby Sass x 0.31 ops/sec ±8.12% (6 runs sampled)
Fastest test is Stylis at 1.62x faster than PostCSS
Stylis x 45.52 ops/sec ±14.61% (77 runs sampled)
Autoprefixer x 13.32 ops/sec ±6.51% (67 runs sampled)
Stylecow x 2.28 ops/sec ±5.97% (16 runs sampled)
nib x 1.79 ops/sec ±25.32% (15 runs sampled)
Compass x 0.15 ops/sec ±9.34% (5 runs sampled)
Fastest test is Stylis at 3.4x faster than Autoprefixer
FAQs
A Light–weight CSS Preprocessor
The npm package stylis receives a total of 10,691,662 weekly downloads. As such, stylis popularity was classified as popular.
We found that stylis demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
Security News
Research
Socket researchers have discovered malicious npm packages targeting crypto developers, stealing credentials and wallet data using spyware delivered through typosquats of popular cryptographic libraries.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.