Skip to content

Interoperable font metrics via explicit font metrics overrides #4792

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

Closed
litherum opened this issue Feb 19, 2020 · 43 comments
Closed

Interoperable font metrics via explicit font metrics overrides #4792

litherum opened this issue Feb 19, 2020 · 43 comments

Comments

@litherum
Copy link
Contributor

litherum commented Feb 19, 2020

Migrated from #2228 (comment)

In font files, there exist at least three different ascent/descent values:

  • ascender and descender from the hhea table
  • sTypoAscender and sTypoDescender from the OS/2 table
  • usWinAscent and usWinDescent from the OS/2 table
  • maybe others???

Different browsers / OSes use different values. In fact, some even use values that are not present in the font file at all. This leads to content being laid out differently on different browsers / OSes. #2228 is an example of one. There have been others.

There have been efforts to try to introduce "interoperable" metrics into CSS (#3978 is one, #938 is related, there are a few others too), to force browsers to agree on which metrics they use. Many of the existing proposals so far have some downsides:

  • They require browsers to parse font files, rather than relying on special-purpose font parsing libraries (such as CoreText). A tenet of the web platform is that browsers should be able to delegate responsibility to helper libraries.
  • They cause all text to be laid out differently, across every website in the entire web. Such a massive change is too scary from a product development standpoint.
  • Any approach which is opt-in for specific cases causes text metrics to not match throughout the page. This can lead to inconsistent spacing and poor typography / webpage design.

However, interoperable font metrics are desirable for many page authors. Here's a compromise proposal that (I believe) solves all the above problems:

What if we add a new descriptor into @font-face to let the CSS author override the metrics of the font? Something like this:

@font-face {
    font-family: "WebFont";
    src: ...;
    ascent-override: 80%;
    descent-override: 20%;
}

Those percentage values are resolved by multiplying by the font size (em box). Negative values are illegal. The browser doesn't have to parse any font files, all browsers will agree on the resolved value, and all text in all situations drawn with that font will use these values.

There's already precedent for this: the font-feature-values and font-variation-values descriptors in @font-face overrides the defaults present in the font file.

@kojiishi
Copy link
Contributor

Thank you for writing this up! /cc @kojiishi @drott

@emilio
Copy link
Collaborator

emilio commented Feb 19, 2020

/cc @jfkthame

@Crissov
Copy link
Contributor

Crissov commented Feb 19, 2020

The downside of any solution that relies on @font-face is that it does not work for local fonts unless authors reference them with local(), which they hardly do in my experience. Please correct me if Iʼm wrong.

@faceless2
Copy link

(other proposals) cause all text to be laid out differently, across every website in the entire web. Such a massive change is too scary from a product development standpoint.

I suspect not applying this to local (or even generic) fonts might be entirely intentional.

It's a good compromise idea - I still think we need leading-override too, as OpenType has at least hhea.LineGap and OS/2.sTypoLineGap defining this.

There are other metrics to consider. Both x-height and cap-height are both in the OpenType PCLT table, and there are the baselines too (in the BASE table). All of these are stored only in one place in the font, so if this issue is purely about removing ambiguity and not about overriding metrics, then I'm not sure whether overriding these is important.

@tobireif
Copy link

I really appreciate any and all efforts that have the goal of fixing #2228 .

This here ticket wouldn't solve my use-case in a way that's convenient enough - I'd first have to figure out which percentage values to fill in.

A good solution would allow me (and other web developers) to ensure that the described cross-OS-differences won't happen (in modern standards-based browsers) - in a convenient and quick way, eg glyph-positioning: glyph-bounding-box (the exact names are up to you / the W3C 😀)

Chrome on MacOS:
41592189-1b1b8ee4-73bc-11e8-9c21-9ff43ac2167f
Chrome on Windows:
41592204-25a82ae8-73bc-11e8-818d-d64216d9c480

@tobireif
Copy link

They cause all text to be laid out differently, across every website in the entire web. Such a massive
change is too scary from a product development standpoint.

Any solution should be opt-in.

Any approach which is opt-in for specific cases causes text metrics to not match throughout the
page. This can lead to inconsistent spacing and poor typography / webpage design.

That's the responsibility of the web developer. They can apply it to the whole page or only to portions of it - it's up to them. I think that typically the property would be used for eg a large heading and that's it - the rest of the page would be smaller text (where the issue is eg negligible and which might not use the same font as the heading). In any case - it's the responsibility of the web developer to ensure consistent spacing and good typography etc. (That's the exact reason why I had posted #2228 😀 because I was trying to do just that.)

@tobireif
Copy link

tobireif commented Feb 19, 2020

If your proposal is the only/last offer by the W3C for solving the issue(s) described in #2228 , then I guess I should accept it (towards then closing that ticket) - if it solves the issue(s) described in #2228 completely, and although it requires a bit more work than I had wished for.

@khaledhosny
Copy link

One can already override font provided line spacing with CSS line-height and it does not require any font parsing either, what additional benefit one would get from the proposed @font-face overrides?

@jfkthame
Copy link
Contributor

Setting line-height is not sufficent -- within a given line-height, where does the baseline of the text go? This depends on the relative ascent & descent metrics.

@faceless2
Copy link

faceless2 commented Feb 19, 2020

Yes, you can set a specific line-height every time you use that font and get consistent cross-browser results for line-spacing.

But it seems if you're overriding ascender/descender, on which the default value of line-height depends, you might also want to set the default line-height (edit: by setting the leading) as well. It's not necessary, but it will save you specifying line-height everywhere you use the font. If the stylesheet defining the font is being imported by someone not familiar with the modified metrics, this is probably quite important.

@jfkthame
Copy link
Contributor

It seems to me we could reasonably use CSS properties (not just font-face descriptors) here: something like font-ascent, font-descent and font-linegap, all with initial values of auto (meaning the browser derives metrics from the font or from system APIs or whatever), but with authors having the possibility to use percentages (to be resolved based on em size) instead.

normal line height would then be based on the used values of these metrics.

Then it might also be useful to have these as font-face descriptors, which would allow webfonts to override the result of auto, while leaving system fonts to do their normal thing. So authors could choose to take control just for a specific web font (using the descriptors), or to override the browser's auto behavior for arbitrary content in any font (using the properties). All this would be opt-in for authors, so there's no risk to existing content.

An author could then choose to do something like

:root { font-ascent: 80%; font-descent: 20%; font-linegap: 10%; }

and expect to get consistent line-spacing behavior across browsers and platforms -- with the understanding that the result may not be the same as any given browser currently gives by default, but it's entirely under their control.

I suppose the metrics properties (not descriptors) should probably accept absolute lengths, calc expressions, etc. for completeness, although em-based percentages would usually be the most sensible thing to use.

The final piece would be to add a from-font value to each of these properties (distinct from auto), and define exactly what it means in terms of metrics from an OpenType font file; I would suggest the sTypo* values would be the appropriate choice. (This might require browsers to peek into font files, if system APIs don't provide the required metrics, so may be less convenient to implement.)

@tobireif
Copy link

tobireif commented Feb 19, 2020

@khaledhosny wrote:

One can already override font provided line spacing with CSS line-height

line-height:normal does not help, see #2228 (comment)

Chrome on MacOS:
36321604-9e035454-134a-11e8-9537-55405fe412cc

Chrome on Windows:
36321633-b52e3cd4-134a-11e8-8526-cadf5e99e0c6

line-height: 1 does not help either, see #2228 (comment)

@faceless2 wrote:

Yes, you can set a specific line-height every time you use that font and get consistent
cross-browser results for line-spacing.

The issue is not only about line-spacing 😀The issue is shown in the above screenshots. When it appears it appears even for a single line or word, on one OS vs another (more at #2228 ).

@jfkthame wrote:

Setting line-height is not sufficent

True!

@litherum
Copy link
Contributor Author

@jfkthame

The final piece would be to add a from-font value to each of these properties (distinct from auto), and define exactly what it means in terms of metrics from an OpenType font file

I believe this fails the “browsers having to parse font files” test.

@litherum
Copy link
Contributor Author

litherum commented Feb 26, 2020

@jfkthame

It seems to me we could reasonably use CSS properties (not just font-face descriptors) here

Just to make sure I understand, would these properties apply to the block container? Non-inherited? And would they override any/all ascent and descent values for every inline descendent?

@jfkthame
Copy link
Contributor

The final piece would be to add a from-font value to each of these properties (distinct from auto), and define exactly what it means in terms of metrics from an OpenType font file

I believe this fails the “browsers having to parse font files” test.

Yes - I figured you probably wouldn't be keen on this value (though we have from-font for a couple of the text-decoration properties; doesn't that require browsers to parse font files, too?) Anyhow, I see it as an optional part of the overall suggestion; I think it'd be logical to include a from-font value, but it's not required in order for the properties to be useful.

Just to make sure I understand, would these properties apply to the block container? Non-inherited? And would they override any/all ascent and descent values for every inline descendent?

I haven't really thought about how inheritance etc ought to work... the suggestion that an author might write

:root { font-ascent: 80%; font-descent: 20%; font-linegap: 10%; }

was based on the idea that these properties would inherit (as percentages, to be resolved for each element against its used font-size), but maybe that's not the right approach.

Just throwing ideas out, really, and happy to hear ideas on how it would best work (or why it wouldn't).

@drott
Copy link
Collaborator

drott commented Mar 5, 2020

If we allow custom overrides, values, percentages, etc. I'd prefer to not have those placed as descriptors in @font-face but rather as new properties. I'd also be very supportive of a from-font value. I'd be even more supportive of not allowing custom value overrides, but only some form of keyword to indicate: "use sTypo* only" - in which case I'd be okay with having that as a descriptor in the @font-face header.

Background for not placing overrides in @font-face are issues #2531 as well as my proposal in #4358. Placing overrides in @font-face is not supported in Chrome currently and architecturally difficult. We removed font-variant in the spec as an override, and I would be happy if we could remove other overrides there as well.

@litherum if I am not mistaken in skimming through the code, WebKit already has code for parsing several OpenType fields manually (for math table, vertical layout metrics), as well as even for sTypoMetrics (but this may not be used when running on Mac OS). I do understand your preference to have CoreText handle metrics parsing, but wouldn't this be an acceptable case of accessing this data to enable a from-font keyword? Or alternatively, since you work closely with your CoreText colleagues, couldn't they expose the sTypo* metrics for you?

@fantasai
Copy link
Collaborator

@jfkthame I would prefer to discuss properties (rather than @font-face descriptors) in a separate issue, as it has rather different implications and considerations than an @font-face descriptor. Also for the record, I don't think it's a good idea. Where to place the ascent/descent metrics is very font-dependent, and applying numbers fine-tuned to one font to another is liable to cause overlapping text. As for handling line-gaps and switching out how we measure the height of text, that's a css-inline issue, not a font issue, and is being handled there. [ in reply to https://github.com//issues/4792#issuecomment-588341590 ]

@chrishtr
Copy link
Contributor

chrishtr commented Jul 23, 2020

There is another use case that would I think be solved by the proposal in this issue: matching fallback font metrics to emulate a web font, so as to minimize layout shift during page load. See here for one example; this can currently be combined with font face observation script libraries to dynamically update styles to remove the overrides. If we also add a descriptor such as:

letter-spacing-override: 0.1

(which would introduce a 0.1em extra spacing between letters) then we can also solve that use case, and avoid the use of these scripts. Using these scripts effectively is quite difficult since the script would have to be loaded extremely early in the page lifecycle. For that reason I think most sites don't use these libraries, even though they might improve page load UX.

To use these overrides on a fallback font-family, the site would have to wrap it in an @font-face rather than a built-in font.

@litherum
Copy link
Contributor Author

litherum commented Aug 29, 2020

See: #2228 (comment) and #5485

@litherum
Copy link
Contributor Author

litherum commented Sep 2, 2020

@chrishtr There's a issue #450 trying to solve this use case from another angle.

@svgeesus
Copy link
Contributor

I just put up #5521 to add ascent-override, descent-override and line-gap-override to the spec. Could anyone review it?

The PR was reviewed and has been merged. You can see it in the spec here.

Well, now we need WPT tests :)

@xiaochengh
Copy link
Contributor

xiaochengh commented Sep 18, 2020

I guess we also need to modify the JS FontFace interface to include these new descriptors?

https://drafts.csswg.org/css-font-loading-3/#fontface-interface

chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Sep 19, 2020
Following the standardization of @font-face descriptors ascent-override,
descent-override and line-gap-override, this patch uploads the existing
test cases to WPT as test coverage.

This resolves the "Need Testcase (WPT)" label in
w3c/csswg-drafts#4792

Bug: 1098355
Change-Id: Iffadff1fb159e52ca5a0675259381401fbe90c99
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Sep 19, 2020
Following the standardization of @font-face descriptors ascent-override,
descent-override and line-gap-override, this patch uploads the existing
test cases to WPT as test coverage.

This resolves the "Need Testcase (WPT)" label in
w3c/csswg-drafts#4792

Bug: 1098355
Change-Id: Iffadff1fb159e52ca5a0675259381401fbe90c99
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2419585
Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#808665}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Sep 19, 2020
Following the standardization of @font-face descriptors ascent-override,
descent-override and line-gap-override, this patch uploads the existing
test cases to WPT as test coverage.

This resolves the "Need Testcase (WPT)" label in
w3c/csswg-drafts#4792

Bug: 1098355
Change-Id: Iffadff1fb159e52ca5a0675259381401fbe90c99
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2419585
Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#808665}
pull bot pushed a commit to Alan-love/chromium that referenced this issue Sep 19, 2020
Following the standardization of @font-face descriptors ascent-override,
descent-override and line-gap-override, this patch uploads the existing
test cases to WPT as test coverage.

This resolves the "Need Testcase (WPT)" label in
w3c/csswg-drafts#4792

Bug: 1098355
Change-Id: Iffadff1fb159e52ca5a0675259381401fbe90c99
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2419585
Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#808665}
@svgeesus
Copy link
Contributor

I guess we also need to modify the JS FontFace interface to include these new descriptors?

Yes, indeed

@litherum
Copy link
Contributor Author

I guess we also need to modify the JS FontFace interface to include these new descriptors?

Yes, indeed

Does this need a separate WG resolution? I hope not.

@astearns
Copy link
Member

No additional resolution needed. It follows directly from the existing resolution.

@xiaochengh
Copy link
Contributor

Could anyone review #5538? Just a trivial patch adding attributes to FontFace for the overrides.

@yisibl
Copy link
Contributor

yisibl commented Sep 23, 2020

2020-09-23 16_18_47
How to solve the punctuation marks, I tried to use unicode-range to cover the punctuation marks individually, and found that line-gap-override will take effect for the entire font.

Demo: https://codepen.io/yisi/pen/xxVmzOM

advance-override can only control the right width of characters. Is this a bug in Chrome?

@font-face {
  font-family: 'STSongti-SC-Regular-punctuation';
  advance-override: -0.4; 
  src: local(STSongti-SC-Regular);
  unicode-range: U+b7;
}

image

@xiaochengh
Copy link
Contributor

@yisibl Thanks for trying the prototype 😄

moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this issue Sep 23, 2020
…escriptors to WPT, a=testonly

Automatic update from web-platform-tests
Upload tests for font metrics override descriptors to WPT

Following the standardization of @font-face descriptors ascent-override,
descent-override and line-gap-override, this patch uploads the existing
test cases to WPT as test coverage.

This resolves the "Need Testcase (WPT)" label in
w3c/csswg-drafts#4792

Bug: 1098355
Change-Id: Iffadff1fb159e52ca5a0675259381401fbe90c99
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2419585
Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#808665}

--

wpt-commits: fba18cc5e2fb20eb8059b3d26009f4921e61a84b
wpt-pr: 25638
sidvishnoi pushed a commit to sidvishnoi/gecko-webmonetization that referenced this issue Sep 24, 2020
…escriptors to WPT, a=testonly

Automatic update from web-platform-tests
Upload tests for font metrics override descriptors to WPT

Following the standardization of @font-face descriptors ascent-override,
descent-override and line-gap-override, this patch uploads the existing
test cases to WPT as test coverage.

This resolves the "Need Testcase (WPT)" label in
w3c/csswg-drafts#4792

Bug: 1098355
Change-Id: Iffadff1fb159e52ca5a0675259381401fbe90c99
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2419585
Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#808665}

--

wpt-commits: fba18cc5e2fb20eb8059b3d26009f4921e61a84b
wpt-pr: 25638
tabatkins added a commit that referenced this issue Sep 25, 2020
[css-font-loading-3] Add override attributes to FontFace interface following resolution in #4792
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified-and-comments-removed that referenced this issue Sep 28, 2020
…escriptors to WPT, a=testonly

Automatic update from web-platform-tests
Upload tests for font metrics override descriptors to WPT

Following the standardization of font-face descriptors ascent-override,
descent-override and line-gap-override, this patch uploads the existing
test cases to WPT as test coverage.

This resolves the "Need Testcase (WPT)" label in
w3c/csswg-drafts#4792

Bug: 1098355
Change-Id: Iffadff1fb159e52ca5a0675259381401fbe90c99
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2419585
Reviewed-by: Chris Harrelson <chrishtrchromium.org>
Commit-Queue: Xiaocheng Hu <xiaochenghchromium.org>
Cr-Commit-Position: refs/heads/master{#808665}

--

wpt-commits: fba18cc5e2fb20eb8059b3d26009f4921e61a84b
wpt-pr: 25638

UltraBlame original commit: bf45a57ead94d683e460e9a7fd00fcad492f99bb
gecko-dev-updater pushed a commit to marco-c/gecko-dev-comments-removed that referenced this issue Sep 28, 2020
…escriptors to WPT, a=testonly

Automatic update from web-platform-tests
Upload tests for font metrics override descriptors to WPT

Following the standardization of font-face descriptors ascent-override,
descent-override and line-gap-override, this patch uploads the existing
test cases to WPT as test coverage.

This resolves the "Need Testcase (WPT)" label in
w3c/csswg-drafts#4792

Bug: 1098355
Change-Id: Iffadff1fb159e52ca5a0675259381401fbe90c99
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2419585
Reviewed-by: Chris Harrelson <chrishtrchromium.org>
Commit-Queue: Xiaocheng Hu <xiaochenghchromium.org>
Cr-Commit-Position: refs/heads/master{#808665}

--

wpt-commits: fba18cc5e2fb20eb8059b3d26009f4921e61a84b
wpt-pr: 25638

UltraBlame original commit: bf45a57ead94d683e460e9a7fd00fcad492f99bb
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified that referenced this issue Sep 28, 2020
…escriptors to WPT, a=testonly

Automatic update from web-platform-tests
Upload tests for font metrics override descriptors to WPT

Following the standardization of font-face descriptors ascent-override,
descent-override and line-gap-override, this patch uploads the existing
test cases to WPT as test coverage.

This resolves the "Need Testcase (WPT)" label in
w3c/csswg-drafts#4792

Bug: 1098355
Change-Id: Iffadff1fb159e52ca5a0675259381401fbe90c99
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2419585
Reviewed-by: Chris Harrelson <chrishtrchromium.org>
Commit-Queue: Xiaocheng Hu <xiaochenghchromium.org>
Cr-Commit-Position: refs/heads/master{#808665}

--

wpt-commits: fba18cc5e2fb20eb8059b3d26009f4921e61a84b
wpt-pr: 25638

UltraBlame original commit: bf45a57ead94d683e460e9a7fd00fcad492f99bb
@tobireif
Copy link

tobireif commented Jan 8, 2021

@chrishtr
Copy link
Contributor

chrishtr commented Feb 4, 2021

Closing. Further discussion can happen on #126 and #5533.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests