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

fieldset and details have inconsistent definitions in the spec #3805

Closed
bzbarsky opened this issue Jul 7, 2018 · 23 comments
Closed

fieldset and details have inconsistent definitions in the spec #3805

bzbarsky opened this issue Jul 7, 2018 · 23 comments
Labels
topic: fieldset topic: rendering topic: shadow Relates to shadow trees (as defined in DOM)

Comments

@bzbarsky
Copy link
Contributor

bzbarsky commented Jul 7, 2018

Fieldset is defined in terms of the rendering; details is defined in terms of a shadow DOM like thing.

These are different when ::before and ::after are involved, because those are not placed in slots in shadow DOM; they get stuck into the rendering tree at the last minute after flattened tree construction is done.

As a result, per spec as currently written, ::before and ::after on a <details> will not be hidden like the normal non-summary DOM kids are and the ::before will render before the summary. But ::before and ::after on a <fieldset> will behave quite differently, with the ::before going into the fieldset rendering area, not before the legend.

It's not clear to me that this is actually purposeful; I suspect the "just use a shadow tree" thing here was written before shadow DOM had its current shape. It would make a lot more sense to me in terms of resulting behavior to have the ::before/::after of a <details> treated like its other non-summary kids.

@annevk
Copy link
Member

annevk commented Jul 26, 2018

I'm pretty sure this was written this way because at least Apple and Google have voiced interest in implementing these new elements through "internal" shadow tree mechanisms. If instead we described them in terms of CSS boxes (or whatever the latest terminology is there) that would no longer be feasible.

(To me it seems somewhat acceptable to keep fieldset elements special and new elements more grounded in a set of primitives that are also directly exposed to web developers.)

@bzbarsky
Copy link
Contributor Author

The problem is that the resulting rendering is kinda broken, from my point of view. Maybe that means that the shadow DOM spec needs changes of some sort, but what we basically have here is prioritizing implementors' interests over authors' interests, from my point of view.

@annevk annevk added the topic: shadow Relates to shadow trees (as defined in DOM) label Jul 31, 2018
@annevk
Copy link
Member

annevk commented Jul 31, 2018

cc @whatwg/components

@zcorpan
Copy link
Member

zcorpan commented Aug 13, 2018

@bzbarsky do I understand correctly that this issue is really about details being defined in a way that is web-developer-unfriendly, and not an issue with fieldset?

@zcorpan
Copy link
Member

zcorpan commented Aug 14, 2018

A quick test with :before shows different rendering between WebKit/Blink, Gecko, and Edge.

http://software.hixie.ch/utilities/js/live-dom-viewer/saved/6088

@annevk
Copy link
Member

annevk commented Aug 24, 2018

Questions I see being raised here:

  1. Do fieldset and details need to follow the same kind of model? (E.g., does details need an appearance value?)
  2. Should ::before and ::after get assigned to slot elements as if they were Text/Element nodes?
  3. What do web developers want the rendering to be for fieldset/details/element with a shadow tree when they use ::before and ::after on them?

@AmeliaBR
Copy link

To summarize: Browser implementations of <details> mean that details::before and details::after are always available, regardless of whether the widget is expanded or not. More generally, these pseudoelements always go before/after shadow tree content, and can't be re-arranged in the template.

Which is pretty much what I would expect, since these pseudos are attached to the parent <details> box for the entire widget, not to the anonymous box that expands and contracts. If I want the before/after on a <details> to change according to open/closed state, I can always be more specific in my CSS (details[open]::after). If I want ::before/::after on the actual expandable part, I currently can wrap the content in a real element (although having a dedicated pseudo-element for accessing the anonymous box in the shadow tree would be nice).

I certainly wouldn't want to not be able to use generated content on a closed <details> (not sure if that's what you're suggesting, or only suggesting that the order should be re-arrangeable).

So, the confusion seems to be that the <summary> is always pulled up ahead of all its sibling content, but not in front of the ::before? While a <legend>, being pulled completely outside the parent box, ends up in the visible flow before the ::before?

I've always seen the rendering of legend within fieldset as being more like absolute positioning than tree rearrangement. (I just wish I had the ability to do position: legend on other elements, like maybe <summary>!) I haven't examined whether screen readers agree on that.

For me, the only confusing part of the whole system is the tree-rearrangement created when a <summary> isn't the first child. I really wish details/summary had been defined with a model that could be neatly defined & overridden with CSS only, without any shadow required. (But it's a little too late to change that.) Instead, we're left trying to define a CSS pseudo-element model for accessing the functional parts of details/summary:
w3c/csswg-drafts#2084

PS, If it's helpful to anyone else, a pen comparing details vs fieldset: https://codepen.io/AmeliaBR/pen/wEQPMN

@annevk
Copy link
Member

annevk commented Sep 19, 2018

@AmeliaBR thank you for writing that down. I think I see the difference between legend and summary in the same way. @bzbarsky or @MatsPalmgren probably have to way in at this point why they see things differently.

(Note that I filed w3c/csswg-drafts#3126 on question 3 above, which also seems to indicate that the way things are today is okay.)

@AmeliaBR
Copy link

A quick test with :before shows different rendering between WebKit/Blink, Gecko, and Edge.

I'm embarrassed to realize I commented without doing cross-browser testing. Indeed, Gecko (Firefox 63 tested) does display the summary before the details::before, and hides the details::before and details::after when the widget is collapsed.

MS Edge doesn't implement details/summary at all (as of the current stable version, EdgeHTML 17), so they just lay them out as unknown container elements. However, they also handle fieldset/legend different than the other browser rendering engines. Instead of pulling the <legend> out of position to align it over the <fieldset> border, the border is restricted to only start at the legend's normal position. Which means that both the ::before content and any other content in the fieldset before the legend gets rendered outside of the visual box.

But, since all the other major browser engines agree on fieldset/legend, maybe that one can just be called a bug on MS Edge. Although to be fair, my example is technically invalid markup, since the spec says that legend must be the first child.

@MatsPalmgren
Copy link

MatsPalmgren commented Sep 28, 2018

<details>/<summary> is very close to <fieldset>/<legend> semantically. I see no reason why they should behave differently when it comes to pseudos. <details> is by default display:block and its not a replaced element, so it's surprising and inconsistent that the <details> pseudos should go outside the block when all other elements do it per the css-pseudo spec:

... these pseudo-elements generate boxes as if they were immediate children of their originating element.

Can we just make <details>/<summary> behave like normal HTML elements please? (i.e. without built-in mandatory shadow DOM magic)

@annevk
Copy link
Member

annevk commented Sep 28, 2018

By that argument the resulting rendering of

<details>
a
<summary>b</summary>
c
</details>

is also weird, no? Whereas it makes perfect sense if you think of it in terms of shadow trees.

@rniwa @mstensho @hayatoito any thoughts on changing this in Chromium/WebKit?

@MatsPalmgren
Copy link

I don't see anything weird about that example. Anyway, this issue isn't about if <summary> (and <legend>) rendering is weird in general or not. It's specifically about why this example:

<details>
details::before
<summary>b</summary>
details::after
</details>

doesn't give the same results as your example. That's inconsistent, surprising and in violation of the quoted css-pseudo spec IMO.

@tabatkins
Copy link
Contributor

tabatkins commented Sep 28, 2018

details is by default display:block and its not a replaced element, so it's surprising and inconsistent that the details pseudos should go outside the block when all other elements do it per the css-pseudo spec:

Hm? They don't go outside the block. details::before is definitely still inside the block generated by the details element, just like it would be on any other element.

The only thing is that pseudo-elements are inserted into the flat tree, not the pre-flattening DOM tree. So they're not scooped up by slots or anything; a ::before is always the first child of its originating element, regardless of what shadowy trickery the element might be doing with the order of its actual DOM children. This is how author-defined shadow hosts work, and should be how UA-defined ones work too. (And the browser shouldn't, if possible to avoid, be specifying behaviors that aren't achieveable by authors. The only way to rationalize details is with shadow DOM, so it should act the same as an author-defined implementation.)

(It looks like this particular interaction isn't well-specified at the moment. Happy to fix that, apologies for missing it.)

@MatsPalmgren
Copy link

Our complaint is that (quoting from the OP): ":before and ::after on a <details> will not be hidden like the normal non-summary DOM kids ". We want it to be consistent with <fieldset>/<legend> and all other HTML elements. We're not disputing that ::before/::after behaves like this in a Shadow DOM tree. We're saying that Shadow DOM might be a bad model for <details>/<summary> since it leads to inconsistent and surprising results compared to all other HTML elements.

You're completely ignoring our complaint by saying: "well, this is how it works". Sad.

@tabatkins
Copy link
Contributor

fieldset/legend are freaky magic that can't be explained in terms of author-exposed APIs. Using them as a basis for anything is a bad idea.

::before on details works exactly like on any other HTML element. Nothing else has special behavior for ::before/::after, except for the replaced elements that don't allow them at all. What inconsistent behavior do you think you're seeing?

I agree that it would be useful to allow ::before/::after to be on the "contents" of a details, so they get hidden when closed. I outlined my suggested solution to this in the sister thread to this on the CSS repo: HTML should define a ::details-content pseudo-element that's defined on details, and which matches a shadow-div wrapped around the <slot> that selects all the non-summary children. This is identical to what authors can do with a details::part(content) pseudo. Then you can use ::details-content::before to get a ::before acting like how you want. This solution is consistent with implementing details as a shadow host, rather than as unreproducible magic.

@tabatkins
Copy link
Contributor

You're completely ignoring our complaint by saying: "well, this is how it works". Sad.

It wasn't my intention to ignore your complaint; you were saying that the behavior was wrong/inconsistent, and I was answering that it's not. The current behavior is indeed the correct Shadow DOM behavior for ::before/::after.

Insofar as you were saying that the current behavior was undesirable, apologies, I thought the CSS repo's thread had already been linked over here and could be assumed as part of the general knowledge. That lack has been corrected by my latest (immediately preceding) comment.

Also:

We want it to be consistent with fieldset/legend

To the best of my knowledge, this is consistent with fieldset/legend too. They have magical rendering that's not author-exposed, equivalent to some sort of display: border-label; value on the first legend child, but aside from that, the rendering of fieldset/legend with ::before behaves exactly the same as for every other element - the ::before is the first child in the DOM. The "rendered legend" is just moved into the border region at layout time, due to bizarre legacy magic, but that doesn't violate the "::before comes first" principle. It's not possible for content to come before the border of the container, after all! (Without negative margins or similar.)

@MatsPalmgren
Copy link

MatsPalmgren commented Sep 29, 2018

::before on details works exactly like on any other HTML element.

I respectfully disagree. The built-in Shadow DOM on <details> makes it not behave as other HTML elements. Perhaps you meant to say "::before on details works exactly like on any other HTML element that has a Shadow DOM attached.". Then it's correct, but other (non-replaced) HTML elements don't have a shadow tree attached by default. (EDIT: added "(non-replaced)" since the internals of replaced elements are opaque and could very well use Shadow DOM internally. However, <details>/<summary> aren't replaced elements.)

What inconsistent behavior do you think you're seeing?

Quoting from the css-pseudo spec (my emphasis):

... these pseudo-elements generate boxes as if they were immediate children of their originating element.

Hence, the pseudos should be hidden when the <details> is closed, just as other immediate children are hidden.

I outlined my suggested solution to this...

That's nice, but it's still a workaround in my opinion. I'd prefer details::before to work like on other HTML elements. If UAs want to implement <details>/<summary> using Shadow DOM internally, they should be required to do so in a way that is non-observable to authors.

@MatsPalmgren
Copy link

MatsPalmgren commented Sep 29, 2018

BTW, would this hypothetical example work in an UA that implements <details>/<summary> using Shadow DOM?

<details style="-webkit-appearance:fieldset">
  <summary style="-webkit-appearance:legend">LEGEND</summary>
  CONTENTS
</details>

("work" as in: clicking the LEGEND hides the CONTENTS, but nothing else.)

@AmeliaBR
Copy link

AmeliaBR commented Oct 1, 2018

FYI, I put together a twitter poll to gather some feedback from web authors about what they expect from pseudo elements on details, focusing just on details/summary without any confusion from trying to draw parallels with fieldset/legend. Retweets for reach, etc.

https://twitter.com/AmeliasBrain/status/1046860654659887104

Early results are fairly divided, though, so I'm not sure it's going to result in a clear preference for one way or the other.

@AmeliaBR
Copy link

AmeliaBR commented Oct 6, 2018

For the record, here are the questions & responses to that poll:

If you use details::before or details::after on a <details>/<summary> widget, would you expect:

  1. A) pseudos hide/show with non-summary content (54% total)
    B) pseudos always visible (46% total)

  2. A) ::before is before <summary> (67% total)
    B) ::before is after <summary>, before rest of content (33% total)

  • 32% 1A and 2A
  • 22% 1A and 2B (aka, what Firefox currently does)
  • 35% 1B and 2A (aka, what Chrome & Safari currently do)
  • 11% 1B and 2B

From replies to the tweet, it is clear that many are rather confused about the underlying model & how it is supposed to map to CSS concepts in general. We can't go back in time & create a more logical markup model. But I suspect it would be helpful to create a model that we can clearly define using established standards (e.g., shadow DOM) & make all behavior consistent with that model.

@rniwa
Copy link

rniwa commented Oct 25, 2018

TPAC F2F WebPlat: Discussed this topic. We may want a flag to control this since author defined custom elements may also want this behavior. But we've decided that this is probably best discussed in the CSS WG.

@emilio
Copy link
Contributor

emilio commented Jun 12, 2019

FWIW, I just wrote https://bugzilla.mozilla.org/show_bug.cgi?id=1308080 which moves Gecko to use Shadow DOM. I want to discuss with @MatsPalmgren / @bzbarsky and co, in particular, since doing that would inmediately fix problems related with the magic way boxes are suppressed in <details> (https://bugzilla.mozilla.org/show_bug.cgi?id=1558049), and eventually fix issues we have with selection (https://bugzilla.mozilla.org/show_bug.cgi?id=1446675) which we need to address with Shadow DOM anyways.

@annevk
Copy link
Member

annevk commented Sep 14, 2020

Since this hasn't really become more (or less) of a problem I'm inclined to close this. Note that #4746 further formalizes the shadow tree behavior of details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: fieldset topic: rendering topic: shadow Relates to shadow trees (as defined in DOM)
Development

No branches or pull requests

8 participants