[csswg-drafts] [css-inline-3] Baseline alignment of text (#5647)

litherum has just created a new issue for https://github.com/w3c/csswg-drafts:

== [css-inline-3] Baseline alignment of text ==
There are two problems with baseline alignment for text as it is currently specified by CSS. As far as I know, text baseline alignment is unimplemented in any browser, so we have an opportunity now to try to improve it.

# Problem 1: It doesn't do anything by default

Consider this content:

```
@font-face {
    font-family: "A";
    src: local("Shobhika-Regular");
}
@font-face {
    font-family: "B";
    src: local("Mukta-Medium");
}
...
<div style="font-size: 192px;"><span style="font-family: 'B';">&#x0939;&#x093f;</span><span style="font-family: 'A';">&#x0928;&#x094d;&#x0926;&#x0940;</span></div>
```

Here is what it looks like in all browsers:

<img width="419" alt="Screen Shot 2020-10-22 at 2 43 30 AM" src="https://user-images.githubusercontent.com/918903/96854489-64e9ac80-1410-11eb-8023-1ea8d7686520.png">

As you can see, the horizontal line is broken vertically. The reason for this is the two fonts have different metrics. Browsers align to the alphabetic baseline, which for Hindi, leads to unfortunate things like this.

Here is what it looks like when rendered with Core Text using baseline alignment (you can see the ascent and descent of the two fonts):

<img width="837" alt="Screen Shot 2020-10-22 at 1 39 51 AM" src="https://user-images.githubusercontent.com/918903/96854511-6d41e780-1410-11eb-90bd-78d3fab50bc2.png">

The CSS spec should allow for this kind of automatic baseline selection (and alignment).

There are two sources of information that are used in practice today to do this automatic selection: 1. Script tables, mapping each script to a particular baseline, and 2. The [bsln table](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6bsln.html) in AAT fonts can annotate particular glyphs as preferring particular baselines.

# Problem 2: It's too easy to get characters floating in the middle of nowhere

The current spec [says](https://drafts.csswg.org/css-inline-3/#alignment) "each ... inline-level box is aligned in the block axis by positioning its alignment baseline to match the corresponding baseline of its parent."

Then, we have the [`alignment-baseline`](https://drafts.csswg.org/css-inline-3/#propdef-alignment-baseline) property, which sets the alignment baseline, but isn't inherited. Also, we have the [`dominant-baseline`](https://drafts.csswg.org/css-inline-3/#propdef-dominant-baseline), which _is_ inherited, but doesn't actually align anything - it just sets the initial value of the `alignment-baseline` property.

If an author wants to change the baseline for some text (which is a fairly straightforward operation in text editing applications), the most natural thing for them to do would be to just set `alignment-baseline` on an ancestor span of the text they want to align. However, that won't be right, because that aligns _the inline box_ of the span to _the span's_ parent, and the glyphs just end up wherever that shift happens to take them. In particular, the alignment of the glyphs relative to that span is unchanged. Therefore, you'll get glyphs aligned to baseline A of the span, the span aligned to baseline B of its parent, and its parent aligned to baseline A of the block. The end result is the glyphs will be floating in the middle of nowhere.

The author can't just set `dominant-baseline` either, since that doesn't actually align the element it's specified on. If they want to do it right, they have to do mental gymnastics and specify both properties on the span. This isn't great.

The underlying problem here is that, according to the CSS spec, each glyph and inline-level box is baseline aligned to its parent, all the way up the tree, which means there are tons of micro-adjustments that happen between deeply nested glyphs and the line box.

### Research

I wanted to understand how the baseline alignment operation works in successful shipping text engines. I interviewed 4 different teams from 3 different companies about this topic. Of those 4 teams, only 2 did any kind of baseline alignment for text that I'm discussing here.

In both of those text engines, there is a reference baseline set that is set for the line that _doesn't_ move, and there's another baseline set attached to glyphs that _does_ move. The alignment moves the glyphs to match one baseline from their baseline set to the corresponding baseline from the reference baseline set.

Neither of these engines represents the line as a hierarchy like the DOM, and therefore neither of these engines does the same kind of series of micro-adjustments that the CSS spec currently prescribes. The baseline alignment operation moves glyphs so they line up coincident with the reference baseline.

In both of these engines, glyphs always end up coincident with the reference baseline, even if the user makes some of the glyphs bold, or selects a different font for some of the glyphs, or some of the glyphs are rendered with a fallback font. You never get glyphs floating in the middle of nowhere. In fact, in both of these engines, it's _impossible_* to do nested alignment, where one thing aligns to something else on the line, which then aligns to the reference baseline.

In both engines, this kind of text baseline alignment didn't increase the line height or grow the size of the paragraph. It just affected visual placement of glyphs, and didn't affect the paragraph's or line's layout geometry at all.

Also, both of the engines allowed the user to select (or override) which baseline from the set is the one that is the active baseline.

# Proposal

### Requirements

1. This alignment should be enabled by default, and is script-aware.

2. With the application of a single property, authors should be able to override the default choice of which baseline gets aligned, and the alignment is between the glyphs and the line (and not intermediate inline-level boxes).

3. It should be _possible_, but not the default, to do nested alignment like the current spec describes. The DOM is a big hierarchy, and requiring punching through every level for all glyphs is probably too strong.

### Proposal
Add a new kind of context, which is identified by an element. Within a context (e.g. descendants of the element), leaves of the tree (e.g. glyphs) are aligned to the baseline set of the context (_not_ to their direct parents). The context element represents the "reference" baseline set described above.

1. Add a new property:
```
Baseline-context: from-font | from-parent | none
Initial: from-parent
Inherited: no
```
This property creates a new reference baseline set.
- `from-parent` does not create a new reference baseline set
- `from-font` creates a new reference baseline set coincident with the baseline-set of the font used on the element
- `none` disables baseline alignment for descendants.

This probably won't be the _only_ way to create reference baselines. For example, blocks probably would create their own reference baselines, even if they don't have this property set on them. Even within a single line, I can imagine wanting something like `font-size: 200%` to automatically create new reference baselines. We'd have to figure out if we want a heuristic, and if so, how smart/dumb it should be.

2. Modify `alignment-baseline`
```
alignment-baseline: auto | text-bottom | alphabetic | ideographic | middle | central | etc.
Initial: auto
Inherited: Yes
```
This property tells the leaves of the tree which alignment baseline to align to the reference baseline. "Auto" means "the UA will look at the script of the character, possibly the `lang` attribute, and the font being used and come up with a best guess about which baseline from the set to align.

There is some compat risk here, since `alignment-baseline` is already implemented for SVG content. However, I believe if we modify it to work as in this proposal, the behavior change (of making it inherited and cause glyphs to be positioned correctly instead of just shifting inline-level boxes) would be a progression. But that's just my intuition.

3. Delete `dominant-baseline`

# Conclusion

We can improve the baseline alignment for text that the CSS spec uses. This proposal represents a general direction, and probably has some things to iron out before it's ready to go. I'm interested in the WG's (indeed; everyone's) feedback of this direction of baseline alignment of text.

* for some definition of "impossible"

Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/5647 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Thursday, 22 October 2020 09:55:06 UTC