whatwg/html

Need a way to styling the disclosure triangle of the <details> (or <summary>) element

aethanyc opened this issue · 28 comments

This question was raised in bug 1221416 when implementing <details> and <summary> elements in Firefox.

The spec does not specify how to customize of the triangle or should it be customizable, but we should support it somehow. The spec might need to clarify on this.

Currently, webkit supports a non-standard pseudo-class summary::-webkit-details-marker as this article said.

@upsuper proposed we could add ::marker support for <summary> element in pseudo-element spec. This makes sense to me.

Any other ideas? @bzbarsky

I don't think the HTML spec is the right place to discuss this. HTML doesn't care much about how things should be rendered or styled. Those are in the scope of CSS, and thus it is better to discuss that in CSSWG. CSS Pseudo-Elements Module is likely the right place for this issue.

@upsuper thanks. I'll close this and file it to the proper place.

FWIW, this probably warrants a change of sorts to the HTML rendering section, since if we don't specify there how the default is rendered, it would be hard for it to be overridden.

So if the CSS WG decies that ::marker is fine we should probably update HTML to use that pseudo-element to get the default triangle rendered.

FWIW, In CSS Counter Styles, disclosure-open and disclosure-closed are defined for <details>, but I don't think it is currently usable for styling this, since list-style-type doesn't seem to be a right property for <details>/<summary>. And ::marker is defined inside CSS Lists and Counters, which currently says this pseudo-element is created only for list items.

cc @tabatkins, any thoughts about this topic?

After discussion with @tabatkins and @fantasai, I think we should add the following presentational hint for <summary>:

summary {
  display: list-item;
  list-style: disclosure-closed;
}
details[open] > summary {
  list-style: disclosure-open;
}

and remove summary from rules in "14.3.3 Flow content" section.

Hmm, that seems pretty weird to me, but I am happy to take the advice of our resident style experts if that's what implementers want to do. And it sounds like @aethanyc and @upsuper are up for implementing this in Gecko? So that's enough support for me to say this is good.

I'd ideally like to track down someone in Blink and WebKit who'd be interested in implementing this, and make sure they're not opposed. But I'm OK with someone doing a PR for this change in the meantime. I will file a Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=590014

To clarify, I don't think we (Gecko) currently have plan to provide the unprefixed ::marker. But via making summary a list item (which is the concept of a box with a marker), the triangle can at least be styled with our existing prefixed ::-moz-list-bullet, which will eventually be merged into ::marker.

I agree with you that the concept "list item" and the corresponding properties are weird here, but @tabatkins and @fantasai think they are otherwise fine, and they are happy with it. From my point of view, it seems reusing these should also make implementing easier in Gecko.

Also, overriding the triangle itself would directly be doable via changing list-style with this setting without support of ::marker.

To complement what @upsuper said, currently gecko don't implement summary as list-item to display the triangle. Instead I reuse the same code path which constructs the list-item in layout engine so that the web page can still see the triangle even if it sets summary as display:block. Gecko already have the ability to style the triangle by ::-moz-list-bullet as shown in this test case.

Of course, setting summary as a list-item does let you display and style the triangle as well. However at least in gecko we have to make the list style position inside to make the triangle show up inside the summary block. That is

summary {
  display: list-item;
  list-style: disclosure-closed inside;
}
details[open] > summary {
  list-style: disclosure-open inside;
}

Oh, I wasn't aware that the triangle is inside summary by default. Yeah, that makes sense. This isn't something Gecko-specific, but what the spec indicates. (BTW, I think we should support outside as well.)

@aethanyc Given that the spec says that the details element should have 40px of padding on its "start" side [1], I don't understand why the summary element should have list-style-position: inside. That padding is presumably there for list-style-position: outside and so that the details content of the details element neatly lines up under the summary content. list-style-position: inside also means that styles like text-decoration: underline are applied to the widget, which seems undesirable.

Also, if you're going to use display: list-item, then display: block should make the list marker disappear. Your explanation makes it sound like changing the property has no effect.

@upsuper Chrome puts the disclosure widget inside the summary element, but I don't see anything in the spec that says to do that. I guess the Mac screenshots [2] might imply it, but those are just examples. It also doesn't put any padding in the details element. Chrome creates an ugly situation where the details text is directly under the disclosure widget.

[1] https://html.spec.whatwg.org/multipage/rendering.html#the-details-element-2
[2] https://html.spec.whatwg.org/multipage/forms.html#the-details-element

@patrickdark Yes, the existing impls do not match the spec, and the elements have been used in wild, so we should just change the spec to match the impls. That says, we should remove the padding and make the marker inside here.

@upsuper That seems like a strange position given that the Firefox implementation doesn't match the Chrome implementation. Chrome uses display: block instead of display: list-item and ::-webkit-details-marker instead of (the useless) ::-moz-list-bullet. If you were trying to match them, you'd be using ::before instead of pretending to use an unimplemented ::marker since that more closely matches their implementation.

Aside from not matching the spec, the Chrome implementation needs to be changed anyway since it ignores OS conventions. Google seems to have implemented something similar to the OSX convention, which makes no sense on Windows. (You can see the Windows conventions by looking at the Device Manager.) Their widget behavior also needs a fix; clicking it twice selects the summary when that can be fixed with user-select: none.

Lastly, Chrome is the only implementation. It seems like it would be better to fix these issues now than ship a poor clone of a poor implementation.

Chrome is not the only implementation. Safari has that as well, although this exists before Blink forked. But you'll need to fix both now anyway.

In addition, an important criteria is that, the elements have been used widely. Chrome platform status shows it has been used in ~0.08% of pages in web, which is enough a significant number. And Drupal said they have been using these elements in Drupal 8, which would potentially increase the number further in near future. Given these, changing the impl could break existing design, consequently cause web compatibility issue.

Changing to display: list-item and ::marker doesn't change its default behavior. As the old behavior is less stylable, I'm not very concerned about changing the user agent stylesheet to match the spec could cause significant webcompat issue for existing impls.

Note that making spec match impls doesn't mean we need to make every details match, but instead, we want to make the spec sensible as far as we do not break the web without a good reason.

If you were trying to match them, you'd be using ::before instead of pretending to use an unimplemented ::marker since that more closely matches their implementation.

This seems weird - why does current usage of a non-standard pseudo-element imply we should use ::before? It seems that, since ::before is currently usable on summary elements, naive compat concerns would imply we have to keep it free to use, so we should definitely be using some new pseudo. ::marker happens to work well with that. (We also purposely don't use ::before on anything currently, as it's intended to be kept for author usage.)

In addition, everything @upsuper said is correct.

What are the CSS properties that can/will be applied to the (new?) pseudo element?

What are the CSS properties that can/will be applied to the (new?) pseudo element?

See CSS Pseudo-Elements Module Leve 4 # List Markers.

It is expected that future specifications will extend this list of properties

That's what I wanted to discuss:

  • How would you replace the marker by an image?
  • If it's considered a list-item, will counter properties be supported?

This isn't in the scope of the HTML spec. Please discuss this in the www-style mailing list.

@tabatkins I suggested using summary::before because the rendering of the disclosure widget as implemented in Chrome and planned by @upsuper for Firefox is inline, which is what is expected of the ::before pseudo-element. An implemented pseudo-element like ::before can also be affected by more style properties like background-color, font-weight, and width. This also makes it easier to erase and replace the disclosure widget because you simply need to overwrite ::before instead of first setting display: block, list-style-type: none, etc.

Regarding backward compatibility, I can't think of any situation where you would want both summary::before and the native disclosure widget especially if the widget is going to be something that can be duplicated with a Unicode character string. I'd imagine that any author specifying ::before at this point has already disabled the disclosure widget and is probably specifying ::before as a replacement for said widget; those webpages wouldn't be affected.

Add to that that you'll need a span element anyway to style the summary element text independent of the list-style-position: inside list bullet, and you have another hook for ::before via summary > span::before.

Now, authors will need to overwrite summary::marker, but can't since it isn't implemented anywhere. Google rejected ::marker as recently as last March and Mozilla hasn't moved on it since 2003. There's no apparent plans by Microsoft on this feature. I don't place much faith in unicorn features like ::marker that have been specified forever, but never implemented by anyone. Also, I think it's telling that whoever implemented ::-webkit-details-marker went around an existing CSS spec to do so.

Furthermore, authors won't be able to use the main benefit of ::marker for backward compatibility reasons; list-style-position: outside won't work because Chrome doesn't implement the disclosure widget as a marker. The other benefit, non-selectability of the disclosure widget, is trivially achieved by pairing summary::before with user-select: none.

An implemented pseudo-element like ::before can also be affected by more style properties like background-color, font-weight, and width.

Markers can be styled pretty reasonably without ::marker (there's plenty of existing content styling list bullets).

::marker is limited in what it allows, but if you want more, you can just set it to 'block' and use ::before yourself.

This also makes it easier to erase and replace the disclosure widget because you simply need to overwrite ::before instead of first setting display: block, list-style-type: none, etc.

All you need to do is set "display: block".

Regarding backward compatibility, I can't think of any situation where you would want both summary::before and the native disclosure widget especially if the widget is going to be something that can be duplicated with a Unicode character string. I'd imagine that any author specifying ::before at this point has already disabled the disclosure widget and is probably specifying ::before as a replacement for said widget; those webpages wouldn't be affected.

I'm not willing to assume that - ::before is used for lots more things than just "putting some text before the real content of the element".

Add to that that you'll need a span element anyway to style the summary element text independent of the list-style-position: inside list bullet, and you have another hook for ::before via summary > span::before.

Today, yes. Once ::marker is supported that won't be necessary.

Google rejected ::marker as recently as last March

We have not "rejected" ::marker in any significant manner.

Also, I think it's telling that whoever implemented ::-webkit-details-marker went around an existing CSS spec to do so.

Don't read too much into this - it's very common for implementors who aren't closely tied into the spec world to invent their own random crap.

Furthermore, authors won't be able to use the main benefit of ::marker for backward compatibility reasons; list-style-position: outside won't work because Chrome doesn't implement the disclosure widget as a marker.

I don't understand what you think the "main benefit... for backward compatibility" is.

@tabatkins:

We have not "rejected" ::marker in any significant manner.

I hope that's the case, but the relevant Chromium bug¹, citing an incomplete spec and performance concerns regarding this feature, didn't leave me confident of that: "Until the spec is in a better state I don't see this moving forward." "Of note, the PseudoElement system was designed to be used for things that are rare." "In order to move forward with something like the above patch, we would need to justify the cost in terms of how many additional elements will we be creating?"

Mozilla cited an incomplete spec 13 years ago², so what's changed? We still have a spec which says "None of its contents should be considered suitable for implementation at this point."³ Now the design of the summary element is being built off of that spec when there's no indication we're going to get anyone to implement its core feature (::marker) and seemingly not any time soon.

¹ https://bugs.chromium.org/p/chromium/issues/detail?id=457718
² https://bugzilla.mozilla.org/show_bug.cgi?id=205202#c1
³ https://drafts.csswg.org/css-lists/#intro

@tabatkins:

I don't understand what you think the "main benefit[ of ::marker for] for backward compatibility" is.

I don't understand what exactly you're trying to ask with your elided quotation.

The essence of what I trying to say in the paragraph is that there's no near-term benefit to using list counters for the disclosure widget. The rationale for using list counters to implement greater styling capability hinges entirely on the unicorn feature called ::marker being implemented. In the meantime, authors will use summary elements in spite of list counters, not because they offer any benefit.

To understand where I'm coming from, imagine you're an author that wants to use details and summary in a way that's cross-browser-compatible, with a custom disclosure widget, with the model implemented in Chrome and proposed in Firefox, but without ::marker. You're almost certainly going to start by disabling the list counter, the Chrome pseudo-element, and resorting to ::before. Why not skip the "disabling the list counter" step entirely?

Now the design of the summary element is being built off of that spec when there's no indication we're going to get anyone to implement its core feature (::marker) and seemingly not any time soon.

CSS Pseudo-Elements spec has a restricted (thus more feasible) ::marker definition, which should have mostly matched current prefixed impls. ::marker in CSS Lists not getting much progress is mostly because its layout details are controversial, while the limited set of properties mentioned in CSS Pseudo-Elements don't have this problem.

You're almost certainly going to start by disabling the list counter, the Chrome pseudo-element, and resorting to ::before. Why not skip the "disabling the list counter" step entirely?

You don't need to. You can use ::-webkit-details-marker and ::-moz-list-bullet immediately. If you only want to change the shape, or use image for the marker, you can do that in a pretty cross-browser way: just specify list-style.

You can use ::-webkit-details-marker and ::-moz-list-bullet immediately.

I didn't mean people should use these two pseudos. I mean, they can be considered as the prefixed version of ::marker currently, and we want to have the unprefixed version eventually (in a not-too-long future).

@upsuper:

CSS Pseudo-Elements spec has a restricted (thus more feasible) ::marker definition, which should have mostly matched current prefixed impls. ::marker in CSS Lists not getting much progress is mostly because its layout details are controversial, while the limited set of properties mentioned in CSS Pseudo-Elements don't have this problem.

Wow, I didn't realize there were two contradictory specs defining this feature.

The feature set in the reduced version is terrible. You can't even use the text-shadow, transform, or width properties, for example. The marker text itself can't be changed either without going back to CSS3 Lists and Counters for list-style-type: "string".

The lack of customization options means that ::before remains the better choice.

On the bright side, maybe we'll get an unprefixed ::marker pseudo-element sooner rather than later.

@upsuper:

You don't need to. You can use ::-webkit-details-marker and ::-moz-list-bullet immediately.

These pseudo-elements are far less powerful than the ::before pseudo-element and aren't documented. In particular, there's no way to change the content of the bullet itself. Firefox at least offers list-style-type: "string" independently, but that does no good without Chrome support.

Chrome's pseudo-element also has some quirks because it refers to a scalable image. For example, changing the width of the bullet region to a specified width without resizing the bullet itself is non-trivial.

@upsuper:

If you only want to change the shape, or use image for the marker, you can do that in a pretty cross-browser way: just specify list-style.

Try summary { display: list-item; }; it does nothing in Chrome.

The workaround requires editing the markup by, say, nesting a span element within the summary element. That will require removing list counters from the summary element in future versions of Firefox.

Chrome is looking for input from other vendors on making this change; see https://bugs.chromium.org/p/chromium/issues/detail?id=590014#c17. In particular:

It looks like we need to synchronize state with other vendors. We measured the use of display: block on summary and it is not used much; but we're not sure about other values of display and need to investigate. Users noticed that flexbox did not work with summary, for example. We'd like to know if any browsers made this change and if they're seeing complaints about the summary triangles not appearing.

@upsuper your expertise would especially be appreciated.

I believe <summery> shows the triangle only when display value is list-item in Gecko, and I don't recall any complaint for that, so I think it should be safe for other vendors to switch to this behavior as well.