A CSS parser, transformer, and minifier written in Rust.



A CSS parser, transformer, and minifier written in Rust.


  • Extremely fast – Parsing and minifying large files is completed in milliseconds, often with significantly smaller output than other tools. See benchmarks below.
  • Typed property values – many other CSS parsers treat property values as an untyped series of tokens. This means that each transformer that wants to do something with these values must interpret them itself, leading to duplicate work and inconsistencies. @parcel/css parses all values using the grammar from the CSS specification, and exposes a specific value type for each property.
  • Browser-grade parser@parcel/css is built on the cssparser and selectors crates created by Mozilla and used by Firefox and Servo. These provide a solid general purpose CSS-parsing foundation on top of which @parcel/css implements support for all specific CSS rules and properties.
  • Minification – One of the main purposes of @parcel/css is to minify CSS to make it smaller. This includes many optimizations including:
    • Combining longhand properties into shorthands where possible.
    • Merging adjacent rules with the same selectors or declarations when it is safe to do so.
    • Combining CSS transforms into a single matrix or vice versa when smaller.
    • Removing vendor prefixes that are not needed, based on the provided browser targets.
    • Reducing calc() expressions where possible.
    • Converting colors to shorter hex notation where possible.
    • Minifying gradients.
    • Minifying CSS grid templates.
    • Normalizing property value order.
    • Removing default property sub-values which will be inferred by browsers.
    • Many micro-optimizations, e.g. converting to shorter units, removing unnecessary quotation marks, etc.
  • Vendor prefixing@parcel/css accepts a list of browser targets, and automatically adds (and removes) vendor prefixes.
  • Syntax lowering@parcel/css parses modern CSS syntax, and generates more compatible output where needed, based on browser targets.
    • CSS Nesting (draft spec)
    • Custom media queries (draft spec)
    • Logical properties
    • CSS Level 4 Color syntax
      • Space separated components in rgb and hsl functions
      • Hex with alpha syntax
      • hwb() color syntax
      • Percent syntax for opacity
    • Double position gradient stops (e.g. red 40% 80%)
    • clamp() function
    • Alignment shorthands (e.g. place-items)
    • Two-value overflow shorthand
    • Media query range syntax (e.g. @media (width <= 100px) or @media (100px < width < 500px))
    • Multi-value display property (e.g. inline flex)
  • CSS modules@parcel/css supports compiling a subset of CSS modules features.
    • Locally scoped class and id selectors
    • Locally scoped custom identifiers, e.g. @keyframes names, grid lines/areas, @counter-style names, etc.
    • :local() and :global() selectors
    • The composes property


@parcel/css can be used from Parcel, as a standalone library from JavaScript or Rust, or wrapped as a plugin within any other tool.

From Node

See the TypeScript definitions for full API docs.

Here is a simple example that compiles the input CSS for Safari 13.2, and minifies the output.

const css = require('@parcel/css');

