parcel-bundler / lightningcss

An extremely fast CSS parser, transformer, bundler, and minifier written in Rust.
https://lightningcss.dev
Mozilla Public License 2.0
6.47k stars 188 forks source link

Lightning CSS doesn't escape `content: "\..."` #310

Open ghost opened 2 years ago

ghost commented 2 years ago

We have @charset "UTF-8"; in our CSS which Lightning CSS is skipping when bunding/minifying the styles. Without it, it's possible to encounter issues with displaying unicode like in https://github.com/parcel-bundler/lightningcss/issues/164. There are other ways to insert the character encoding like HTTP headers and the HTML but this is not possible for people in some use cases.

Is it possible to respect the @charset rule?

I've also prepared a Playground link demonstrating the issue.

ghost commented 2 years ago

At least from my understanding, this conversion of the Unicode is due to the missing @charset but I may be mistaken. It would be great if we could respect the Unicode.

devongovett commented 2 years ago

UTF-8 is the default character set for CSS, so I don't think this is necessary?

ghost commented 2 years ago

UTF-8 is the default character set for CSS, so I don't think this is necessary?

I might be misunderstanding the problem then but isn't this causing the change from content:"\f67f" to content: "";?

devongovett commented 2 years ago

Escaping isn't necessary since the output is utf8.

ghost commented 2 years ago

Something must be going on because the content doesn't always render correctly: image image And I've only managed to trace it to this difference in the CSS. If I minify the CSS with SWC, it escapes the content and I can't reproduce the rendering issue. But that product is not mature enough in my opinion.

neoGeneva commented 2 years ago

This is something I've encountered too. I'm currently unsure what causes Chrome to suddenly think that the CSS file isn't UTF-8, but I have a hunch that it's something to do with devtools.

There's a discussion over in the Font Awesome repo about a similar issue: https://github.com/FortAwesome/Font-Awesome/issues/17644 The consensus there seems that @charset "UTF-8"; doesn't always solve the issue, so it would be good if Lighning CSS left characters in their encoded form or had an option to toggle it.

ghost commented 2 years ago

This is something I've encountered too. I'm currently unsure what causes Chrome to suddenly think that the CSS file isn't UTF-8, but I have a hunch that it's something to do with devtools.

There's a discussion over in the Font Awesome repo about a similar issue: FortAwesome/Font-Awesome#17644 The consensus there seems that @charset "UTF-8"; doesn't always solve the issue, so it would be good if Lighning CSS left characters in their encoded form or had an option to toggle it.

Our QA also managed to narrow it down to having DevTools open and refreshing the page. The surest way of avoiding this that I've found is avoiding escaping content:"\f67f" to content: ""; but Lightning is not giving us an option to do that. Hopefully, with this issue, they will consider it.

rkumorek commented 1 year ago

We've had the same issue recently with migrated sites that were still using font icons. Had to revert back to nanocss for the time being as clients reported issues with icons.

Same thing: content:"\f67f" becomes content: "" (square bracket) which seems not to work on some browsers... for some clients... sometimes.

devongovett commented 1 year ago

See https://developer.mozilla.org/en-US/docs/Web/CSS/@charset for the rules of how a charset is chosen by browsers when loading a CSS file. The problem could be that you are setting a non-UTF8 charset as part of the Content-Type HTTP header, as that would override other methods such as @charset. You could also prepend a @charset rule to the file, but this is usually unnecessary because if no other value is overriding it, the default is UTF-8.

domenkozar commented 1 year ago

I've hacked around parcel bug to include @charset "UTF-8" at the beginning of the main.css, but it still sometimes just renders it in correctly. Opening the debugging tools triggers the bug almost always.

devongovett commented 1 year ago

Honestly this sounds like a chrome dev tools bug? Has anyone filed an issue there?

woody-li commented 1 year ago

Met the same issue. Font icon content converted as unicode "box" char, and con't be resolved by dynamic font. Is it posibile to provide a option for convert unicode or not?

nclemeur commented 1 year ago

I have also seen this problem, and I would also greatly appreciate if this behavior could be made optional...

dbt-padberg commented 1 year ago

I can confirm this issue. For me it's the same using vite==4.4.9 (depends on lightningcss^1.21.5) in combination with @mdi/font==7.2.96

musosoft commented 10 months ago

In the Lightning CSS documentation, it states:

Lightning CSS does not do this – the output CSS should always behave identically to the input. Keep this in mind when comparing file sizes between tools.

However, this doesn't seem to be true for projects using font icons. Lightning CSS converts all Unicode escapes into direct Unicode characters. Browsers can't render these.

To address this, I suggest you to implement a feature that will compare characters against a list of most common used UTF-8 characters and encode only those that match.

As this issue is still open for over a year now, I'm moving back to PostCSS. Hopefully, it could be resolved soon as this is an incredible project that suits all CSS needs nowadays.

Fedik commented 8 months ago

Would be good to have an option to keep the content value unchanged. Currently

let { code } = transform({
  code: Buffer.from(`
    .foo:before {
      content: "\\31";
    }
    .bar:before {
      content: "\\e4c2";
    }
  `),
});

Produce:

.foo:before {
  content: "1";
}
.bar:before {
  content: "";
}

But I expect that it keep the original value

monochromer commented 2 months ago

The problem could be that you are setting a non-UTF8 charset as part of the Content-Type HTTP header

Some cloud providers do not provide the ability to modify HTTP headers.

amirsarfarW commented 2 months ago

Would be good to have an option to keep the content value unchanged. Currently

let { code } = transform({
  code: Buffer.from(`
    .foo:before {
      content: "\\31";
    }
    .bar:before {
      content: "\\e4c2";
    }
  `),
});

Produce:

.foo:before {
  content: "1";
}
.bar:before {
  content: "";
}

But I expect that it keep the original value

I have the same issue

Is this gonna be fixed or not?