Bug 300620
| Summary: | REGRESSION (Safari 26): `@font-face` / `FontFace.family` fails when font family name contains space (e.g. "Lato 2") | ||
|---|---|---|---|
| Product: | WebKit | Reporter: | snandhu361 |
| Component: | CSS | Assignee: | Darin Adler <darin> |
| Status: | RESOLVED FIXED | ||
| Severity: | Major | CC: | darin, fantasai.bugs, koivisto, ntim, sam, simon.fraser, vitor.roriz, webkit-bug-importer |
| Priority: | P1 | Keywords: | InRadar |
| Version: | Safari 26 | ||
| Hardware: | Mac (Apple Silicon) | ||
| OS: | macOS 26 | ||
| See Also: | https://bugs.webkit.org/show_bug.cgi?id=196381 | ||
snandhu361
Description:
After the recent Safari update, when creating a FontFace object with a family name containing a space (for example "Lato 2"), the FontFace.family property now returns a quoted value ("\"Lato 2\"").
This issue did not occur in previous Safari versions — it previously returned the expected unquoted string ("Lato 2").
This regression affects applications that rely on the unquoted family name for caching or mapping logic.
Steps to Reproduce:
const font = new FontFace("Lato 2", "url('Lato2.woff2')");
console.log(font.family);
Observed Result (Safari 18+):
"\"Lato 2\""
Expected Result (previous behavior / other browsers):
"Lato 2"
Context:
My application implements a delayed font loading mechanism.
After each font is rendered, a div is dynamically created, and a key map is maintained to reuse fonts by their family names.
Example:
fontMap.set("Lato 2", fontFace);
After Safari’s recent change, fontFace.family returns "\"Lato 2\"", which causes the key map lookup to fail, breaking the delayed loading logic.
Expected Behavior:
Safari should preserve the original unquoted font-family name (e.g. "Lato 2") when accessed through FontFace.family.
Actual Behavior:
Safari now returns a quoted value ("\"Lato 2\""), leading to incorrect string comparison and logic errors.
Additional Notes:
The font itself renders correctly on the page.
The issue only appears in JavaScript when inspecting the FontFace.family property.
Chrome and Firefox continue to return the expected unquoted string.
The regression likely stems from the recent spec compliance fix (142009630), which restricted @font-face descriptors to a single value.
| Attachments | ||
|---|---|---|
| Add attachment proposed patch, testcase, etc. |
Darin Adler
Is the "app" mentioned here a website, or an iOS app, or something else?
If it’s a website, then some things to figure out:
- Is this a request for different behavior in Safari than other web browsers?
- If not, is this important interoperability concern already covered by a Web Platform Test?
- Is the specification wrong, or was this a mistake made in passing while implementing the specification not required by the specification?
If it’s an iOS app maybe we need a compatibility hack of some sort for older apps.
snandhu361
Hi, thanks for the quick response.
This issue occurs in a web application (website) — not an iOS app.
To answer your questions:
It’s not a request for different behavior from other browsers.
In fact, Chrome and Firefox both still return the unquoted family name (e.g., "Lato 2") for FontFace.family.
Safari used to behave the same until the recent change (142009630).
It appears to be a regression / interoperability issue — Safari now returns "\"Lato 2\"", which causes cross-browser inconsistency.
As per the CSS Font Loading specification, the FontFace.family attribute should reflect the font’s family name as a simple string — not a quoted version.
So this seems to be a small parsing or serialization error introduced by the spec compliance fix, rather than a spec requirement.
Radar WebKit Bug Importer
<rdar://problem/162637501>
Darin Adler
I’ll try to look at this myself when I have a chance, but I’m hoping someone else gets to it first.
We should add a Web Platform Test for this!
Radar WebKit Bug Importer
<rdar://problem/162637585>
Darin Adler
While waiting for this to be fixed, or for compatibility with the versions of Safari already in use with this bug, any website running into this should have a simple workaround: assuming we don’t need compatibility with font names that happen to start with a quotation mark, we can write simple JavaScript code to strip the quotes after getting the value of the family attribute.
snandhu361
Thanks for confirming and for the suggested workaround.
I’ve implemented a simple normalization step to strip quotes from FontFace.family values, which resolves the issue for now.
It’d be great if future Safari versions align with Chrome/Firefox behavior, so the workaround isn’t needed long-term.
Alexey Proskuryakov
<rdar://problem/162637501>
Tim Nguyen (:ntim)
Easy steps to reproduce:
1. visit wpt.live
2. run this in the console:
```
font = new FontFace("IcTestFullWidth Bold", "url('https://wpt.live/css/css-values/resources/IcTestFullWidth.woff2')");
font.load().then(() => {
console.log(font.family);
});
```
Tim Nguyen (:ntim)
Using serializeIdentifier here: https://searchfox.org/wubkat/rev/7c3fea2e73edc7d7c5373dda8f22bf2c44b1293e/Source/WebCore/css/CSSMarkup.cpp#146-149 would probably fix the issue, but it would affect more than just descriptor (also the font-family CSS property).
Tim Nguyen (:ntim)
The entry point of this code is `parseFontFaceFontFamily`
Darin Adler
I suspect we want to change the result of the family method of CSSFontFace to not be quoted have the font-family CSS property continue to return a list of quoted strings. Need to check the relevant CSS specifications to see where that’s made clear.
To do that we would need to change the body of the CSSFontFace::family function to not call getPropertyValue(CSSPropertyFontFamily).
Darin Adler
It might mean we also want to change the behavior of setting family on CSSFontFace. That function, CSSFontFace::setFamily currently takes a list of quoted family names.
Darin Adler
One note is that the font-family descriptor in a @font-face from is a <family-name> <https://www.w3.org/TR/css-fonts-4/#descdef-font-face-font-family>, whereas the font-family CSS property from CSS style from the CSS Fonts Module is a [ <family-name> | <generic-family> ]#. <https://www.w3.org/TR/css-fonts-4/#propdef-font-family>.
But <family-name> is <string> | <custom-ident>+.
I can’t find a place where it’s specified when <family-name> should serialized as a <string> and when it should be serialized as <custom-ident>+.
Darin Adler
For authors, the CSS Fonts Module says "to avoid mistakes in escaping, it is recommended to quote font family names that contain white space, digits, or punctuation characters other than hyphens" and "if you really have a font whose name is the same as one of the <generic-family> names, or the system font names, or the CSS-wide keywords, it must be quoted". I could imagine turning these author rules into a serialization rule to determine when to serialize a family name as a string and when to serialize them as an identifier. It’s really unclear what specification rule prevents the use of a quoted string when serializing!
Tim Nguyen (:ntim)
Here are some testcases: https://jsfiddle.net/ntim/q7t81jgh/
Firefox seems to have the most sensible behavior, from Elika's words:
- Adds quotes around names that are also keywords.
- Doesn't add quotes for spaces.
- Only adds quotes for numbers if they're at the start of a word (basically stuff would otherwise parse as a dimension).
- Adds quotes for punctuation.
fantasai
Nah, actually, I confused myself. Firefox is tracking whether the author specified quotes or not, and serializing to match.
I think either of these approaches would work, fwiw.
Darin Adler
Not to be a broken record, but I’d really like to specify this and test it in WPT rather than just choosing what WebKit will do.
fantasai
So the question of how to serialize font-family values is https://github.com/w3c/csswg-drafts/issues/5846
However that doesn't help with values like "Lato 2" which is not valid as a font-family value (whether as a property value or as a descriptor value) unless it's unquoted or unescaped.
The issue here is about the FontFace.family API, which is defined here:
https://drafts.csswg.org/css-font-loading/#dom-fontface-family
We previously had interop on returning just bare strings here -- which is reasonable, because the font-family *descriptor*, unlike the font-family *property*, never has any value that isn't fundamentally just a string. (It doesn't accept generic family keywords.) Given previous interop, and this evidence that changes are likely not Web-compatible, and the fact that it's a pretty reasonable behavior to have in the first place for this API, I think we should revert WebKit's behavior and ask the spec to match implementations here.
Darin Adler
(In reply to fantasai from comment #19)
> The issue here is about the FontFace.family API, which is defined here:
> https://drafts.csswg.org/css-font-loading/#dom-fontface-family
> We previously had interop on returning just bare strings here -- which is
> reasonable, because the font-family *descriptor*, unlike the font-family
> *property*, never has any value that isn't fundamentally just a string. (It
> doesn't accept generic family keywords.) Given previous interop, and this
> evidence that changes are likely not Web-compatible, and the fact that it's
> a pretty reasonable behavior to have in the first place for this API, I
> think we should revert WebKit's behavior and ask the spec to match
> implementations here.
One confusing thing about FontFace.family and the CSS specifications is that the specification says "parsed the same as the corresponding @font-face descriptors". I don’t fully understand the implications of that, but it doesn’t seem entirely consistent with “just a string”.
Darin Adler
To implement “just a string” in WebKit without changing anything outside FontFace I would probably change the getter and setter implementation for the family property of FontFace and I’d want to add some tests for both the getter and setter in WPT.
This wouldn’t change the behavior of @font-face parsing or have any effect on serialization of the font-family property or of the font-family descriptor if serialized as part of @font-face.
fantasai
> I don’t fully understand the implications of that, but it doesn’t seem entirely consistent with “just a string”.
Yeah, that's why I was saying we should ask the spec to change to match implementations here.
@snandhu361 You mentioned @font-face in the title, but not in the steps to reproduce. What exactly is the problem with @font-face?
Darin Adler
Pull request: https://github.com/WebKit/WebKit/pull/52623
EWS
Committed 301793@main (3208096991b9): <https://commits.webkit.org/301793@main>
Reviewed commits have been landed. Closing PR #52623 and removing active labels.
EWS
Committed 301765.28@safari-7623-branch (bf7a790fd42c): <https://commits.webkit.org/301765.28@safari-7623-branch>
Reviewed commits have been landed. Closing PR #3807 and removing active labels.