Skip to content
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

[css-inline] vertically align to nth-child #1339

Open
dauwhe opened this issue May 9, 2017 · 14 comments
Open

[css-inline] vertically align to nth-child #1339

dauwhe opened this issue May 9, 2017 · 14 comments

Comments

@dauwhe
Copy link
Contributor

dauwhe commented May 9, 2017

In math and likely other contexts, you may have a stack of inline elements, but need to align the surrounding text to the baseline of one particular element in the stack. An example and proposal are at https://codepen.io/pkra/pen/JWbPzZ

How might CSS handle such situations?

@dauwhe dauwhe added the css-inline-3 Current Work label May 9, 2017
@pkra
Copy link
Member

pkra commented May 9, 2017

Thanks for posting this here, Dave.

For context, this question originated in the Math-on-web CG.

@tabatkins
Copy link
Member

Usually, rather than explicitly indicating an element in a property, we invert control and have the target indicate that it's the one to be used (and when necessary, have some sort of tie-breaker for ambiguous situations). So in this case, we'd do something like have a property to indicate that the element has a specially-computed baseline, and another property on the appropriate descendant that it's the one that computes the baseline for its nearest baseline-container.

In your particular example, which element would be contributing the baseline? I think it's the bar, contributing a central baseline?

@pkra
Copy link
Member

pkra commented Jun 14, 2017

Thanks so much for your response, @tabatkins. I'm sorry for the long delay. I wanted to get some feedback from other CG members but I had to skip two meetings.

To add some comments from mainly a MathJax point of view.

What you describe would work out well from our point of view, i.e., to have something that marks a container whose baseline will be determined by one of its children, together with a mark on the child that is the one to use for the baseline.

The answer to your question would be yes: in the fraction example, the item to use for the baseline would have to be the fraction line, as suggested.

Another important case is the one for under-over constructions, e.g., a sum with limits on top and bottom (e.g., the Cauchy-Schwartz equation). In that case, we would need to be able to use the middle element for its baseline.

To add some context beyond the simple case (though I realize that I risk causing confusion so please feel free to disregard the rest).

Another case to consider is the situation, where a large, stretchy delimiter (parenthesis, brace etc) is placed around a (large) expression (again, e.g., Cauchy-Schwartz). Here, we would want the baseline to be that of the middle piece not whatever construct is needed for the left and right delimiter (we would also want them to be centered on the math axis which is about .25em above the baseline but that's perhaps another topic). We don't know how to do that without knowing the actual height of the delimiters, defeating the purpose of having automatically stretchy constructions (which is actually doable nowadays). It would be great to be able to make a box containing the left delimiter, the main content, the right delimiter (say a flex-box with the left and right pieces stretching to the height and depth of the container), and have the container use the baseline of the middle piece (ignoring the others).

A different example is a horizontal shift to the top and bottom so that they can be centered, but shifted. This is needed to handle italic correction, like for an integral sign where the limits are placed above and below: they should be centered, but not directly over the integral; the top is shifted to the right, while the bottom is shifted to the left. The bounding box of the entire expression needs to take these shiftings into account properly. I haven't been able to work out a decent way to handle that without knowing the exact widths of the three pieces.

Anyway, this is just to point out that a vertical stack is not the only time that being able to specify whose baseline to use would be a valuable asset.

@tabatkins
Copy link
Member

Yeah, all those seem compatible with the "container says it has a special baseline, some descendant marks itself as the baseline-provider". You already have to search arbitrarily far down the tree of descendants to find something that can contribute a baseline.

@fantasai, as an editor of the relevant spec, any thoughts?

@fantasai
Copy link
Collaborator

My thoughts are, I agree with @tabatkins :)

@fantasai
Copy link
Collaborator

Agenda+ for the joint meeting with Math on Web Pages CG next Monday.

@astearns
Copy link
Member

Need to work on the proposal a bit more before bringing this to the agenda.

@astearns astearns removed the Agenda+ label Dec 11, 2018
@fantasai
Copy link
Collaborator

