Skip to content


Choose a tag to compare
@devongovett devongovett released this 29 Nov 17:17
· 52 commits to master since this release

This release includes support for the new nesting syntax, a new Rust visitor API to make building custom transforms easier, support for page margin at rules, and several other improvements and fixes.

New nesting syntax

The CSS nesting support has been updated to relax some of the rules around where the & selector is required, following the latest spec changes. The & selector is now automatically inserted with a descendant combinator when not already present, unless it starts with an element selector. The @nest rule is deprecated, and will print a warning.

.foo {
  color: red;

  .bar {
    color: blue;

compiles to:

.foo {
  color: red;

.foo .bar {
  color: blue;


Visitor API

The Rust API now includes a Visitor API, allowing you to much more easily traverse the style sheet and implement custom transforms. You can visit rules, properties, and many common value types such as lengths, urls, custom functions, etc.

For example, this visitor converts all pixel values to rems.

struct MyVisitor;
impl<'i> Visitor<'i> for MyVisitor {
  const TYPES: VisitTypes = visit_types!(LENGTHS);

  fn visit_length(&mut self, length: &mut LengthValue) {
    match length {
      LengthValue::Px(px) => *length = LengthValue::Rem(*px / 16.0),
      _ => {}

stylesheet.visit(&mut MyVisitor);

You must declare what types of values you want to visit with bitflags via the visit_types macro. This enables us to completely skip visiting entire branches of the AST when they don't contain any relevant values, statically, at compile time, which improves performance. For example, if you declare you only want to visit urls, we don't need to visit any properties that don't contain URLs somewhere in their type (recursively). Check out the documentation for more details.

You can also implement support for parsing custom at rules (e.g. Tailwind's @apply), by providing a custom AtRuleParser implementation. The parsed rules are stored in the stylesheet using a generic parameter. See the example for more details.

Other fixes and improvements

  • Support for margin at rules within @page80a982a
  • Simplify :is() selector when only a single simple selector is provided as an argument – b870d1f
  • Fix ARM linux GLIBC requirement – 5098cae
  • Fix parenthesization of media queries – 5a12639
  • Bump napi-rs – 9f2e369
  • Expose and add docs for selector module – e31234f