Skip to content

Commit

Permalink
css: support for color() colors
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Dec 8, 2023
1 parent 2e59c93 commit 5671059
Show file tree
Hide file tree
Showing 11 changed files with 535 additions and 46 deletions.
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,27 @@

## Unreleased

* Add support for HWB colors in CSS
* Add support for `hwb()` and `color()` in CSS

CSS has recently added lots of new ways of specifying colors. This release adds support for lowering and/or minifying colors that use the `hwb()` syntax:
CSS has recently added lots of new ways of specifying colors. This release adds support for lowering and/or minifying colors that use the `hwb()` or `color()` syntax for browsers that don't support it yet:

```css
/* Original code */
div {
color: hwb(90deg 20% 40%);
background: color(display-p3 1 0 0);
}

/* New output (with --target=chrome99) */
div {
color: #669933;
background: #ff0f0e;
background: color(display-p3 1 0 0);
}
```

As you can see, colors outside of the sRGB color space such as `color(display-p3 1 0 0)` are mapped back into the sRGB gamut and inserted as a fallback for browsers that don't support the `color()` syntax.

* Allow empty type parameter lists in certain cases ([#3512](https://github.com/evanw/esbuild/issues/3512))

TypeScript allows interface declarations and type aliases to have empty type parameter lists. Previously esbuild didn't handle this edge case but with this release, esbuild will now parse this syntax:
Expand Down
2 changes: 1 addition & 1 deletion compat-table/src/css_table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ import (
\t"github.com/evanw/esbuild/internal/css_ast"
)
type CSSFeature uint8
type CSSFeature uint16
const (
${Object.keys(map).sort().map((feature, i) => `\t${feature}${i ? '' : ' CSSFeature = 1 << iota'}`).join('\n')}
Expand Down
1 change: 1 addition & 0 deletions compat-table/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export const jsFeatures = {

export type CSSFeature = keyof typeof cssFeatures
export const cssFeatures = {
ColorFunction: true,
HexRGBA: true,
HWB: true,
InlineStyle: true,
Expand Down
7 changes: 4 additions & 3 deletions compat-table/src/mdn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ const jsFeatures: Partial<Record<JSFeature, string>> = {
}

const cssFeatures: Partial<Record<CSSFeature, string | string[]>> = {
InsetProperty: 'css.properties.inset',
RebeccaPurple: 'css.types.color.named-color.rebeccapurple',
ColorFunction: 'css.types.color.color',
HexRGBA: 'css.types.color.rgb_hexadecimal_notation.alpha_hexadecimal_notation',
HWB: 'css.types.color.hwb',
InsetProperty: 'css.properties.inset',
Modern_RGB_HSL: [
'css.types.color.hsl.alpha_parameter',
'css.types.color.hsl.space_separated_parameters',
Expand All @@ -39,8 +40,8 @@ const cssFeatures: Partial<Record<CSSFeature, string | string[]>> = {
'css.types.color.rgba.float_values',
'css.types.color.rgba.space_separated_parameters',
],
HWB: 'css.types.color.hwb',
Nesting: 'css.selectors.nesting',
RebeccaPurple: 'css.types.color.named-color.rebeccapurple',
}

const similarPrefixedProperty: Record<string, { prefix: string, property: string }> = {
Expand Down
14 changes: 12 additions & 2 deletions internal/compat/css_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import (
"github.com/evanw/esbuild/internal/css_ast"
)

type CSSFeature uint8
type CSSFeature uint16

const (
HWB CSSFeature = 1 << iota
ColorFunction CSSFeature = 1 << iota
HWB
HexRGBA
InlineStyle
InsetProperty
Expand All @@ -20,6 +21,7 @@ const (
)

var StringToCSSFeature = map[string]CSSFeature{
"color-function": ColorFunction,
"hwb": HWB,
"hex-rgba": HexRGBA,
"inline-style": InlineStyle,
Expand All @@ -39,6 +41,14 @@ func (features CSSFeature) ApplyOverrides(overrides CSSFeature, mask CSSFeature)
}

var cssTable = map[CSSFeature]map[Engine][]versionRange{
ColorFunction: {
Chrome: {{start: v{111, 0, 0}}},
Edge: {{start: v{111, 0, 0}}},
Firefox: {{start: v{113, 0, 0}}},
IOS: {{start: v{15, 0, 0}}},
Opera: {{start: v{97, 0, 0}}},
Safari: {{start: v{15, 0, 0}}},
},
HWB: {
Chrome: {{start: v{101, 0, 0}}},
Edge: {{start: v{101, 0, 0}}},
Expand Down
25 changes: 24 additions & 1 deletion internal/css_ast/css_ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,28 @@ func TokensAreCommaSeparated(tokens []Token) bool {
return false
}

func (t Token) NumberOrFractionForPercentage() (float64, bool) {
switch t.Kind {
case css_lexer.TNumber:
if f, err := strconv.ParseFloat(t.Text, 64); err == nil {
return f, true
}

case css_lexer.TPercentage:
if f, err := strconv.ParseFloat(t.PercentageValue(), 64); err == nil {
if f < 0 {
return 0, true
}
if f > 100 {
return 1, true
}
return f / 100, true
}
}

return 0, false
}

func (t Token) ClampedFractionForPercentage() (float64, bool) {
if t.Kind == css_lexer.TPercentage {
if f, err := strconv.ParseFloat(t.PercentageValue(), 64); err == nil {
Expand All @@ -290,9 +312,10 @@ func (t Token) ClampedFractionForPercentage() (float64, bool) {
if f > 100 {
return 1, true
}
return f / 100.0, true
return f / 100, true
}
}

return 0, false
}

Expand Down
Loading

0 comments on commit 5671059

Please sign in to comment.