let {code, map} = css.transform({
  filename: 'style.css',
  code: Buffer.from('.foo { color: red }'),
  minify: true,
  sourceMap: true,
  targets: {
    // Semver versions are represented using a single 24-bit number, with one component per byte.
    // e.g. to represent 13.2.0, the following could be used.
    safari: (13 << 16) | (2 << 8)

You can also convert the results of running browserslist into targets which can be passed to @parcel/css:

const browserslist = require('browserslist');
const css = require('@parcel/css');

let targets = css.browserslistToTargets(browserslist('>= 0.25%'));

From Rust

See the Rust API docs on docs.rs. More docs and examples are coming soon. For now, start with the StyleSheet API.

With Parcel

Add the following to your .parcelrc:

  "extends": "@parcel/config-default",
  "transformers": {
    "*.css": ["@parcel/transformer-css-experimental"]
  "optimizers": {
    "*.css": ["@parcel/optimizer-css"]

You should also add a browserslist property to your package.json, which defines the target browsers that your CSS will be compiled for.

While Parcel CSS handles the most commonly used PostCSS plugins like autoprefixer, postcss-preset-env, and CSS modules, you may still need PostCSS for more custom plugins like TailwindCSS. If that's the case, just add @parcel/transformer-postcss before @parcel/transformer-css-experimental, and your PostCSS config will be picked up automatically. You can remove the plugins listed above from your PostCSS config, and they'll be handled by Parcel CSS.

You can also configure Parcel CSS in the package.json in the root of your project. Currently, three options are supported: drafts, which can be used to enable CSS nesting and custom media queries, pseudoClasses, which allows replacing some pseudo classes like :focus-visible with normal classes that can be applied via JavaScript (e.g. polyfills), and cssModules, which enables CSS modules globally rather than only for files ending in .module.css.

  "@parcel/transformer-css": {
    "cssModules": true,
    "drafts": {
      "nesting": true,
      "customMedia": true
    "pseudoClasses": {
      "focusVisible": "focus-ring"

From Deno or in browser

The @parcel/css-wasm package can be used in Deno or directly in browsers. This uses a WebAssembly build of Parcel CSS. Use TextEncoder and TextDecoder convert code from a string to a typed array and back.

import init, {transform} from 'https://unpkg.com/@parcel/css-wasm';

await init();

let {code, map} = transform({
  filename: 'style.css',
  code: new TextEncoder().encode('.foo { color: red }'),
  minify: true,

console.log(new TextDecoder().decode(code));




$ node bench.js bootstrap-4.css 
cssnano: 542.879ms
159636 bytes

esbuild: 16.839ms
160332 bytes

parcel-css: 4.345ms
143121 bytes

$ node bench.js animate.css
cssnano: 283.105ms
71723 bytes

esbuild: 11.858ms
72183 bytes

parcel-css: 1.973ms
23666 bytes

$ node bench.js tailwind.css 
cssnano: 2.198s
1925626 bytes

esbuild: 107.668ms
1961642 bytes

parcel-css: 43.368ms
1824130 bytes
  • Deno support?

    Deno support?

    Are there any plans to support Deno? I've tried to import it, but get errors about missing ./pkg directory.

    When importing from Skypack https://cdn.skypack.dev/@parcel/css...

       Import "./pkg" could not be resolved from file.
    opened by joelmoss 19
  • Unsupported pseudo class or element: cue

    Unsupported pseudo class or element: cue

    🐛 bug report

    I believe this is valid SCSS - it worked in my old environment (node 16, parcel 2.0), but now that I've needed to upgrade (node 18, parcel 2.6) it says "Unsupported pseudo class or element: cue"

    ::cue(v[voice="active"]) {
       color: yellow;

    🎛 Configuration (.babelrc, package.json, cli command)

    parcel build --public-url . src/index.html

    🤔 Expected Behavior

    ::cue(v[voice="active"]) {color: yellow;}

    appears in the final CSS

    😯 Current Behavior

    Build error: "Unsupported pseudo class or element: cue"

    💁 Possible Solution

    🔦 Context

    This is the syntax for styling VTT subtitles used in HTML5 videos


    💻 Code Sample

    🌍 Your Environment

    | Software | Version(s) | | ---------------- | ---------- | | Parcel | 2.6.0 | Node | 18.3.0 | npm/Yarn | 8.11 | Operating System | Linux in Docker on an M1 Mac

    opened by shish 18
  • error with star-prefixed css properties

    error with star-prefixed css properties

    const css = require('@parcel/css');
        filename: 'style.css',
        code: Buffer.from('.clearfix { *zoom: 1; }'),
        minify: true

    results in

    SyntaxError: Unexpected token Delim('*')
        at Object.<anonymous> (/home/dominikg/develop/vite-ecosystem-ci/parcel.cjs:3:5)
        at Module._compile (node:internal/modules/cjs/loader:1101:14)
        at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
        at Module.load (node:internal/modules/cjs/loader:981:32)
        at Function.Module._load (node:internal/modules/cjs/loader:822:12)
        at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
        at node:internal/main/run_main_module:17:47 {
      fileName: 'style.css',
      source: '.clearfix { *zoom: 1; }',
      loc: { line: 1, column: 13 }

    found via css-minification-benchmark. https://github.com/GoalSmashers/css-minification-benchmark/pull/101

    Some of their test data is old and still has them: https://github.com/GoalSmashers/css-minification-benchmark/blob/e1d52eaea8e1107e95ea06f5cc085227cd36b2c0/data/gumby.css#L1216

    iirc they were used to add special treatment for ancient IE


    opened by dominikg 18
  • Additional CLI features

    Additional CLI features

    As of #44 we have a basic CLI. Currently it can minify and output to stdout or a file, but might be nice to add a few more features.

    • --targets option. Could accept a browserslist and convert them to Parcel CSS targets with browserslist-rs (see #37).
    • --sourcemap option. Should output a source map file in addition to a css file, and add a sourceMappingUrl comment to the CSS.
    • --nesting option to enable parsing CSS nesting.
    • --css-modules option to enable CSS modules. Output a JSON file in addition to compiled CSS?
    • Ability to compile multiple files at once, either by passing file names or directories.
    enhancement good first issue 
    opened by devongovett 14
  • Could not resolve lightningcss.linux-arm64-gnu.node in Docker with M1

    Could not resolve lightningcss.linux-arm64-gnu.node in Docker with M1

    I'm not sure if this belongs in Parcel or here, but I'll start here and you can correct me.

    It seems like trying to use lightningcss inside Docker on an M1 Mac fails to do the right thing with the binary dependencies (not sure if M1 is related or not, but that's what I'm using). I've made a demo repo to show the problem.

    If I do npm run build natively on my M1 Mac, it works. However, inside Docker, the build gives this:

    ❯ docker build . -t parcel-bug
    [+] Building 21.3s (9/9) FINISHED
     => [internal] load build definition from Dockerfile                       0.0s
     => => transferring dockerfile: 116B                                       0.0s
     => [internal] load .dockerignore                                          0.0s
     => => transferring context: 34B                                           0.0s
     => [internal] load metadata for docker.io/library/node:16.18.1-bullseye   0.3s
     => [1/5] FROM docker.io/library/node:16.18.1-bullseye@sha256:7fb41fa8410  0.0s
     => [internal] load build context                                          0.0s
     => => transferring context: 329B                                          0.0s
     => CACHED [2/5] WORKDIR /app                                              0.0s
     => [3/5] COPY . .                                                         0.0s
     => [4/5] RUN npm i                                                       19.6s
     => ERROR [5/5] RUN npm run build                                          1.2s
     > [5/5] RUN npm run build:
    #0 0.389
    #0 0.389 > [email protected] build
    #0 0.389 > parcel build index.html
    #0 0.389
    #0 0.819 Building...
    #0 1.102 🚨 Build failed.
    #0 1.104
    #0 1.105 @parcel/transformer-css: Could not resolve module
    #0 1.105 "/app/node_modules/lightningcss/lightningcss.linux-arm64-gnu.node" from
    #0 1.105 "/app/node_modules/lightningcss/node/index.js"
    #0 1.106
    #0 1.106   Error: Could not resolve module
    #0 1.106   "/app/node_modules/lightningcss/lightningcss.linux-arm64-gnu.node" from
    #0 1.106   "/app/node_modules/lightningcss/node/index.js"
    #0 1.106       at $0578d0f6e116167e$export$fb2a0b866a8162dc.resolve
    #0 1.106   (/app/node_modules/@parcel/package-manager/lib/index.js:4991:21)
    #0 1.106       at NodePackageManager.resolveSync
    #0 1.106   (/app/node_modules/@parcel/package-manager/lib/index.js:3510:42)
    #0 1.106       at NodePackageManager.requireSync
    #0 1.106   (/app/node_modules/@parcel/package-manager/lib/index.js:3352:34)
    #0 1.106       at Module.m.require
    #0 1.106   (/app/node_modules/@parcel/package-manager/lib/index.js:3366:25)
    #0 1.106       at require (node:internal/modules/cjs/helpers:103:18)
    #0 1.106       at Object.<anonymous> (/app/node_modules/lightningcss/node/index.js:21:22)
    #0 1.106       at Module._compile (node:internal/modules/cjs/loader:1155:14)
    #0 1.106       at Object.Module._extensions..js
    #0 1.106   (node:internal/modules/cjs/loader:1209:10)
    #0 1.106       at Module.load (node:internal/modules/cjs/loader:1033:32)
    #0 1.106       at NodePackageManager.load
    #0 1.106   (/app/node_modules/@parcel/package-manager/lib/index.js:3375:15)
    #0 1.108
    ERROR: failed to solve: executor failed running [/bin/sh -c npm run build]: exit code: 1

    Inside the container, I can see that it's pulled in what I think are the right dependencies:

    /app/node_modules# ls lightningcss*
    LICENSE  README.md  node  package.json
    README.md  lightningcss.linux-arm64-gnu.node  package.json
    README.md  lightningcss.linux-arm64-musl.node  package.json

    Inside the container, node is using process.platform === 'linux' and process.arch === 'arm64'.

    opened by humphd 13
  • Custom resolver

    Custom resolver

    Hi, I'm trying to use @parcel/css to bundle CSS files, however there doesn't seem to be a way to provide a custom resolver for @import statements, the package appears to directly use the real file system. This is a challenge for my use case where I'm hoping to use Parcel for CSS bundling in a Bazel workspace. Bazel is a build tool which puts generated files in different directories from the source code, meaning that @import './foo.css' could resolve to ./foo or $project_root/dist/bin/path/to/dir/foo.css, or even a few other paths. I would like to configure @parcel/css to resolve these paths correctly, but AFAICT, this package doesn't have any direct support for that. See https://github.com/dgp1130/rules_prerender/issues/46 and https://github.com/dgp1130/rules_prerender/commit/7e995d6c41a4b4bbf1235903a2fd400a47f710d3 for a little more info about the use case and my attempt to implement it.

    It does seem that custom resolvers are supported in .parcelrc, but I don't get the impression @parcel/css has any understanding of that configuration file. I'm unclear how the parcel package supports custom CSS resolvers if @parcel/css doesn't, but maybe they don't compose each other in the way I think they do? If there is a more appropriate package or different level of abstraction I should be using which would support resolvers, please let me know and I'm happy to try that.

    If it does make sense to support custom resolvers in @parcel/css, I'm happy to put in the effort to contribute it. I think we would just need to update BundleConfig to accept a SourceResolver from JS and then use that instead of the FileResolver. All the inputs and outputs would be strings, so serializing into and out-of JS shouldn't be too much of an issue. I think it's possible, though I haven't done too much with Rust or WASM, so any pointers or suggestions here would be appreciated.

    Is this a contribution you would be interested in accepting or am I going about this problem in the wrong manner?

    opened by dgp1130 13
  • Custom parser and visitor API

    Custom parser and visitor API

    This is an experiment that adds support for custom (non-standard) at rules to be parsed via the Rust API, allowing something like Tailwind to be implemented. It's accomplished by passing a custom AtRuleParser trait implementation to the ParserOptions struct. During parsing, the methods of this trait are called if no standard at rule is seen. The CssRule type has been extended to support a Custom variant, which wraps the AtRuleParser::AtRule type. This allows custom structs provided by the user to be stored as part of the stylesheet.

    An example is included that implements simple @tailwind and @apply support via this API. It can be run by cloning the branch and running cargo run --example custom_at_rule test.css, where test.css might look something like this:

    @tailwind base;
    @tailwind components;
    @tailwind utilities;
    .a {
      @apply bg-blue-400 text-red-400;


    .a {
      background-color: #00f; color: red; 

    We'd need to expose more things if we wanted to implement it for real, e.g. the printer for better formatting/sourcemaps and maybe a way to hook into the transform/minify pass. Mainly wanted to get feedback to see if this is a useful direction before continuing too far. Tailwind also has custom functions like theme, and I'm not sure how we'd handle those yet (probably by exposing the PropertyHandler trait for unparsed properties).

    It's worth noting that this approach is a bit different from how something like PostCSS works. PostCSS would accept any unknown at rule and try to guess what it can contain (does it have a block? does the block accept declarations, rules, or something else? etc.), whereas Parcel CSS works more like how browsers parse CSS where only known rules are supported which control how the rule is parsed. This results in much better performance, better error handling, and more predictable results. Hopefully it is flexible enough. If not, I suppose we could try to implement that but I'm not sure it's possible without potentially unbounded lookahead in the parser...

    opened by devongovett 12
  • Can't load parcel-css on Ubuntu 20.04 LTS

    Can't load parcel-css on Ubuntu 20.04 LTS

    Could not resolve module "<PROJECT_DIR>/node_modules/@parcel/css/parcel-css.linux-x64-gnu.node" from

    I used npm install --save-dev parcel to install. I looked at https://github.com/parcel-bundler/parcel-css/issues/139 and tried both:


    in my Node REPL, both of which returned MODULE_NOT_FOUND. Then I ran npm install --save-dev @parcel/css-linux-x64-gnu, which fixed my issue.

    Should I have done something differently to load the package automatically?

    opened by samuelstevens 11
  • Add sourcemap, nesting, and css-modules CLI flags

    Add sourcemap, nesting, and css-modules CLI flags

    Address parts of #52, but not --targets or transforming multiple files.

    • makes --minify a boolean option, instead of a subcommand
    • instead of --input-file option as part of the minify subcommand, input file is now a required positional arg
    • moves --output-file from subcommand to the top level
    • adds --nesting boolean option, to enable nesting
    • adds --css-modules and --css-modules-output-file options
    • adds --sourcemap option
    • adds integration tests in rust for the CLI in tests/cli_integration_tests.rs

    CSS Modules and sourcemap options make what seem to me like decent default choices for where to send their output.

    • Sourcemap requires an output file, since it doesn't make sense to have a sourcemap without a file...
    • if there's an output file out.css, then the map is written to out.css.map
    • css modules allows specifying a path for the json output, or writes to out.json if there's an output file named out.css

    I'd be glad for any feedback, and happy to carve it into smaller chunks, in case this PR is too large.

    opened by rrcobb 11
  • detect-libc returns `glibc` on Linux

    detect-libc returns `glibc` on Linux

    hence tries to locale package @parcel/css-linux-x64-glibc,

    [admin@2445c87ab686 /home/admin]
    Welcome to Node.js v16.15.0.
    Type ".help" for more information.
    > require('detect-libc').familySync()

    Should @parcel/css-linux-x64-gnu be renamed as @parcel/css-linux-x64-glibc, or both should be published?

    opened by cyjake 10
  • Support for design tokens

    Support for design tokens


    After releasing https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-design-tokens#readme I was curious to hear your feedback on this and gauge your interest of implementing something similar in @parcel/css.

    Our main concern with existing tools around design tokens is that these take away too much control and freedom from stylesheet authors. (creating an accessible website is impossible for example)

    Converging on a single way to expose design tokens in CSS source code will help stylesheet authors switch tooling or even use multiple tools side by side.

    This will also make it more worthwhile for other tools (editors, linters, ...) to support this.

    Any feedback or insights would be greatly appreciated :)

    opened by romainmenke 10
  • Support for svelte style preprocessing

    Support for svelte style preprocessing

    Lightningcss is cool and working good with most of the bundlers.

    I am using Svelte + Vite with official vite-plugin-lightningcss but the styles declared in .svelte files are not transpiled or minified using lightningcss. I tried to manually add lightning css as a style preprocessor in svelte configuration but I couldn't able to add it.

    Please add svelte compiler support via a plugin or a config option

    opened by Rajaniraiyn 1
  • possible to use in stackblitz?

    possible to use in stackblitz?

    When running in stackblitz, I get this error when importing lightningcss:

    Error: Cannot find module '../lightningcss.linux-x64-gnu.node'
    Require stack:
    - /home/projects/node-n6my9w/node_modules/lightningcss/node/index.js
        at Module._resolveFilename (https://noden6my9w-ec0u.w-credentialless.staticblitz.com/blitz.8dd2e1d89f7d2e6b43a2b4af08588e58ffd9a2ea.js:6:217308)
        at Module._load (https://noden6my9w-ec0u.w-credentialless.staticblitz.com/blitz.8dd2e1d89f7d2e6b43a2b4af08588e58ffd9a2ea.js:6:214847)
        at Module.require (https://noden6my9w-ec0u.w-credentialless.staticblitz.com/blitz.8dd2e1d89f7d2e6b43a2b4af08588e58ffd9a2ea.js:6:218087)
        at i (https://noden6my9w-ec0u.w-credentialless.staticblitz.com/blitz.8dd2e1d89f7d2e6b43a2b4af08588e58ffd9a2ea.js:6:415284)
        at _0x434ff9 (https://noden6my9w-ec0u.w-credentialless.staticblitz.com/blitz.8dd2e1d89f7d2e6b43a2b4af08588e58ffd9a2ea.js:15:142782)
        at Object.eval (file:///home/projects/node-n6my9w/node_modules/lightningcss/node/index.js:21:22)
        at Object.function (https://noden6my9w-ec0u.w-credentialless.staticblitz.com/blitz.8dd2e1d89f7d2e6b43a2b4af08588e58ffd9a2ea.js:15:143544)
        at Module._compile (https://noden6my9w-ec0u.w-credentialless.staticblitz.com/blitz.8dd2e1d89f7d2e6b43a2b4af08588e58ffd9a2ea.js:6:219079)
        at Module._extensions..js (https://noden6my9w-ec0u.w-credentialless.staticblitz.com/blitz.8dd2e1d89f7d2e6b43a2b4af08588e58ffd9a2ea.js:6:219743)
        at Module.load (https://noden6my9w-ec0u.w-credentialless.staticblitz.com/blitz.8dd2e1d89f7d2e6b43a2b4af08588e58ffd9a2ea.js:6:217769) {
      code: 'MODULE_NOT_FOUND',
      requireStack: [

    See repro (same project works fine locally): https://stackblitz.com/edit/node-n6my9w?file=index.js

    opened by mayank99 7
  • "1/1" Aspect-ratio media query decimal transformation

    🐛 bug report

    Parcel seems to transform the aspect-ratio "1/1" media query into decimal 1.

    🎛 Configuration (.babelrc, package.json, cli command)

    relevant package.json

      // ...
      "devDependencies": {
        // ...
        "@parcel/packager-raw-url": "^2.5.0",
        "@parcel/transformer-sass": "^2.5.0",
        "@parcel/transformer-webmanifest": "^2.5.0",
        "parcel": "^2.8.2",
        "parcel-reporter-static-files-copy": "^1.3.4",
        "process": "^0.11.10",
        "punycode": "^1.4.1",


      "extends": ["@parcel/config-default"],
      "reporters":  ["...", "parcel-reporter-static-files-copy"]

    🤔 Expected Behavior

    In a CSS file I have:

    @media (max-aspect-ratio: 1/1) {
        visibility: hidden;

    I expect to have the same in the output css.

    😯 Current Behavior

    It gets transformed to

    @media (max-aspect-ratio: 1) {
      .mid-container {
        visibility: hidden;

    and thus doesn't work.

    💁 Possible Solution

    Could not find any workarounds. Edit: just found one, I guess I'll use 1000/1001 for the time being.

    🔦 Context

    Doesn't seem to happen to other numbers, e.g. 3 / 4. Spaces don't help, i.e. 1 / 1 gets transformed.

    💻 Code Sample

    🌍 Your Environment

    | Software | Version(s) | | ---------------- | ---------- | | Parcel |^2.8.2 | Node |v16.13.0 | npm/Yarn | npm 8.3.0 | Operating System | Linux Mint 20.3 Una

    opened by proto-n 7
  • Optimize media query rulesets

    Optimize media query rulesets

    It seems like there's an optimization to be had by grouping rules from the same media queries. For example, I'm working on dark mode for a project and the minified stylesheet has six instances of @media screen and (prefers-color-scheme:dark){}. Five of those could have been removed from the output (that's 235 characters, and I'm still creating more). I can see other media queries where this should be the case as well.

    Perhaps there's an edge case(s) that prevent this from being doable, but if I manually merge my six instances into one everything still works.

    opened by jfbrennan 2
  • Can't disable `grid` feature

    Can't disable `grid` feature

    Right now it isn't possible to run cargo build --no-default-features, since lightningcss does not currently compile with the "grid" feature disabled.

    It looks like the issue is that the is_shorthand method is pattern matching on the grid properties even if the "grid" feature is disabled.


    The grid feature is the only one that has a feature flag. Why is it necessary?

    opened by chinedufn 1
  • v1.18.0(Jan 4, 2023)

    This release adds support for custom transform visitors written in JavaScript, which lets you extend Lightning CSS with support for custom CSS syntax extensions, perform build time transforms, and more. It also adds support for nested @container and @layer rules, implements vendor prefixing for @supports, adds support for compiling from stdin via the CLI, and reduces compile times for the Rust crate by adding feature flags.

    Custom transforms

    The Lightning CSS visitor API enables you to implement custom non-standard extensions to CSS, making your code easier to author while shipping standard CSS to the browser. You can implement extensions such as custom shorthand properties or additional at-rules (e.g. mixins), build time transforms (e.g. convert units, inline constants, etc.), CSS rule analysis, and much more.

    The API is designed to call into JavaScript as little as possible. You provide functions for specific types of values you're interested in such as Length, Url, or specific properties or rules. Lightning CSS fully parses all CSS rules and properties (with individual type definitions!), and only calls your plugin when it visits a value type you need to transform. This granularity improves performance, and also makes it much easier to build plugins since you don't need to worry about parsing values or selectors yourself. You can return a new value from a visitor function, or even remove or replace a value with multiple values in some cases. Check out the docs for more details!

    Custom transforms have a build time cost: it can be around 2x slower to compile with a JS visitor than without. That being said, it is around 6x faster than equivalent postcss plugins in my testing. While standard CSS features should continue to be implemented in Rust as part of Lightning CSS core, the plugin API can help you migrate from other tools while supporting non-standard syntax extensions you might use. We look forward to hearing your feedback!

    Playground updates

    The Lightning CSS playground has also been updated to support visitors, which makes it easy to play around right in your browser. It also has a new editor experience powered by Code Mirror including syntax highlighting and inline errors. Check out an example with a custom visitor to see what it can do.

    New docs

    The Lightning CSS website has also been updated to include documentation for all of the features, including transpilation, CSS modules, bundling, and minification.


    • JavaScript visitor API for custom transforms – #363
    • Add visitor support to WASM build via napi-wasm – #373
    • Parse @container and @layer block rules nested within style rules – 615893c00386fe154c7ad33fddc116416e25b407
    • Add projectRoot option and use relative paths for CSS module hashes – 33febb4a87f40da0d9d0991ac5c886f8691fcd26
    • Implement vendor prefixing for @supports – 787f46f7e6b673778bfc33d95cf77fad7e730220
    • CLI support for piping – #380
    • Introduce "bundler" feature flag – #358
    • Put all of serde behind feature flag – #360
    • Introduce "visitor" feature flag – #367
    • Add sourcemap feature – #372
    • Remove derive-move – #377


    • Fix important declarations within nested at rules – 6a7d19e81234809bc3c27ac65bc14e9ee4422a2c
    • Remove parentheses from supports condition AST – 87ca70512ca5a57ae5f8cd81f890faf30f5b28ce
    Source code(tar.gz)
    Source code(zip)
  • v1.17.1(Nov 30, 2022)

    Fixed a regression where zero lengths were serialized without a unit in custom properties, which could break calc() usages. 0afccf92d206022cd7f9f62975ed1f11354b68e2

    Source code(tar.gz)
    Source code(zip)
  • v1.17.0(Nov 29, 2022)

    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 @page – 80a982a181269aed6dc3e508207fd77007554d40
    • Simplify :is() selector when only a single simple selector is provided as an argument – b870d1fcbb7db44147eae1274150ab81394b281b
    • Fix ARM linux GLIBC requirement – 5098cae7e804ecd6bfa1d8a1950146b96f02b6a9
    • Fix parenthesization of media queries – 5a126392ca0eb53d28e33b333a92f6ea38d56119
    • Bump napi-rs – 9f2e369ef053f555e715b63e92103f021426a37d
    • Expose and add docs for selector module – e31234f1b97c2c1d59641223ff4fad0c34ea3d66
    Source code(tar.gz)
    Source code(zip)
  • v1.16.1(Nov 6, 2022)

    Bug fixes

    • Parse :nth-col() and :nth-last-col() selectors – @yisibl in https://github.com/parcel-bundler/lightningcss/pull/302
    • Use :is for non-leading nesting with multiple compound selectors – 865270134da6f25d66ce4a4ec0e4c4b93b90b759
    • Fix flipped border-bottom-right and border-bottom-left in shorthands – @LeoniePhiline in https://github.com/parcel-bundler/lightningcss/pull/308
    • Fix auto prefixing for browser versions greater than the latest – @mischnic in https://github.com/parcel-bundler/lightningcss/pull/326

    CLI features

    • Add --browserslist option to load browsers list config by @LeoniePhiline in https://github.com/parcel-bundler/lightningcss/pull/324
    Source code(tar.gz)
    Source code(zip)
  • v1.16.0(Sep 20, 2022)

    This release adds support for the new relative color syntax, improves support for quoted CSS animation names, and fixes some bugs.

    Relative color syntax

    Lightning CSS now supports the new relative color syntax in the CSS Color Level 5 spec! This allows you to use math functions like calc() to manipulate the channel values of a source color, and to convert between color spaces. This is not yet shipping in any browsers, but Lightning CSS will do this manipulation at build time when possible, so that it works in any browser today!

    Here's a simple example, which uses the lch color space to darken slateblue by 10%. This is done by using the l channel value in a calc() expression, and preserving the c and h channels as is.

    .foo {
      color: lch(from slateblue calc(l - 10%) c h);

    This will output:

    .foo {
      color: lch(34.5711% 65.7776 296.794);

    And, when lch colors are not supported by your browser targets, Lightning CSS already supports outputting fallbacks for older browsers:

    .foo {
      color: #4e42b1;
      color: lch(34.5711% 65.7776 296.794);

    Check it out in the playground!

    Note that due to being a build time transform, CSS variables are not supported as source colors since the variable value may change at runtime. We'll have to wait for browser support for that.

    Other fixes and improvements

    • Support for parsing the border-spacing property – @yisibl in https://github.com/parcel-bundler/lightningcss/pull/294
    • Avoid converting animation: "none" to animation: "none" none – @yisibl in https://github.com/parcel-bundler/lightningcss/pull/295
    • If the browser doesn't support #rrggbbaa color syntax, output transparent instead of rgba(0, 0, 0, 0) – @yisibl in https://github.com/parcel-bundler/lightningcss/pull/296
    • Support parsing angles with unitless zero in gradients and transforms – https://github.com/parcel-bundler/lightningcss/commit/cbd392f4e7c616a0c40754f4419c55eb3362ea49
    • Bump parcel_sourcemap dependency to fix parsing source maps without sourcesContent, and improve base64 performance – https://github.com/parcel-bundler/lightningcss/commit/061c0c2dff80bb4e25c857bfa4737c1c4092fbae
    Source code(tar.gz)
    Source code(zip)
  • v1.15.0(Sep 15, 2022)

    This release includes several new features and a bunch of bug fixes.

    New features

    • Use inline source maps during bundling – bfa8b8cec3914ab925722bb503cbc87d61923570
    • Add new preserveImports option for analyzeDependencies, which preserves the @import rules with placeholder URLs similar to url() dependencies – 676bf1fefc46a75d7098efbc53e744d89d47ba93
    • Add filename option for transformStyleAttribute, used for error messages and dependency locations – 815a1836dbff09bce2cc154c31d1660a4cfedb59
    • Add version flag to cli – @lucasweng in 3c9db12b684f34ea015a287f2a23b728ee5ade85

    Bug fixes

    • Fix types for bundleAsync – adabfc13b9ecb1a6a1b5517e61e3b07d4802fa2a
    • Fix CLI package – a82381fbcbbff04ec19368f0a8d313b466a952c4
    • Fix bundling of @import rules with both layer and import conditions – f66c6d7ddd102a885fb573e1ef5cf3d09eb2dba3
    • Fix printing flex shorthand – 84298d2a735d3cc1288c0fd5802af7b56c11fe28
    • Parenthesize custom media conditions with not – 7c5828386fac6af27423e9ae9af6f1587dfc0035
    • Fix handling of strings in animation-name property – 7efeef220b9559716dc53daa0343c0fc23ac62eb
    Source code(tar.gz)
    Source code(zip)
  • v1.14.0(Sep 8, 2022)

    We are excited to announce that Parcel CSS is now called Lightning CSS! ⚡ This new name makes it clear that the project can be used outside of Parcel, with other build tools, or even standalone.

    We also have a brand new website showcasing some of the features, along with the WASM-based playground at lightningcss.dev. This will expand over time to include more documentation and examples.

    Going forward, new releases will be under the lightningcss npm package and Rust crate. The @parcel/css package still exists on npm for backward compatibility, but now re-exports lightningcss. The parcel_css Rust crate is deprecated - please use lightningcss going forward.

    New features

    This release also includes several new features, including major improvements to the bundler.

    Custom JS resolver

    The node bindings now include a new bundleAsync function in addition to the existing bundle function. bundleAsync runs the bundler asynchronously in a background thread, and returns a promise that lets you know when it has completed. In addition, bundleAsync supports custom JavaScript-based resolvers, which allow you to customize the resolution behavior for @import specifiers, and provide the contents of files from a source other than the file system.

    let {code, map} = await css.bundleAsync({
      filename: 'style.css',
      minify: true,
      resolver: {
        read(filePath) {
          return fs.readFileSync(filePath, 'utf8');
        resolve(specifier, from) {
          return path.resolve(path.dirname(from), specifier);

    Note that providing a resolver can negatively affect performance, so only do so when you need to customize things.

    CSS modules bundling

    Dependencies in CSS modules are now also bundled. For example, the composes property allows you to reference another file. These will now be bundled, and the resolved class name will be included in the output JSON as well.

    Bug fixes

    • add types for wasm init default export – @deckchairlabs in https://github.com/parcel-bundler/parcel-css/pull/269
    • match the spec so that feature-* in @font-face tech() becomes plural – @yisibl in https://github.com/parcel-bundler/parcel-css/pull/270
    • CSS-wide keywords and none in @keyframes cannot remove quotes – @yisibl in https://github.com/parcel-bundler/parcel-css/pull/267
    Source code(tar.gz)
    Source code(zip)
  • v1.13.1(Sep 2, 2022)


    • Playground: Fix wrong text color in output panel – @marvinhagemeister in https://github.com/parcel-bundler/parcel-css/pull/259
    • Add missing semicolon in Custom Media Queries – @Marabyte in https://github.com/parcel-bundler/parcel-css/pull/260
    • Do not omit 1x resolution in image-set() – @yisibl in https://github.com/parcel-bundler/parcel-css/pull/264
    • Suppress unsupported pseudo class or element warning if vendor prefixed – @pfroud in https://github.com/parcel-bundler/parcel-css/pull/266
    Source code(tar.gz)
    Source code(zip)
  • v1.13.0(Aug 22, 2022)

    This release includes a few new features and bug fixes.

    Parcel CSS will now try to preserve unknown @ rules and selectors rather than erroring (a warning will be emitted instead). These rules are not fully parsed and therefore may not be minified as much as possible. This is useful in cases where Parcel CSS has not yet implemented a feature that browsers are experimenting with.

    We now also have experimental bindings to use Parcel CSS via C, which will enable it to be used from many languages other than Rust and JavaScript. See here for an example. For now, this will need to be compiled from source. More features will be added in future updates as the need arises (please open a feature request).


    Bug fixes

    Source code(tar.gz)
    Source code(zip)
  • v1.12.1(Jul 31, 2022)

    This release includes bug fixes.

    • Fix stack overflow regression – c1c67e04b653217e6cdaddad254c2dade851905f
    • Update compat data – b658cb91c397b82183752d23a57df7f4fa0afcdd
    • Fix prefixing mask-image – 713ce2e4e3adc23c28b9f8382fda2a951e908cf4
    • Prevent double prefixing mask-image – 6b157544f5e7c90ac0fd6ae9fefeeac468b40726
    • Add missing errorRecovery option to TypeScript types for transformStyleAttribute function – 8de63d99d4e36b83c552908c6a3e67eb0965c285
    Source code(tar.gz)
    Source code(zip)
  • v1.12.0(Jul 14, 2022)

    This release includes several new features including more math functions, container queries, a new error recovery mode, and improved minification.

    Math functions

    Parcel CSS can now simplify the following math functions:

    • Trig functions: sin, cos, tan, asin, acos, atan, and atan2
    • Exponential functions: pow, sqrt, hypot, log, and exp
    • Sign related functions: abs, sign

    These are supported everywhere calc() is supported. In addition, the numeric constants e, pi, infinity, -infinity, and NaN are supported in all calculations.

    These functions and constants do not currently have wide browser support, but Parcel CSS will handle computing the value of the calculation where possible so you can use them today. This can also help with minification, allowing you to write source code that's more readable, but distribute more compact output. For example:

    width: calc(100px * sin(pi / 4));

    compiles to:

    width: 70.7107px;

    Error recovery

    In browsers, when an invalid rule or declaration is encountered, it is skipped, and the parser tries its best to recover and continue parsing the following rules. This is useful for future proofing, so that when new types of rules or declarations are added to CSS, they don't break older browsers. However, as a dev tool, Parcel CSS chooses to be more strict by default, and will emit errors when it fails to parse a rule. This way, developers are aware when they make an error that would have silently been skipped in a browser, and can fix their mistake.

    However, this caused issues in third party libraries, which sometimes unintentionally contain invalid rules. In other cases, older libraries perform CSS hacks to target specific browsers like Internet Explorer. These are not valid CSS syntax, so other browsers will ignore them, but Parcel CSS will error. If you cannot easily edit a dependency to fix these problems, it can be frustrating.

    Parcel CSS now has a new errorRecovery option (--error-recovery via the CLI), which can be enabled to make Parcel CSS warn rather than error on invalid rules and declarations. These will be skipped in the output, just like in a browser, but you will still get a warning. This is opt-in, so if you encounter a library with some invalid syntax and need to work around it, you can enable this option. In the Node/WASM APIs, warnings are returned as a part of the result from the transform and bundle APIs.

    Container queries

    Parcel CSS can now parse and minify @container queries, and the container-type, container-name and container declarations.

    @container my-layout (inline-size > 45em) {
      .foo {
        color: red;
    .foo {
      container-type: inline-size;
      container-name: my-layout;

    minifies to:

    @container my-layout (inline-size>45em){.foo{color:red}}.foo{container:my-layout/inline-size}

    Merge adjacent @media and @supports rules

    Parcel CSS will now merge adjacent @media and @supports rules with identical conditions.

    @media (hover) {
      .foo {
        color: red;
    @media (hover) {
      .foo {
        background: #fff;


    @media (hover) {
      .foo {
        color: red;
        background: #fff;

    Maximum nesting depth

    Previously, a stack overflow crash could occur if the parser encountered input with very deeply nested blocks (e.g. [, {, or (). Now it will return an error when reaching a maximum nesting depth instead. If using Parcel CSS in a server where denial of service attacks could be possible, please make sure to update to avoid this crash.

    Source code(tar.gz)
    Source code(zip)
  • v1.11.0(Jul 7, 2022)

    This release includes a bunch of new features for source maps, math functions, @layer minification, and several bug fixes.


    Input source maps

    Parcel CSS now supports an inputSourceMap option to the Node/WASM APIs. If you generated CSS using another tool (e.g. SASS) before passing it to Parcel CSS, this ensures that the source map generated by Parcel CSS points to the original files rather than the intermediary CSS. Parcel CSS also supports inline base64 encoded source maps in the sourceMappingURL comment. Source maps referenced by filename from a sourceMappingURL comment are not supported because Parcel CSS does not always have access to the file system.

    Downlevel space separated colors with variables in alpha component

    Parcel CSS will now downlevel the modern space separated color syntax when the alpha component includes a CSS variable. These are commonly generated by Tailwind CSS, but may not be supported in all browser targets.

    .text-white {
       --tw-text-opacity: 1;
       color: rgb(255 255 255 / var(--tw-text-opacity));

    now becomes:

    .text-white {
       --tw-text-opacity: 1;
       color: rgb(255, 255, 255, var(--tw-text-opacity));

    Note that this is only supported for variables in the alpha component because other cases are ambiguous (CSS variables may include multiple tokens).

    Merge adjacent @layer rules

    Parcel CSS will now merge adjacent @layer rules with the same name.

    @layer foo {
      .foo { color: red; }
    @layer foo {
      .foo { background: green;

    now becomes:

    @layer foo {
      .foo {
        color: red;
        background: green;

    Thanks to @jacobrask for contributing this feature!

    Simplify calc() expressions in color components

    Parcel CSS will now simplify calc() expressions inside color components where possible. For example:

    color: hsl(calc(360deg / 2) 50% 50%);

    now becomes:

    color: #40bfbf;

    Support for round(), rem(), and mod() functions

    Parcel CSS will now simplify the round(), rem(), and mod() stepped value functions. These can be used anywhere calc() is supported, and work with lengths, angles, percentages, times, etc. For example:

    width: round(22px, 5px);


    width: 20px;

    Note that this can only be simplified down to a number when the units are compatible. For example, round(22px, 5vw) will not be simplified.

    Node ESM support

    Parcel CSS can now be imported using ESM in Node. Functions are available as named exports.

    import {transform} from '@parcel/css';
    transform({ /* ... */});


    • Add libc fields only for platforms that have libc - #210
    • Implement Debug trait for ToCssResult - https://github.com/parcel-bundler/parcel-css/commit/d1cee402c765f0690da224a4a58e56bc58ec809e
    Source code(tar.gz)
    Source code(zip)
  • v1.10.1(Jun 16, 2022)

  • v1.10.0(Jun 11, 2022)

    This release includes improved minification, exposes new CSS modules features to the CLI, and fixes a bunch of bugs. Enjoy!


    • Improved merging for adjacent style rules when merging two rules enables another to be merged. e9277fd4f5e1e1d1358844223b1b3c4b4b30cfe3 – Example
    • Support for ::cue and ::cue-region pseudo elements.
    • Errors are now displayed in the playground. #200
    • Return code and CSS module exports as JSON via stdout when no output file is given #192
    • Add --css-modules-pattern and --css-modules-dashed-idents CLI options. #197
    • Add libc field to package.json to allow package managers to select the correct binary. #188


    • Fix -apple-system font name. #190
    • Improve error message for @nest. #191
    • Fix calc() in media query range syntax. #195
    • Use physical properties when logical properties are equal. #201
    • Fix order of border-image and border properties with CSS variables. #187
    • Throw useful errors when parsing invalid CSS modules pattern strings rather than panicking. 96f419f32199e96787b5148ee2bf8ab5863745ed
    Source code(tar.gz)
    Source code(zip)
  • v1.9.0(May 25, 2022)

    This release includes new features for CSS modules, support for compiling the system-ui font family, and a few other bug fixes and improvements.

    Locally scoped CSS variables

    Just like other identifiers such as class names, ids, and @keyframes, Parcel CSS now supports locally scoping CSS dashed identifiers such as variable names and @font-palette-values names. This prevents variables in one file from clashing with variables in another. By default, all variable references via the var() function are scoped to the module, so you can only reference variables declared in that file. To reference a variable declared in a different CSS module, you can use a new syntax extension:

    .button {
      background: var(--accent-color from "./colors.module.css");

    You can also reference a global variable like this:

    .button {
      color: var(--color from global);

    CSS variables may also be referenced from JavaScript, the same way as with classes:

    import * as style from './style.module.css';

    This applies not only to CSS variables but anywhere the <dashed-ident> syntax is used in CSS. Right now that means @font-palette-values and @property, but others such as @custom-media and @color-profile are coming.

    All of this is opt-in with the dashedIdents option of the cssModules config object.

      "cssModules": {
        "dashedIndents": true

    Custom CSS modules naming patterns

    You can now configure how Parcel CSS generates names in CSS modules, via the pattern option of the cssModules config object.

      "cssModules": {
        "pattern": "library-[name]-[hash]-[local]"

    The currently supported segments are:

    • [name] - the base name of the CSS file, without the extension
    • [hash] - a hash of the full file path
    • [local] - the original class name

    Support for compiling system-ui font

    The system-ui font family will now be compiled for older browsers to include a font stack that works across most common operating systems.


    .foo {
      font-family: system-ui;


    .foo {
      font-family: system-ui, AppleSystem, BlinkMacSystemFont, Segoe UI, Roboto, Noto Sans, Ubuntu, Cantarell, Helvetica Neue;

    Thanks to @onigoetz for contributing this feature!

    Other fixes and improvements

    • Support for custom resolve() method in SourceProvider trait for Rust bundler API (contributed by @dgp1130) - #177
    • Allow fragment URLs in custom properties - f6f16732057f6beecc899427d8b3862f26639919
    • Bump Rust toolchain to v1.61.0, and drop deprecated retain_mut dependency (contributed by @joshstoik1) - #184
    Source code(tar.gz)
    Source code(zip)
  • v1.8.3(May 12, 2022)

    This release includes enhancements to the Parcel CSS Rust API, and some bug fixes.

    New Rust API features


    This release begins to implement the CSS Object Model (CSSOM) API. For now, that includes some new methods in the Rust API to get, set, and remove properties. This supports reading and writing both shorthand (e.g. border) and longhand (e.g. border-left-width) properties, no matter which properties were originally written in the rule. The Property and PropertyId enums have also been updated to expose some metadata about shorthand and longhand properties as well. Check out the docs for more details.

    Source locations

    Also in this release is a new way to lazily compute the original line and column ranges for a CSS property. This information is not stored during parsing because would use a lot of memory, and it is rarely used except in error scenarios. However, it can be recomputed on demand when needed. This can be done using the property_location method of a StyleRule. You must provide the original source string that was used to parse the stylesheet along with the index of the property to retrieve the location for.

    Serde support

    Finally, we added Serde support for all nodes in the AST, so you can serialize or deserialize from JSON and other formats. Given Parcel CSS has such a detailed parsing of each CSS rule, property, and value, this may be useful for applications written in other languages that want to manipulate parsed CSS values. This is enabled behind the serde feature flag. Check out the example of how to serialize a stylesheet for more details.


    • Fix compat data for margin-inline and padding-inline shorthand properties – 0d7e4c628cbd22b4b0ede063fd2aab4ba514953b
    • Parse z-index property and fix rounding issue with serialization – 839bcd1c53baf4c6c354333f7cd3067b9ea2cfa8
    Source code(tar.gz)
    Source code(zip)
  • v1.8.2(Apr 30, 2022)

    This release includes bug fixes.

    • Always output quoted url() when not minifying. This fixes a bug when using data URLs in Parcel. #160
    • Mark jemallocator as a CLI-only dependency in the Rust crate. #157
    • Upgrade to napi-rs v2. #161
    • Improve whitespace printing when non-minified. 677277cc14891f5d0b1fcf6b57304b8d8d97017c
    • Fix stack overflow while simplifying calc expressions with nested functions 9a64787cf829dc72f5fb9b9ad687f0d447a31929
    • Fix minification of border: none shorthand 1f66776d2a9b24a4c253adde55ee413507b63684
    • Fix interpretation of "not all" in media queries f146b66b3757876f7d7762e9295b06e3a2b886e5
    Source code(tar.gz)
    Source code(zip)
  • v1.8.1(Apr 11, 2022)


    • Compile text-decoration-thickness percentage to a calc for non-supporting browsers.
    • Don't include text-decoration-thickness in text-decoration shorthand for non-supporting browsers.
    • Do not convert out of bounds rotation transforms to a matrix, or wrap around 360 degrees.
    • Only output known prefixes for the :is selector
    • Manually construct napi buffers to avoid a copy and workaround a Node.js crash with zero-length vectors.


    • Add support for selecting a version of @parcel/css in the playground. Thanks @ahabhgk!
    Source code(tar.gz)
    Source code(zip)
  • v1.8.0(Apr 7, 2022)

    This release adds support for compiling several selector features for older browsers, improves the Rust API, and fixes some bugs.


    • Downlevel :dir selector for non-supporting browsers. This is compiled to the :lang selector, which is the closest equivalent. However, it is not perfect. :dir is meant to be affected by both the dir HTML attribute and the direction CSS property, but :lang is only affected by the lang HTML attribute. When setting the dir HTML attribute the lang is usually also set, so it should work for most cases, but it is not possible to polyfill 100% correctly in pure CSS, so keep this in mind.
    • Support for :lang selector with multiple arguments, e.g. :lang(en, fr, de) This is currently only supported natively in Safari. Parcel CSS will generate fallbacks for other browsers using the :is selector, e.g. :is(:lang(en), :lang(fr), :lang(de)).
    • Downlevel :is selector in simple cases. The :is selector is fairly recent, but older browsers have supported the :-webkit-any and :-moz-any selectors, which are equivalent but do not support complex selectors (e.g. selectors with combinators) as arguments. Parcel CSS will compile :is to these fallbacks depending on your browser targets when only simple selectors are used.
    • A new approach to compiling CSS Logical Properties. Logical properties such as border-start-start-radius allow you to define many CSS properties in terms of the writing direction, so that UIs mirror in right-to-left languages. Parcel CSS used to compile logical properties using CSS variables, but this had some problems with the cascade when overriding values defined in other rules. Now, we use the :dir or :lang selectors (as described above) to compile these properties instead.
    • Rust API improvements. The Parse and ToCss traits are now exposed, which allows you to parse and serialize individual CSS rules and values. See https://github.com/parcel-bundler/parcel-css/pull/140 for an example. Errors also now implement std::error::Error.


    Source code(tar.gz)
    Source code(zip)
  • v1.7.4(Mar 31, 2022)

    This release includes bug fixes.

    • Allow empty string in @-moz-document url-prefix() function
    • font-family: revert/revert-layer cannot remove quotation marks
    • Reserve revert-layer keyword in custom ident
    • Support pseudo classes on ::-webkit-scrollbar pseudo elements
    • Parse predefined list styles as enum so they aren't renamed in css modules
    • Ensure custom property names are escaped
    • Fix css module hashing with implicit CSS grid line names
    Source code(tar.gz)
    Source code(zip)
  • v1.7.0(Mar 19, 2022)

    This release adds a number of new features, including improved vendor prefixing support, and support for new CSS syntax features.

    • Vendor prefixing and improved minification for mask properties. This includes collapsing multiple separate properties into shorthands, as well as support for new color fallbacks. Example.
    • Vendor prefixing for clip-path
    • Vendor prefixing for filter
    • Downlevel :not selector list syntax for older browsers
    • Parsing support for :has, now supported natively in Safari.
    • Support for @font-palette-values rule and font-palette property. These let you override the color palette of color fonts, such as emoji.
    • Support for many more length units, including in calc() simplification. These include new viewport units, and new font relative units from css-values-4.
    • Analyze url() dependencies in custom properties. Only absolute URLs are supported. Relative paths will throw an error. This is because in the browser, urls in custom properties resolve from the location where the var() is used, not where the custom property is defined. Therefore, without actually applying all var() usages, it's not possible to know all of the potential urls that will be resolved. Enforcing that these urls must be absolute resolves this ambiguity.
    • Update compatibility data from caniuse and mdn
    Source code(tar.gz)
    Source code(zip)
  • v1.6.0(Mar 10, 2022)

    This release brings more CSS Color goodies including the new color-mix() function, gamut mapping for color conversions, support for none components, and more.


    The color-mix() function from the CSS Color Level 5 spec allows you to mix two colors together by a specified amount. This works similarly to defining a gradient between two colors, and then choosing the interpolated value somewhere in between.

    This syntax is currently available behind a flag in Safari TP, but Parcel CSS parses this function and converts it to a color definition that current browsers can understand.

    color-mix(in lch, teal 65%, olive);

    results in:

    lch(49.4431% 40.4806 162.546);

    You get a ton of control over how colors are mixed as well. In addition to choosing how much of each color to mix in, you can choose which color space interpolation occurs in as well as control how hues are mixed. For example:

    color-mix(in lch longer hue, teal 65%, olive);

    results in:

    lch(49.4431% 40.4806 288.546);

    Parcel CSS will also convert this color to a legacy RGB color supported by older browsers as well if needed.

    Learn more about color-mix() and interpolation in the spec, and try it out!

    none components

    Colors can now also have components that are defined as none. For example, hsl(none 20% 40%). This defines an HSL color where the hue component is "missing". If rendered directly, this is equivalent to a value of 0. However, these missing components are interpreted differently when mixing colors using color-mix(). In this case, the none component is replaced by the corresponding component in the other color. For example:

    color-mix(in hsl, hsl(none 20% 40%), hsl(30deg none 80%));

    is equivalent to:

    hsl(30deg 20% 60%)

    The none components of each color are replaced with the other, and the remaining ones are interpolated.

    This can also happen automatically in some cases, when components are deemed "powerless". Read more about how this works in the spec.

    Gamut mapping

    Some color spaces have a higher color gamut than others. This means the range of valid values is wider, i.e. it can represent more colors. For example, the P3 color space can represent around 25% more colors than sRGB. When converting between color spaces, we need to decide how to handle these "out of gamut" colors. Previously, this was done by clipping. For example, color(display-p3 0 1 0) would become rgb(0, 255, 0). However, this can result in strange behavior in some cases, where you end up with a very different looking color because the relative amounts of each channel changed when one of them is clipped.

    Now, Parcel CSS implements Gamut Mapping as defined in the CSS Color spec. This attempts to find a closer color to the intended one within the gamut of the target color space by converting the color to the OKLab color space and adjusting the chroma component (i.e. how "colorful" it is) until the result is within the color gamut and "close enough" to the original color. The above example now converts to rgb(0, 249, 66) instead of rgb(0, 255, 0).

    More improvements

    • If you're using the Rust API, each color format is now represented as a struct and you can convert between them easily using Rust's From and Into traits.
    • Color fallback generation is improved so that we generate fewer fallbacks when not needed.
    • Fixed the order of border and border-image declarations in generated code.
    Source code(tar.gz)
    Source code(zip)
  • v1.5.0(Mar 2, 2022)

    This release adds support for the CSS Color Level 4 spec, which enables many new ways to define colors including high gamut (e.g. HDR) color spaces. Currently, these are only implemented in Safari, but Parcel CSS can now compile them to older sRGB colors supported across all browsers automatically.

    The supported functions are:

    • lab() and lch() – these are device independent color spaces which can represent the entire human visual spectrum. Currently supported in Safari 15.
    • oklab() and oklch() – an improved version of the lab and lch color spaces. Available in Safari TP.
    • color() – provides a way to use pre-defined color spaces such as Display P3 (supported since Safari 10), rec2020, and CIE XYZ. All specified color spaces are supported.

    This screenshot shows the difference between sRGB and lab in terms of color gamut. The lab version is much more vibrant when displayed on modern hardware with high color gamut support.


    Parcel CSS will compile these colors according to your browser targets. When a browser doesn't support them, duplicate fallback declarations will be created containing the equivalent sRGB color. The original color will also be included so that browsers that support it will get a higher color gamut. If a lower version of Safari is included that doesn't support Lab but does support P3, a Display P3 version will also be included as it includes a higher color gamut than sRGB.

    For example:

    .foo {
      color: oklab(59.686% 0.1009 0.1192);


    .foo {
      color: #c65d07;
      color: color(display-p3 .724144 .386777 .148795);
      color: lab(52.2319% 40.1449 59.9171);

    In addition, Parcel CSS also supports these colors when used within custom properties, or in declarations that use var() references. In these cases, fallbacks cannot be done with duplicate declarations in the same rule. Instead, Parcel CSS outputs a duplicate rule within an @supports block.

    .foo {
      text-shadow: var(--x) lab(29.2345% 39.3825 20.0664);
      --foo: lab(29.2345% 39.3825 20.0664);


    .foo {
      text-shadow: var(--x) #7d2329;
      --foo: #7d2329;
    @supports (color: color(display-p3 0 0 0)) {
      .foo {
        text-shadow: var(--x) color(display-p3 .451706 .165516 .1701);
        --foo: color(display-p3 .451706 .165516 .1701);
    @supports (color: lab(0% 0 0)) {
      .foo {
        text-shadow: var(--x) lab(29.2345% 39.3825 20.0664);
        --foo: lab(29.2345% 39.3825 20.0664);

    Try it out here.

    To learn more about these new color spaces, check out this article, and play around with this lab color picker.

    Source code(tar.gz)
    Source code(zip)
  • v1.4.0(Feb 23, 2022)

    This release add some new features, including support for unicode-range syntax, cascade layers, and the @property rule. There is also a fix to the order in which CSS files are bundled to be correct according to the spec and browser behavior.

    Unicode range

    The unicode-range property within an @font-face rule declares what characters a font supports. Parcel CSS now supports parsing and minifying this syntax. For example, U+2000-20FF minifies as U+20??. Example

    Cascade layers

    Parcel CSS now supports parsing, minifying, and bundling cascade layers including the @layer rule and layers defined within @import rules. When bundling an @import with a layer, the rules within that dependency are wrapped in an @layer rule. For example:

    /* a.css */
    @import "b.css" layer(foo);
    .a { color: red }
    /* b.css */
    .b { color: green }


    @layer foo {
      .b {
        color: green;
    .a {
      color: red;

    Bundling order

    Cascade layers also introduced a change to the way bundling must occur to preserve correctness. @layer rules are one of the few rules that are allowed before @import rules, so we can no longer simply concatenate files together. The imported CSS must be inlined where the @import rule was seen, preserving the @layer rules before.

    This also uncovered a bug in the bundling logic. If a CSS file is imported twice, the last occurrence should be preserved rather than the first. For example:

    /* index.css */
    @import "a.css";
    @import "b.css";
    @import "a.css";
    /* a.css */
    body { background: green; }
    /* b.css */
    body { background: red; }

    In this example, the body should be green, but the previous bundling behavior made it red. This might seem unexpected, as a number of CSS bundlers implement this incorrectly, taking the first instance rather than the last. But in browsers, both @import "a.css" rules are evaluated, so the last one wins. Now Parcel CSS matches browser behavior here as well.

    @property rule

    The @property rule allows you to register the syntax for custom properties, so that they may be type checked, have a default value, and control inheritance. For example:

    @property --property-name {
      syntax: '<color>';
      inherits: false;
      initial-value: #c0ffee;

    This defines a custom property named --property-name, which accepts colors, has an initial value of #c0ffee and is not inherited.

    Parcel CSS can now parse, validate and minify this rule. This includes parsing the syntax property and validating that the initial-value parses according to it. The initial-value and syntax are also minified accordingly. Here's a live example.

    Source code(tar.gz)
    Source code(zip)
  • v1.3.2(Feb 16, 2022)

    This release includes a few bug fixes:

    • Fixes @media rules with no media queries, improves minification for media queries that always match, and improves error reporting for invalid media queries. https://github.com/parcel-bundler/parcel-css/issues/84
    • Fixes lifetime issue with latest dashmap version that caused compile errors for the Rust crate. https://github.com/parcel-bundler/parcel-css/issues/83
    • Merge important declarations of adjacent rules. https://github.com/parcel-bundler/parcel-css/pull/89
    Source code(tar.gz)
    Source code(zip)
  • v1.3.0(Feb 14, 2022)

    This release adds a new standalone CLI for Parcel CSS, implements @import bundling, reduces binary size, and improves performance.


    Parcel CSS now has a standalone CLI written in Rust, which can be used when you only need to compile CSS and don't need a more advanced build tool. It supports all Parcel CSS features, including enabling nesting and custom media, CSS modules, source maps, targets, and more. It also supports a --bundle option, which inlines @import rules. See below for details about that.

    Check out the readme for more details.

    Thanks to @schultyy and @rrcobb for contributing to the CLI!


    We now have a bundle method in the Node API, and a --bundle option in the CLI, which inlines the contents of @import rules. This lets you write multiple source files, but compile them into a single output file. Parcel CSS handles wrapping rules in @media and @supports blocks as needed, and files are parsed in parallel for performance. This also enables @custom-media rules to be referenced across different files.

    Reduced binary size and improved performance

    We have reduced the binary size for the Node bindings significantly in this release (4.08 MB -> 2.64 MB). This was accomplished using some Rust compiler options, as well as some refactoring of large methods. This refactoring also happened to improve performance as well by another ~5%! Here are the updated benchmark results:

    image Source code(tar.gz)
    Source code(zip)
  • v1.2.0(Jan 31, 2022)

    Improved performance

    This release improves performance by avoiding string copies during parsing, and instead borrowing all strings stored in the AST from the input source code (i.e. just pointers). This also reduces memory usage. New benchmark results:


    Improved minification

    This release also improves minification of custom properties, and properties containing CSS variable references. Parcel CSS can now remove unnecessary whitespace and comments in these properties, and minify color values and numbers embedded within them. For example:

    .foo {
      color: var(--color, rgb(255, 255, 0));

    now minifies to:


    Minification of border related properties is also improved by better use of shorthands. For example, the following css:

    .foo {
      border-top: 1px solid black;
      border-bottom: 1px solid black;
      border-left: 2px solid black;
      border-right: 2px solid black;

    now compiles to:

    .foo {
      border: 1px solid #000;
      border-width: 1px 2px;

    Other fixes

    • Fix compilation of CSS nesting selectors with combinators in parent rule - 1e79fa7dd839cf4ea588c2c96c6623560ceca667
    • Fix list-style-type property in CSS modules when none value is used - 9d38efbd11b74a71d001c077d56bae7491afe078
    • Fix dependency collection in image-set - 8378ae25479c4ad57a46518a26403e7bfef464b4
    • Fix vendor prefixing image-set - 0d01b83fdc165d6e78843565f2392240ccf2edef
    • Update prefix and compat data - 7060ca1579aea1edf76d6e9d370156d481150dfe
    • Fix transition vendor prefix decomposition - 718efba6f9db1e1bd07755f68a69823282385c5d
    • Improve border shorthand minification - 46cca004993e67eed6f0ca64570e55f705ee5b30
    • Fix compat logic with multiple targets - f1bb3cf40b03f2292c6387eb5c85f6fb393aa9d3
    • More progress on CLI, including sourcemap, nesting, and css-modules CLI flags - d13f86a9820ac1b184153d09eaf0a987b3855aba
    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Jan 20, 2022)

    This release adds support for the @custom-media rule defined in the media queries level 5 spec! This allows you to define media queries that can be reused in multiple @media rules.

    @custom-media --modern (color), (hover);
    @media (--modern) and (width > 1024px) {
      .a {
        color: green;

    compiles to:

    @media ((color) or (hover)) and (min-width: 1024px) {
      .a {
        color: green;

    Try it out in the playground.

    This feature can be enabled using the customMedia option under the drafts object, similar to nesting. A few things to note:

    • The drafts option only enables parsing of @custom-media rules. You must have targets set for it to be compiled.
    • We currently error on complex Boolean logic with media types (e.g. print, screen, etc.). This is quite difficult to emulate with current CSS syntax, so it is not supported at the moment.
    • @custom-media rules currently must be defined in the same file where they are used, because Parcel CSS does not handle @import rules itself. This may change in a future release.
    Source code(tar.gz)
    Source code(zip)
  • v1.0.3(Jan 17, 2022)

    What's Changed

    • Implement basic parsing for legacy @viewport rule in https://github.com/parcel-bundler/parcel-css/commit/56e6bf0c47805cd2d9e66c6d78726975597432a8
    • Add basic CLI by @schultyy in https://github.com/parcel-bundler/parcel-css/pull/44
    • Added StyleSheet::new method to Rust API by @deckchairlabs in https://github.com/parcel-bundler/parcel-css/pull/53
    • Simplify comparison in browser compatibility data by @Danue1 in https://github.com/parcel-bundler/parcel-css/pull/54
    • Write url placeholders with quotes in https://github.com/parcel-bundler/parcel-css/commit/41eefe4d20a64cec062e40851f5b7ffb59f3545c

    New Contributors

    • @schultyy made their first contribution in https://github.com/parcel-bundler/parcel-css/pull/44
    • @deckchairlabs made their first contribution in https://github.com/parcel-bundler/parcel-css/pull/53
    • @Danue1 made their first contribution in https://github.com/parcel-bundler/parcel-css/pull/54

    Full Changelog: https://github.com/parcel-bundler/parcel-css/compare/v1.0.2...v1.0.3

    Source code(tar.gz)
    Source code(zip)
📦🚀 Blazing fast, zero configuration web application bundler
This project aims to implement a CSS(less like) parser in rust. Currently the code is targeting the PostCSS AST. Very early stage, do not use in production.

CSS(less like) parser written in rust (WIP) This project aims to implement a CSS(less like) parser in rust. Currently the code is targeting the PostCS

Huang Liuhaoran 21 Aug 23, 2022
Yet Another Parser library for Rust. A lightweight, dependency free, parser combinator inspired set of utility methods to help with parsing strings and slices.

Yap: Yet another (rust) parsing library A lightweight, dependency free, parser combinator inspired set of utility methods to help with parsing input.

James Wilson 117 Dec 14, 2022
Website for Microformats Rust parser (using 'microformats-parser'/'mf2')

Website for Microformats Rust parser (using 'microformats-parser'/'mf2')

Microformats 5 Jul 19, 2022
🕑 A personal git log and MacJournal output parser, written in rust.

?? git log and MacJournal export parser A personal project, written in rust. WORK IN PROGRESS; NOT READY This repo consolidates daily activity from tw

Steven Black 4 Aug 17, 2022
A WIP svelte parser written in rust. Designed with error recovery and reporting in mind

Svelte(rs) A WIP parser for svelte files that is designed with error recovery and reporting in mind. This is mostly a toy project for now, with some v

James Birtles 3 Apr 19, 2023
PEG parser for YAML written in Rust 🦀

yaml-peg PEG parser (pest) for YAML written in Rust ?? Quick Start ⚡️ # Run cargo run -- --file example_files/test.yaml # Output { "xmas": "true",

Visarut Phusua 4 Sep 17, 2022
MRT/BGP data parser written in Rust.

BGPKIT Parser BGPKIT Parser aims to provides the most ergonomic MRT/BGP message parsing Rust API. BGPKIT Parser has the following features: performant

BGPKIT 46 Dec 19, 2022
gors is an experimental go toolchain written in rust (parser, compiler).

gors gors is an experimental go toolchain written in rust (parser, compiler). Install Using git This method requires the Rust toolchain to be installe

Aymeric Beaumet 12 Dec 14, 2022
A handwritten fault-tolerant, recursive-descent parser for PHP written in Rust.

PHP-Parser A handwritten fault-tolerant, recursive-descent parser for PHP written in Rust. Warning - this is still alpha software and the public API i

PHP Rust Tools 278 Jun 24, 2023
Pure, simple and elegant HTML parser and editor.

HTML Editor Pure, simple and elegant HTML parser and editor. Examples Parse HTML segment/document let document = parse("<!doctype html><html><head></h

Lomirus 16 Nov 8, 2022
A native Rust port of Google's robots.txt parser and matcher C++ library.

robotstxt A native Rust port of Google's robots.txt parser and matcher C++ library. Native Rust port, no third-part crate dependency Zero unsafe code

Folyd 72 Dec 11, 2022
Sqllogictest parser and runner in Rust.

Sqllogictest-rs Sqllogictest parser and runner in Rust. License Licensed under either of Apache License, Version 2.0 (LICENSE-APACHE or http://www.apa

Singularity Data Inc. 101 Dec 21, 2022
An IRC (RFC1459) parser and formatter, built in Rust.

ircparser An IRC (RFC1459) parser and formatter, built in Rust. ircparser should work on basically any Rust version, but the earliest version checked

Ethan Henderson 2 Oct 18, 2022
A rusty, dual-wielding Quake and Half-Life texture WAD parser.

Ogre   A rusty, dual-wielding Quake and Half-Life texture WAD parser ogre is a rust representation and nom parser for Quake and Half-Life WAD files. I

Josh Palmer 16 Dec 5, 2022
A modern dialogue executor and tree parser using YAML.

A modern dialogue executor and tree parser using YAML. This crate is for building(ex), importing/exporting(ex), and walking(ex) dialogue trees. convo

Spencer Imbleau 27 Aug 3, 2022
Org mode structural parser/emitter with an emphasis on modularity and avoiding edits unrelated to changes.

Introduction Org mode structural parser/emitter with an emphasis on modularity and avoiding edits unrelated to changes. The goal of this library is to

Alex Roper 4 Oct 7, 2022
Parser for Object files define the geometry and other properties for objects in Wavefront's Advanced Visualizer.

format of the Rust library load locad blender obj file to Rust NDArray. cargo run test\t10k-images.idx3-ubyte A png file will be generated for the fi

Nasser Eddine Idirene 1 Jan 3, 2022
Lexer and parser collections.

laps Lexer and parser collections. With laps, you can build parsers by just defining ASTs and deriving Parse trait for them. Usage Add laps to your pr

MaxXing 11 Jan 27, 2023
Rust parser combinator framework

nom, eating data byte by byte nom is a parser combinators library written in Rust. Its goal is to provide tools to build safe parsers without compromi

Geoffroy Couprie 7.6k Jan 7, 2023