A simple and lightweight scoped CSS solution
Download the CJS, ESM, UMD versions or install via NPM:
npm install @ryanmorr/csscope
Provide a unique ID and CSS as a string and get a transformed CSS string with the unique ID inserted as an attribute selector for each CSS selector sequence. It supports media queries, including prefixing keyframe and animation names, and deep combinators (>>>
) to add styles targeting child components. For example:
import csscope from '@ryanmorr/csscope';
const css = csscope('foo', `
.foo {
animation: grow 3s linear 1s infinite running;
}
.bar + [attr=value], :empty {
background-color: red;
}
.component >>> .sub-component {
margin-bottom: 1em;
}
@media screen and (max-width: 480px) {
.foo {
color: red;
}
}
@keyframes grow {
from {
width: 0;
height: 0
}
to {
width: 100px;
height: 100px
}
}
`);
Generates the following CSS as a string:
.foo[foo] {
animation: foo-grow 3s linear 1s infinite running;
}
.bar[foo] + [foo][attr=value], [foo]:empty {
background-color: red;
}
.component[foo] .sub-component {
margin-bottom: 1em;
}
@media screen and (max-width: 480px) {
div[foo] {
color: red;
}
}
@keyframes foo-grow {
from {
width: 0;
}
to {
width: 100%;
}
}
Use the transformed CSS string to create a stylesheet client-side or server-side. To apply those styles to a DOM tree (component), add the unique ID as an attribute to every element in a DOM tree that should be influenced by the scoped styles.
Beware of descandant selectors for recursive components! For a CSS rule with the selector ".foo .bar", if the ".foo" element contains a recursive child component, than all ".bar" elements in that child component will be matched by the rule.
This project is dedicated to the public domain as described by the Unlicense.