So let's say we introduce a property baseline-priority: high | normal for this. The way it would work is that if an element has baseline-priority: high then its baseline gets propagated to its container at a higher priority than any other: it usurps the place of the first/last baseline when we go looking for the first/last baselines. That's maybe not too complicated.

The next interesting question is, what happens when we get to the container's container? It's for sure representing the first/last baselines of its container. Does it try to usurp the first/last baselines of the container's container as well?

Example:

  <ol style="display: inline-block">
     <li>
     <li><ol><li><li style="baseline-priority: high"><li></ol>
    <li>
  </ol>

The first baseline of the inner OL normally comes from the first line of item 2.1, the last baseline from 2.3. But 2.2 says "pick me", so when we go looking for the first or last baselines of the inner OL, we pick the baseline of 2.2. (This would matter if, e.g. the inner OL were a horizontal flexbox that baseline-aligned its items.)

Now suppose the LIs are all (inner and outer) arranged vertically, and we need the baseline of the outer OL to align it to the surrounding text. We're doing first-baseline alignment, so we ask the OL for its first baseline. Does it return the baseline of item 1 or item 2.2 (which we propagate through the inner OL to be the baseline of item 2)?

@fantasai
Copy link
Collaborator

The alternative to propagating automatically would be propagating explicitly: e.g. LI 2 would also have to say "pick me" for the outer OL to pick it's baseline rather than LI 1.

@tabatkins
Copy link
Member

This is why my earlier idea had the container explicitly opting into the "find my baseline in a weird way" behavior, so we didn't have to either have baselines escaping all over the place, or spamming the baseline-adjuster over all elements between the element and its intended container.

@fantasai
Copy link
Collaborator

fantasai commented Jun 5, 2020

@tabatkins I think if we're only looking at children, and not arbitrary descendants, it's not necessary to have a two-way opt in. (We could, but I think it'll end up more awkward than helpful from an authoring point of view. Imho the only reason to make them do that extra work would be if there's too much of a perf hit for implementations otherwise.)

So I think my proposal here is just to add a baseline-priority: normal | high property, and the container looks at its children and takes its baseline from the first/last item with baseline-priority: high if one exists, or the first/last item with baseline-priority: normal otherwise.

@fred-wang
Copy link

I was asked to comment on this issue but I feel I'm lacking the full context of this request. I can understand alignment against a specific child might be useful for some math constructions but the case of fraction (and more generally for all primitives math constructions with rules defined in the TeXBook / OpenType MATH [1]) the example is not really convincing to be honest...

Concretely, the codepen uses 3 spans for the numerator, horizontal bar and denominator, without space between them (other than the default one around the text inside the 1st and 3nd span) and the goal is to vertically align the middle of the 2nd one with the math axis of the container. I don't see this baseline anymore in [2], but equivalently it is AxisHeight [1] above the (first) alphabetic baseline of the container. It would definitely possible to define such an automatic alignment but more is missing in order to properly perform the full math layout of a fraction [1]:

  • One needs access to font parameters (I believe this is handled in a separate CSS proposal by the Houdini people) e.g. to decide the rule thickness of the bar or AxisHeight from the (first) alphabetic baseline of the container.
  • One has to know the math-style to decide between e.g. fractionShift and fractionDisplayStyleShift (this is handled by [css-fonts] Add new CSS properties math-script-level and math-style #3746 but was put on hold ; hopefully we will be able to reopen the discussion on this soon)
  • One has to know the ink extent of the text in the numerator/denominator text to do the proper layout.
  • The minimal gaps between the ink extent of the numerator/denominator and fraction bar is calculated from the fraction*GapMin parameters.
  • The minimal shifts between the middle of the fraction bar and the (first) alphabetic baselines of the numerator/denominator is calculated from the fractionShift parameters.

So if you consider for example a numerator with a large block size below its (first) alphabetic baseline, the distance from the fraction bar is essentially given by fractionNumeratorGapMin. But if the numerator is changed to have very small block size below its (first) alphabetic baseline, that distance must now be increased to honor the minimal fractionNumeratorShiftUp constraint. So even if the fraction bar alignment is done automatically, one still needs to recalculate the whole gaps/shifts between the numerator/denominator and fraction bar ; while avoiding this recursive calculation was apparently the problem to address.

Obviously, fraction is one the simplest math layout and the situation will be even trickier for more complex constructions. So the conclusion of this long explanation is that this proposal alone will probably not be useful if the goal is to have math layout with quality comparable to TeX / OpenType. It can be fine for very specific cases that use CSS layout with simplified math layout like the ones show in codepen though.

In any case, I personally believe it is more interesting to consider JavaScript layout based on the CSS Layout API in order to perform this kind of advanced layout required for math layout. For example, this single vertical alignment property will probably be irrelevant if the CSS Layout API becomes widely available and is extended to allow authors to specify alphabetic baselines [3]. Last time I tried, this feature was not working yet in Blink but I'm sure @bfgeek can give more details on the status and plan here.

[1] https://docs.microsoft.com/en-us/typography/opentype/spec/math
[2] https://drafts.csswg.org/css-writing-modes-3/
[3] https://drafts.css-houdini.org/css-layout-api/#interaction-alignment

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-inline] vertically align to nth-child.

