Open tobireif opened 6 years ago
I think we could solve this with a new descriptor inside @font-face that takes a raw number that represents the font ascent (and another one for descent). The raw number would be a multiplier on the used font-size. If present, the browser would use this number instead of whatever is in the font file.
I mostly agree with @litherum in this thread, but I would strictly prefer not have per-@font-face overrides for metrics. Implementing and maintaining such overrides introduces a big maintenance burden and unnecessary implementation cost, I doubt this is the right solution to this problem.
c) Fixing each font:
Currently, the most practical approach to fix this seems to be to edit the font data and synchronize these different platform-specific ascent and descent metrics (e.g. the FontSquirrel's web font generator has the "Auto-Adjust Vertical Metrics" option in the Expert mode, and you can always adjust them manually with a font-editing tool like FontForge as a last resort).
Not efficient. A client pays me to do web dev, not for fixing each font I use. Also, have you looked at the license of commercial web fonts? If I remember correctly, some do not allow any modifications. Oh, and many web developers (unfortunately) insist on having their web fonts hosted eg by Google - in that setup they couldn't fix the fonts either.
If there are technical issues with the fonts, it is possible to contact the vendor and get them fixed. I've seen that process work (one of several examples here). Google Fonts updates the fonts as well if the original source has updates or fixes. A browser-side override is not a reasonable solution to work around fonts with inconsistent metrics.
@tobireif do you have additional examples? With how many fonts are you facing this problem?
do you have additional examples? With how many fonts are you facing this problem?
With way too many. It's an issue in almost every project where large text is part of the design. (I always do testing across operating systems, devices, and browsers.)
A test-page using the font Hetilica: https://tobireif.com/non_site_stuff/test_case_for_font_position_report_yet_another_font/
A test-page using the popular font Frankfurter: https://tobireif.com/non_site_stuff/test_case_for_font_position_report/
Other fonts where the issue occurs include Ruritania, QuigleyWiggly, Scratch, and BigFish. See the code at https://github.com/w3c/csswg-drafts/issues/2228#issuecomment-366312842 . Each word "#svg" etc uses a different one of the above fonts. There were text-layout issues across operating systems and across browsers.
And there are several StackOverflow pages which most likely are the tip of the iceberg.
I would strictly prefer not have per-@font-face overrides for metrics. Implementing and maintaining such overrides introduces a big maintenance burden and unnecessary implementation cost, I doubt this is the right solution to this problem.
I agree! They'd mean way too much work for the web developer, and for implementers.
All I want is being able to opt into the same text-layout that browsers use for SVG text, for example
text-layout: glyph-bounding-box;
This line would set the same text positioning that browsers use for SVG.
One line of CSS to type for the web developer, and for implementers it probably wouldn't be a lot of work because that text-layout has already been implemented for SVG text.
And it wouldn't break any existing websites because it'd be opt in (via the new property).
If there are technical issues with the fonts, it is possible to contact the vendor and get them fixed.
Typical project deadlines don't leave time for requesting, awaiting, and hoping for a fix - for each used font. And some type foundries might never reply. And the license might not allow me to fix it.
A browser-side override is not a reasonable solution to work around fonts with inconsistent metrics.
The sad truth is that it's a widespread issue, and fixing each font is not feasible, thus a solution is required. Some designs feature many fonts. In one design (one single page) I had to compensate the text-layout for five(!) fonts (see the example in https://github.com/w3c/csswg-drafts/issues/2228#issuecomment-366312842 ). I'd much prefer it if every font would work well cross-platform, but alas that is not the case.
All I want is being able to opt into the same text-layout that browsers use for SVG text, eg
glyph-positioning: as-for-svg;
or eg
text-layout: glyph-bounding-box;
Having such a property would mean that we could opt into text layout that's consistent across platforms without having to replace the HTML text with SVG text, without having to wait for font creators to fix each and every used font, and without having to compensate for the differences by applying OS-specific spacing. Instead we could opt into an already-implemented text-layout option where the glyphs stay in the same position across platforms.
Wonder if https://github.com/w3c/csswg-drafts/issues/3240 could/would be used to also solve this per os issue?
Wonder if #3240 could/would be used to also solve this per os issue?
Yes, that is the intention.
Any solution would be a big step forward for text in layout on the web! Keep us updated 😀
Or perhaps glyph-spacing: bounding-box
All I want is being able to opt into the same text-layout that browsers use for SVG text
@tobireif you do realize that SVG text rendering is not the same thing as browser-based text rendering, right? They each have different features, advantages, and drawbacks.
Your desire for browsers to "just be able to use SVG logic for non-SVG content" is a bit like asking for a car that could just use the same propellor as your boat.
BTW it's almost surreal that the following article was published the very day I came across this issue.
https://product.voxmedia.com/2019/6/17/18524029/the-ballad-of-drop-caps-and-design-systems
I need consistent positioning of large and medium-sized text across operating systems.
Regarding the article: It compares the rendering across browsers, not across operating systems. Their fix line-height: 1
does not fix the issue across OSs (eg https://tobireif.com/non_site_stuff/test_case_for_font_position_report_yet_another_font/ in Chrome on Mac vs Windows).
The issue is shown in the top post on this page here -> see the image below "Chrome on MacOS" vs "Chrome on Windows".
General info: Related tickets with recent activity:
I hope that this issue will get resolved soon.
It would be great if this could get added to the agenda.
I opened https://github.com/w3c/csswg-drafts/issues/4792 with the proposal I made in https://github.com/w3c/csswg-drafts/issues/2228#issuecomment-380762748
I finally got around to doing some proper testing. Here's what I believe is the algorithm for extracting ascent, descent and line-gap from OpenType fonts across several browsers:
int ems = post.ems; // 1000, 2048 etc
boolean usetypo = (os2.fsSelector & 128) != 0; // USE_TYPO_METRICS
int ascent; // distance from text-top to baseline; positive
int descent; // distance from text-bottom to baseline; negative
int linegap; // add to ascent and -descent to get default line-height
if (safari_on_mac || chrome_on_mac || safari_on_ipad || chrome_on_ipad) {
ascent = hhea.ascent;
descent = hhea.descent;
linegap = hhea.linegap;
} else if (firefox_on_mac || chrome_on_linux || chrome_on_android || edge_on_android || samsung_on_android || prince || bfo) {
ascent = usetypo ? os2.sTypoAscender : hhea.ascent;
descent = usetypo ? os2.sTypoDescender: hhea.descent;
linegap = usetypo ? os2.sTypoLineGap : hhea.linegap;
} else if (firefox_on_linux || firefox_on_android) {
ascent = usetypo ? os2.sTypoAscender : hhea.ascent;
descent = usetypo ? os2.sTypoDescender: hhea.descent;
linegap = os2.sTypoLineGap;
} else if (chrome_on_windows || firefox_on_windows || edge_on_windows || ie11) {
ascent = usetypo ? os2.sTypoAscender : os2.usWinAscent;
descent = usetypo ? os2.sTypoAscender : -os2.usWinDescent;
linegap = usetypo ? os2.sTypoLineGap : hhea.linegap; // note ie11 puts all linegap after line.
}
if (firefox) {
if (linegap == 0 && ascent - descent <= ems) {
if (usetypo || !firefox_on_android) { // apparently, according to crossbrowsertesting.org
linegap = ems * 1.2 - ascent + descent; // line-height always 1.2em
}
} else if (ascent - descent < ems) {
linegap += ems - ascent + descent;
}
}
I'd hoped to show exhaustive working in one place, but the testing got a bit out of hand and there are just too many combinations! Plus some of this I'd already established so didn't need to retest. I didn't test anything really weird (e.g. -ve ascents) and I haven't fully confirmed the firefox "fix up the line-gap" algorithm is the same on all platforms. So there's undoubtedly more to this, but I think it's pretty close.
(Edit: updated to add prince, our renderer, and some other results according to http://crossbrowsertesting.org)
I've made a hopefully coherent demonstration of this at https://bfo.com/misc/metrics/ - it doesn't demonstrate the firefox "fix-up the line gap" algorithm, but does show the special handling when linegap==0
Fwiw, Gecko's normal computation is in GetNormalLineHeight
Aha! Thank you @fantasai. So the "fix up the line gap" constant is NORMAL_LINE_HEIGHT_FACTOR
Finally there's a great solution for the issue where browsers display large text at different vertical positions across operating systems: font metrics overriding.
Check out my post: https://tobireif.com/posts/ensuring_the_correct_vertical_position_of_large_text/
I'm leaving this ticket open, because having eg text-layout: glyph-bounding-box
would mean we'd have a solution that doesn't require the web developer to figure out property values / percentages.
I need consistent positioning of large and medium-sized text across operating systems.
The large text on the page https://tobireif.com/non_site_stuff/test_case_for_font_position_report/ gets positioned differently eg in Chrome on Mac vs in Chrome on Windows:
The space above the large text is 102px in Chrome on Mac vs 125px in Chrome on Windows.
The space below the large text is 75px in Chrome on Mac vs 52px in Chrome on Windows.
Another test-page: https://tobireif.com/non_site_stuff/test_case_for_font_position_report_yet_another_font/
From the above test-page:
Chrome on MacOS:
Chrome on Windows:
The large-text positioning / the space above and below the large text should be the same across operating platforms, for this font and for all fonts where the effective position currently is different across operating systems.
In order to not break existing content there needs to be a new CSS property, eg
position-of-glyphs: consistent-across-platforms;
or egtext-layout: glyph-bounding-box;
(The latter would set the same text positioning that browsers use for SVG.)There are many other pages/sites/layouts where medium/large text and its position is important.
I need a way to ensure the same vertical text position across platforms.
The alternatives are not great:
a) Applying spacing:
eg
This is a hack.
b) Fixing each problematic font:
This is not always feasible: There might be no time to do this, many web devs use fonts hosted by external services, and thirdly the font license might not allow any modifications.
c) Using SVG text instead of HTML text:
Replacing each respective text with SVG has major drawbacks: Some might fear that it might impact eg search engine visibility. Imagine a newspaper considering to use SVG for its headlines while search engines handle h1/h2/etc well - they probably wouldn't take that risk. And it might also impact accessibility, see https://www.google.com/search?q=svg+text+screen+readers . It's a potential issue as far as I can see (eg in a given specific screen reader), while HTML text can be expected to just work. Also, SVG is meant for graphics (which might contain text or not) - a pure text page (eg an article) coded in HTML shouldn't have to use SVG just to get consistent cross-OS text-layout (for its large text instances).
Thus it would be great if consistent cross-OS text-layout would be available in HTML as well (not just in SVG as is currently the case).
I hope that CSS will support opting into the glyph-bounding-box-based layout (which browsers already have implemented for SVG) as option for (typically large) HTML text.
eg
h1 {text-layout: glyph-bounding-box}
orh1 {glyph-positioning: glyph-bounding-box}
(The exact names for the property and value could be different.)That would solve the issue completely.