Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: colormin is lossy, colors in minified builds don't match development #1515

Open
adamwathan opened this issue Aug 1, 2023 · 3 comments
Labels

Comments

@adamwathan
Copy link

adamwathan commented Aug 1, 2023

Describe the bug

Right now when you minify certain color syntaxes, cssnano converts them to a different color format, for example RGB values are often converted to HSL:

/* Input */
html {
  background-color: rgb(143 101 98 / 43%);
}

/* Output */
html {
  background-color: hsla(4, 19%, 47%, .43);
}

But because the HSL values are rounded to whole numbers for the saturation and lightness channel, this is a lossy conversion — only 100 values can be represented compared to the 256 that are possible in RGB channels.

When converting the HSL value above back to RGB, it's not the same:

  html {
-   background-color: rgb(143 101 98 / 43%);
+   background-color: rgb(143 100 97 / 43%);
    /*                          ^  ^      */
  }

This issue is most noticeable when working on sites that need to share colors between the actual UI and image assets, where you can often see a seam between the image and the browser rendered UI where the colors aren't an exact match.

Expected behaviour

Colors should only be minified when it can be done in a way that guarantees no information is lost, for example converting #ffaaff to #faf, converting rgb(255, 255, 255) to #fff, or converting rgb(255, 0 ,0) to red.

Another option is to convert with higher precision, so we don't round to whole numbers and instead preserve the fractional elements. I feel like this didn't used to work but my testing now seems to show this working in modern browsers.

Alternatively, colormin could be disabled in the default preset and only enabled in the advanced preset where there are other unsafe optimizations.

Steps to reproduce

See reproduction in cssnano playground:

https://cssnano.co/playground/#eyJpbnB1dCI6Imh0bWwge1xuICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2IoMTQzIDEwMSA5OCAvIDQzJSk7XG59IiwiY29uZmlnIjoiY3NzbmFuby1wcmVzZXQtZGVmYXVsdCJ9

Version

6.0.1

Preset

default

Environment

N/A, occurs in cssnano playground.

Package details

N/A, occurs in cssnano playground.

Additional context

No response

@alexander-akait
Copy link
Member

I see, do you want to send a fix? Should not be hard

@RobinMalfait
Copy link

Hey @alexander-akait!

Which option do you prefer as the solution?

  1. Convert the color without losing information. One way we can do this is by converting the color, then converting it back and checking if it is the same color. This could potentially be slow if it works for 99% of colors you use, but not for the other 1%.
  2. Including the decimal points in HSLA would ensure the result is not lossy, but since cssnano is using another package for this (colord) we would have to patch this upstream. Then wait for a release and then bump it here.
  3. Move the colormin to the advanced preset and remove it from the default preset.

Or is there another option you would prefer? Once we agree on a solution, I'll provide a PR to fix the issue. Thanks!

@ludofischer
Copy link
Collaborator

The best would be to send a PR to colord. A likely fix might be voiding to round on this line: https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colord.ts#L89

@ludofischer ludofischer removed the triage label Oct 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants