Skip to content

Releases: parcel-bundler/lightningcss

v1.6.0

10 Mar 15:47
Compare
Choose a tag to compare

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

color-mix()

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.

v1.5.0

02 Mar 15:31
Compare
Choose a tag to compare

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.

image

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);
}

becomes:

.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);
}

becomes:

.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.

v1.4.0

23 Feb 15:53
Compare
Choose a tag to compare

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 }

becomes:

@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.

v1.3.2

16 Feb 16:42
Compare
Choose a tag to compare

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. #84
  • Fixes lifetime issue with latest dashmap version that caused compile errors for the Rust crate. #83
  • Merge important declarations of adjacent rules. #89

v1.3.0

14 Feb 16:03
Compare
Choose a tag to compare

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

CLI

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!

Bundling

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

v1.2.0

31 Jan 17:10
Compare
Choose a tag to compare

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:

image

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:

.foo{color:var(--color,#ff0)}

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 - 1e79fa7
  • Fix list-style-type property in CSS modules when none value is used - 9d38efb
  • Fix dependency collection in image-set - 8378ae2
  • Fix vendor prefixing image-set - 0d01b83
  • Update prefix and compat data - 7060ca1
  • Fix transition vendor prefix decomposition - 718efba
  • Improve border shorthand minification - 46cca00
  • Fix compat logic with multiple targets - f1bb3cf
  • More progress on CLI, including sourcemap, nesting, and css-modules CLI flags - d13f86a

v1.1.0

20 Jan 16:38
Compare
Choose a tag to compare

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.

v1.0.3

17 Jan 00:19
Compare
Choose a tag to compare

What's Changed

  • Implement basic parsing for legacy @viewport rule in 56e6bf0
  • Add basic CLI by @schultyy in #44
  • Added StyleSheet::new method to Rust API by @deckchairlabs in #53
  • Simplify comparison in browser compatibility data by @Danue1 in #54
  • Write url placeholders with quotes in 41eefe4

New Contributors

Full Changelog: v1.0.2...v1.0.3

v1.0.2

14 Jan 17:08
Compare
Choose a tag to compare
  • Improves minification of background position - 07c1e79
  • Fix parsing bug with normal keyword in font shorthand - 939d171
  • Fixes TypeScript definitions for targets option - a6a4bdc
  • Adds a WASM build that can be used in Deno or natively in browsers. See the readme for details.

v1.0.1

13 Jan 17:25
Compare
Choose a tag to compare

This release publishes architecture specific packages, e.g. @parcel/css-darwin-arm64, rather than a single package containing binaries for all platforms. The main @parcel/css package has optional dependencies on each of these, and package managers will ignore packages that aren't compatible. This reduces the typical install size of @parcel/css to ~3.8 MB.