Security News
Node.js EOL Versions CVE Dubbed the "Worst CVE of the Year" by Security Experts
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
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.
Stylis is a small css compiler that turns this
stylis('#user', styles);
Where styles
is the following css
// variables
~~foo: 20px;
// flat css
font-size: 2em;
font-family: sans-serif;
width: var(~~foo);
// emulation for shadow dom selectors
:host {
color: red;
}
:host(.fancy) {
color: red;
}
:host-context(body) {
color: red;
}
// removes line comment
.name {
transform: rotate(30deg);
}
// inject to global scope block
@global {
body {
background: yellow;
}
}
// inject to global scope inline
span, h1, :global(h2) {
color:red;
/**
* removes block comments
*/
}
// prefixing
& {
animation: slidein 3s ease infinite;
display: flex;
flex: 1;
user-select: none;
}
// namespaced animations
&:before {
animation: slidein 3s ease infinite;
}
// namespaced keyframes
@keyframes slidein {
from { transform: translate(10px); }
to { transform: translate(200px); }
}
// flat namespaced css in @media
@media (max-width: 600px) {
display: block;
&, h1 {
appearance: none;
}
}
// nesting
h1 {
color: red;
h2 {
display: block;
h3, &:hover {
color: blue;
}
}
font-size: 12px;
}
// static mixins
@mixin large-text {
font-size: 20px;
}
// function mixins
@mixin linx (link, visit, hover, active) {
a {
color: var(~~link);
&:hover {
color: var(~~hover);
}
}
}
// use static mixins
& {
@include large-text;
}
// use function mixins
@include linx(white, blue, green, red);
into this (minus the whitespace)
#user {
font-size: 2em;
font-family: sans-serif;
width: 20px;
}
#user {
color: red;
}
#user.fancy {
color: red;
}
body #user {
color: red;
}
#user .name {
-webkit-transform: rotate(30deg);
-ms-transform: rotate(30deg);
transform: rotate(30deg);
}
body {
background: yellow;
}
#user span,
#user h1,
h2 {
color: red;
}
#user {
display: -webkit-flex;
display: flex;
-webkit-flex: 1;
-moz-flex: 1;
flex: 1;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-animation: userslidein 3s ease infinite;
animation: userslidein 3s ease infinite;
}
#user:before {
-webkit-animation: userslidein 3s ease infinite;
animation: userslidein 3s ease infinite;
}
@-webkit-keyframes userslidein {
from {
-webkit-transform: translate(10px);
-ms-transform: translate(10px);
transform: translate(10px);
}
to {
-webkit-transform: translate(200px);
-ms-transform: translate(200px);
transform: translate(200px);
}
}
@keyframes userslidein {
from {
-webkit-transform: translate(10px);
-ms-transform: translate(10px);
transform: translate(10px);
}
to {
-webkit-transform: translate(200px);
-ms-transform: translate(200px);
transform: translate(200px);
}
}
@media (max-width: 600px) {
#user, #user h1 {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
#user {
display: block;
}
}
#user h1 {
color: red;
font-size: 12px;
}
#user h1 h2 {
display: block;
}
#user h1 h2 h3,
#user h1 h2 h2:hover {
color: blue;
}
#user {
font-size: 20px;
}
#user a {
color: white;
&:hover {
color: green;
}
}
<script src=stylis.min.js></script>
<script src=https://unpkg.com/stylis@0.9.2/stylis.min.js></script>
npm install stylis --save
~~foo
and var(~~foo)
;:host
, :host()
and :host-context()
:global(selector)
@global {}
a { &:hover {} }
@mixin ...
and @include
color: red; h1 { color: red; }
stylis(
selector: {string}, // selector - i.e `.class` or `#id` or `[attr=id]`
styles: {string}, // css string
animations: {boolean=} // false to prevent prefixing animations, true by default
middleware: {function=}
);
The optional middleware function accepts four arguments ctx, str, line, column
, the middleware is executed 1. at every token ctx = 0
and 2. before a block of compiled css is added to the output string ctx = 1
, 3. when flat css is appened to the output bundle ctx = 2
and 4. When an import
statement is found ctx = 3
.
If you wanted to you could parse import statements in the middleware and return the imported file, stylis will then insert the content of it into the css that it will parse/compile. The str value on import context is the file i.e foo
or foo.scss
or multiple files foo, bar
.
If the middleware returns a non-falsey value the token or block of css will be replaced with the return value. For example we can add a feature random()
that when used prints a random number.
stylis(``, `width: calc(random()*10)`, false, function (ctx, str, line, column) {
switch (ctx) {
case 0: return str.replace(/random\(\)/g, Math.random());
}
});
Will replace all instances of random()
with a random number
You can use stylis to build an abstraction ontop of, for example imagine we want to build an abstract that makes the following React Component possible
class Heading extends React.Component {
stylesheet(){
return `
&{
color: blue
}
`;
}
render() {
return (
React.createElement('h1', 'Hello World')
);
}
}
We could simply extend the Component class as follows
React.Component.prototype.stylis = function (self) {
var namespace = this.displayName;
return function () {
stylis(namespace, self.stylesheet(), document.head);
mounted = true;
this.setAttribute(namespace);
}
}
Then use it in the following way
class Heading extends React.Component {
stylesheet(){
return `
&{
color: blue
}
`;
}
render() {
return (
React.createElement('h1', {ref: this.stylis(self)}, 'Hello World')
);
}
}
When the first instance of the component is mounted the function assigned to the ref will get executed adding a style element with the compiled output of stylesheet()
where as only the namespace attribute is added to any subsequent instances.
You can of course do this another way
class Heading extends React.Component {
constructor (props) {
super(props);
// or you can even inline this
this.style = React.createElement('style', {id: this.displayName}, this.stylesheet());
}
stylesheet(){
return `
&{
color: blue
}
`;
}
render() {
return (
React.createElement('h1', null, 'Hello World', this.style)
);
}
}
One will add it to the head another will render it in place with the component.
If you want a better picture into what can be done, there is an abstraction i created for dio.js that does away with the above boilerplate entirely http://jsbin.com/mozefe/1/edit?js,output
FAQs
A Light–weight CSS Preprocessor
The npm package stylis receives a total of 12,851,890 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.
Security News
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
Security News
cURL and Go security teams are publicly rejecting CVSS as flawed for assessing vulnerabilities and are calling for more accurate, context-aware approaches.
Security News
Bun 1.2 enhances its JavaScript runtime with 90% Node.js compatibility, built-in S3 and Postgres support, HTML Imports, and faster, cloud-first performance.