postcss / autoprefixer

Parse CSS and add vendor prefixes to rules by Can I Use
https://twitter.com/autoprefixer
MIT License
21.57k stars 1.25k forks source link

Use `-webkit-linear-gradient` instead of `-webkit-gradient` when the `linear-gradient` contains `var(...)`. #1515

Open Goodwine opened 3 months ago

Goodwine commented 3 months ago

INPUT

// Set browserlist to 'last 2 versions'
.foo {
  background: linear-gradient(0.25turn, #3f87a6, #ebf8e1, #f69d3c);
}

.bar {
  --value: 0.25turn, #3f87a6, #ebf8e1, #f69d3c;
  background-image: linear-gradient(var(--value));
}

GOT

.foo {
  background: -webkit-gradient(linear, left top, right top, from(#3f87a6), color-stop(#ebf8e1), to(#f69d3c));
  background: linear-gradient(0.25turn, #3f87a6, #ebf8e1, #f69d3c);
}

.bar {
  --value: 0.25turn, #3f87a6, #ebf8e1, #f69d3c;
  /* V--- BUG: Bad CSS when expanding CSS variable. ---V */
  background-image: -webkit-gradient(linear, left top, left bottom, from(var(--value)));
  background-image: linear-gradient(var(--value));
}

WANT

In these cases, it is safer to use -webkit-linear-gradient instead of -webkit-gradient:

.foo {
  background: -webkit-gradient(linear, left top, right top, from(#3f87a6), color-stop(#ebf8e1), to(#f69d3c));
  background: linear-gradient(0.25turn, #3f87a6, #ebf8e1, #f69d3c);
}

.bar {
  --value: 0.25turn, #3f87a6, #ebf8e1, #f69d3c;
  /* V--- NO BUG ---V */
  background-image: -webkit-linear--gradient(var(--value));
  background-image: linear-gradient(var(--value));
}
ai commented 3 months ago

In these cases, it is safer to use -webkit-linear-gradient instead of -webkit-gradient

Why?

WANT

You need to send PR for that. Since it is a feature for old browsers, I will not have time to implement it (too busy on preparing the slides for the talk).

Goodwine commented 3 months ago

Why? The CSS variable in the provided example contains a list of values rather than a single value. This variable is then in turn used as an argument for linear-gradient()`. Even though there is a "single" argument, browsers will expand that variable to be actually multiple arguments.

The issue in autoprefixer is that it thinks that the function has a single argument and proceeds to transform it under that assumption to -webkit-gradient(...). However, it can't introspect the CSS variable to determine whether it's a single value or a comma-separated list of values.

That limitation is reasonable, however I think Autoprefixer should be safer and either

  1. Do not do autoprefixing, because it's not safe.
  2. Do autoprefixing, but choose a safer option.

Thankfully, we can use -webkit-linear-gradient() instead of -webkit-gradient() to achieve similar support but without generating "bad" CSS.

In other words, Autoprefixer assumes custom CSS properties contain 1 and only 1 value. But they could contain multiple values.

You need to send PR for that.

Sure, no rush, I can try sending a PR later. We can also always use autoprefixer: ignore next. I just wanted to document this potential issue here :)