The full IRC log of that discussion <dael> Topic: [css-inline] vertically align to nth-child
<dael> github: https://github.com//issues/1339
<dael> fantasai: Some discussion of being able to align not just to first or last line but of a particular child of element
<dael> fantasai: Some people working on mathML polyfills wanting this. Also cases where might want vertical alignment in respect to header but stuff above you ignore
<dael> fantasai: Feature to say hey this element is what you should pay attention to for baseline
<fantasai> https://github.com//issues/1339#issuecomment-494988680
<fantasai> e.g. baseline-priority: high | normal
<dael> fantasai: Question is does WG want to add such a feature like baseline-priority:high and if it's high that get priority
<dael> AmeliaBR: Useful for various layout cases where default baseline alignment isn't what you want.
<dbaron> what if you want a child to override the first baseline but not the last lbaseline?
<dael> AmeliaBR: Agree with TabAtkins that way to do it that the child declares it rather than figure out how to have parent refer to which child
<dael> Rossen_: Multiplicity?
<dael> AmeliaBR: First child that says baseline priority if first and last child with last
<dael> Rossen_: Intent of feature is select a specific
<dael> AmeliaBR: You select by setting property on child element
<dael> fantasai: Yes, makes sense
<dael> TabAtkins: You don't declare on everything, you put it on the one thing you want the baseline to come from and that's what you get
<dael> dbaron: What if author wants something high priority for first but not last?
<dael> fantasai: Interesting. Should let them do it. Maybe set sep for first and last baseline
<Rossen_> q?
<dael> AmeliaBR: Or what if you want to align with last line of heading? I don't know.
<faceless2> See also https://github.com//issues/4116, which is the same sort of issues except images exporting baselines.
<dael> AmeliaBR: Prob need to think through full proposal
<dael> fantasai: What I'm hearing is interest in doing this. PRoposal should deal with cases for diff elements setting first and last baseline and cases where first baseline isn't nec the first baseline selected
<dael> Rossen_: At least to start with. More cases will come as we work. I agree there's interest from group
<dael> Rossen_: Who will work? fantasai?
<dael> fantasai: I guess. I would appreciate people with comments and ideas
<dael> Rossen_: General support in going forward with such feature. Sounds like a natural extension to baselines and using more granular capabilities. Please help fantasai with use cases and ideas
<dael> Rossen_: Sound good?
<dael> fantasai: Yep
<dael> dauwhe: Is Brian on?
<dael> Rossen_: I don't see on meeting
<dael> dauwhe: Might be interested b/c MathML work
<dael> Rossen_: Definitely. Anyone interested should help fantasai

@faceless2
Copy link

See also #4116 which is a very similar problem.

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

8 participants