Releases: parcel-bundler/lightningcss
v1.7.0
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 thevar()
is used, not where the custom property is defined. Therefore, without actually applying allvar()
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
v1.6.0
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
andInto
traits. - Color fallback generation is improved so that we generate fewer fallbacks when not needed.
- Fixed the order of
border
andborder-image
declarations in generated code.
v1.5.0
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()
andlch()
– these are device independent color spaces which can represent the entire human visual spectrum. Currently supported in Safari 15.oklab()
andoklch()
– 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);
}
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
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
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
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:
v1.2.0
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:
.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 whennone
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
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 havetargets
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
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
- @schultyy made their first contribution in #44
- @deckchairlabs made their first contribution in #53
- @Danue1 made their first contribution in #54
Full Changelog: v1.0.2...v1.0.3
v1.0.2
- Improves minification of background position - 07c1e79
- Fix parsing bug with
normal
keyword infont
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.