Less.js: Hex colors with opacity tangles up

Created on 17 Jul 2018  ·  14Comments  ·  Source: less/less.js

Updated to [email protected] after which colors opacity with render as

background-color: #55555599; --> #55555599 99; (not valid)
background-color: #5559; --> #5559 9; (not valid)

bug medium priority

Most helpful comment

I've updated the color() function to recognize #RRGGBBAA as well as doing some updates to keep colors in the same color space. In the past, everything was converted to either simple hex (if alpha = 1) or rgba() for browser compatibility. Now, we can keep Less more consistent by preserving color values as used. Hex colors and keywords were already output as-is, but with my PR, Less will output hsl() and hsla() as-is (except when clamping values), and even preserve the color space after color operations like darken() or spin().

All 14 comments

Did Less even support hex rgba notation before?

@rjgotten Not directly, no. But it should just skip (preserve) unrecognized values. That's probably the regression.

@rjgotten @tapsaman I don't think this was a regression, so much as it wasn't yet supported. However, it was just a few regex changes and changes to the color node to support this form. See the tests in the PR for verification.

One thing this does is remove "invalid" colors for future compatibility. It's not until you try to use an "invalid" color in a color operation that it should throw an error at evaluation time. But Less in 3.0+ is more forgiving of values in properties, so this seemed reasonable to remove.

One thing: should Less convert #RRGGBBAA for incompatible browsers? As of today, IE/Edge have no support, and a few other browsers don't either. Microsoft hasn't given any indication they will implement any time soon. However, the reason why I implemented it is because there definitely was an issue with parsing in the color parsing function. It was grabbing the entire string and saving in color, but not advancing the parser if the color was 4 or 8 chars, which is why it was repeating the last digits.

EDIT: What I did was allow conversion by the author to rgba() format via rgba(#55555599).

Here are a list of thoughts I'm having relative to this.

  • I'm not sure it's Less's job to be conscious of browser support.
  • Conflating a Less function with a CSS function "feels" dangerous, but I can't say why.
  • We _DO_ already have the argb() function meant to output #AARRGGBB.
  • We also have a color() function. Does it support #AARRGGBB, #ARGB?
  • color: #AA334455; and color: #A345; are valid (or acceptable) CSS, even if there aren't many browsers that _understand_ that form.
  • I wonder if rbga() casting is a slippery slope. rgb(), hsl(), and hsla() are all CSS functions as well.
  • On the other hand, given Less is a superset of CSS, rgba() makes a lot of sense.

tl;dr: I think my overall first impression is that we should ensure the color() function supports 8- and 4-digit ARGB strings, since that seems to be it's purpose anyway.

Conflating a Less function with a CSS function "feels" dangerous, but I can't say why.

That ship has sailed. rgba() has existed as a Less function for a long time. But the main reason is so that you can pass colors to something like lighten(). That is, rgba() needs to internally return a color. So functions like rgba() _have_ to be Less functions if you want to actually use Less's color functions. (e.g. lighten(rgba(50,50,50,0.5), 50%)) Otherwise it would just be an unknown function call. We have to know what the color actually _is_ in order to manipulate said color.

I wonder if rbga() casting is a slippery slope. rgb(), hsl(), and hsla() are all CSS functions as well.

Yeah, I guess. But casting is the wrong way to think about it. It also enables this form: rgba(#777777, 0.5), which is allowed or will be allowed in browsers. It doesn't extend it to hsla(), that's true, but the internal implementation is much harder and also not necessary if you have a method that works.

We also have a color() function. Does it support #AARRGGBB, #ARGB?

No, thanks for pointing this out. I can add that. Although I'm confused why that function exists at all?

It also enables this form: rgba(#777777, 0.5), which is allowed or will be allowed in browsers.

To rephrase, this form is a valid color in CSS: rgba(<Color> [, opacity]). So there's no reason to not allow this.

We _DO_ already have the argb() function meant to output #AARRGGBB.

The ARGB order is specifically used for legacy DirectShow filters in Internet Explorer.
The 8- or 4-digit hex syntax in CSS is afaik RGBA order.

Supporting both also makes it directly impossible to know whether a literal #000000FF represents a fully transparent blue (ARGB), or a fully opaque black (RGBA).

My advice: drop the ARGB color support. You would only ever need it for stone-age IE browsers that are long out of commission.

My advice: drop the ARGB color support. You would only ever need it for stone-age IE browsers that are long out of commission.

We don't test support on anything less than IE11, so this is a good idea.

@rjgotten Are there any other function candidates (or features) for deprecation? I'm still confused why anyone would ever need to write a color as a _string_ in Less and then convert it to a color using the color() function. Looks like it was added 4 years ago.

I'm still confused why anyone would ever need to write a color as a string in Less and then convert it to a color using the color() function.

The only thing I can imagine is automated extraction scenarios.
E.g. a complex plugin which introsepects SVG background images and extracts color definitions from them to match color usage in other rules, or something like that.

A quite profound edge case, I think.

@rjgotten Unfortunately I couldn't find any history in the issues that explained where it came from.

I've updated the color() function to recognize #RRGGBBAA as well as doing some updates to keep colors in the same color space. In the past, everything was converted to either simple hex (if alpha = 1) or rgba() for browser compatibility. Now, we can keep Less more consistent by preserving color values as used. Hex colors and keywords were already output as-is, but with my PR, Less will output hsl() and hsla() as-is (except when clamping values), and even preserve the color space after color operations like darken() or spin().

Catching up, I'm on board. The argb() function I think answers any need for the old format. This is a good move.

Was this page helpful?
0 / 5 - 0 ratings