Open hfhchan opened 6 years ago
Something like this could also be used for some cases of list styling:
li {display :inline;}
ul::between { content: ", "; }
ul::after { content: "."; }
:lang(jp) ul::between { content: "、"; }
:lang(jp) ul::after { content: "。"; }
You can do that with existing selectors though.
If what you're trying to put separators between is a bunch of buttons or a bunch of links (without a wrapping element), it's true that ::after
would insert the separator inside of the buttons/links, which is not what you'd want.
My ::contents
proposal (#2406) would solve your use-case:
ul.recycler {
display: contents;
}
ul.recycler::contents {
display: block;
}
ul.recycler + ul.recycler::before {
display: block;
content: "";
border-bottom: 1px solid #ccc;
margin: 0 40px
}
...huh, ::between
isn't a bad idea at all. ::contents
isn't either. Both of them involve adding a substantial chunk of complexity in different ways.
Really I think there's been four variants of this idea proposed in the past, all with different strengths and weaknesses:
::between(an+b)
you also have to store an arbitrary amount of additional style data. At least recalculating it won't be more complex than handling :nth-child()
pseudos (which is to say, relatively expensive). As a plus, ::between is a child of its originating node, which makes inheritance saner.if
s to every element.I suspect we'll want to add one of these at some point in the future, so it would be good to see which of these are easier/harder in the various engines.
If we only go for one, my vote probably goes for ::contents
, it seems more powerful and generally applicable. And if you add that, I agree we shouldn't get ::parent
/::wrapper
or ::outer-before
/::outer-after
, I am not sure it cancels the argument for ::between
@Loirooriol's example shows how you can achieve the ::between effect with ::contents. You can produce similar code with any of the others, too.
I don't think @Loirooriol's example cover's the 2nd point laid out by @hfhchan where ::between
could make it so hit-testing is on the actual children items. The example might just need to alter ul.recycler + ul.recycler::before
to ul.recycler li + li::before
, adding in the li
to the selectors? But still don't think that fully covers that point. Say, if it's not a ul
with li
inside, and instead just a div
with a
tags inside, I think forcing the use of ::before
would make styling a:hover
cumbersome, instead having to style a::contents:hover
as well as clicking on the ::before
would execute the link, unless it had pointer-events: none
set?
All in all, I'm a huge fan of the ::contents
proposal and am more excited to see that land. But it doesn't seem to cover the possibility of generated content being truly between siblings.
Right. either I'm misunderstanding @Loirooriol 's example, or it doesn't work. His css seems to assume that there'd be multiple ul.recycler
and puts pseudos between them, but the original example assumed a single ul.recycler
with multiple children, and put pseudos between the children.
And I agree with @jonjohnjohnson's point: using the foo::contents
with foo + foo::before
does not fully replace ::between
when foo is an interactive element like a link, as that interactiveness would still apply to the ::before
.
Yeah, I was assuming that @Loirooriol's code was corrected to refer to the li
s, not the ul
. ^_^
I fat-fingered the delete button of a previous comment, basically I said that I misread the proposal and that the code with ::contents
needs some small modifications:
ul.recycler > * {
& { display: contents }
&::contents { display: block }
& + ::before { /* ... */ }
}
It's true that proper hit-testing may need some refinements, like using ul.recycler > ::contents:hover
instead of just ul.recycler > :hover
, or playing with pointer-events
. But I think it's mostly doable.
This table summarizes the relationships between the related proposals:
Feature | Can be simulated with | |||
---|---|---|---|---|
::between |
::contents |
::wrapper |
::outer-before / ::outer-after |
|
::between |
- | Yes, with display: contents and ::before / ::after . |
Only if ::wrapper::before / ::wrapper::after are allowed. |
Yes. |
::contents |
Mostly not. | - | Only for use-cases without ::before nor ::after |
Mostly not. |
::wrapper |
Mostly not. | Only for use-cases without ::before nor ::after |
- | Mostly not. |
::outer-before / ::outer-after |
Mostly not. | Yes, with display: contents and ::before / ::after . |
Only if ::wrapper::before / ::wrapper::after are allowed. |
- |
IMO the best and most complete one is ::contents
. ::wrapper
may be good enough if pseudo-element nesting is allowed, but this would allow generating arbitrarily-deep structures which I suspect will be more difficult to implement.
From what I've gathered, ::contents
has the best (if not only) shot at gaining implementor interest, because of it's nearly seamless use of display: contents
and inheritance. So in my mind, the others aren't really on the docket.
The CSS Working Group just discussed new generated content pseudo :between/:separator
.
Following https://twitter.com/AmeliasBrain/status/1100162917893234688, I'd like to express a use-case for replaced elements. In my first years, I tried several times to do something similar to:
input:required::after {
content: "*";
color: red;
}
I've also had to explain why this can't work to co-workers.
I could imagine wanting to prepend an icon like 🔗 to type=url
or 📩 to type=email
.
jensimmons: We have gaps in flexbox and grid, another way would be to style gaps or empty grid cells jensimmons: would allow authors to style those things without them being real
For what it's worth, styling gaps is also discussed in #2748. And personally, I believe the use case of styling gaps in flexbox, grid and multi-column layout is better handled via some properties, because they avoid side effects by inheritance and styling unrelated to gaps. For implementers, this should also make it easier to handle, because it means no extra boxes have to be generated for them.
Having said that, there are still many other use cases, in which the aforementioned pseudo-elements would avoid having to do hacks or add elements only used for styling.
Sebastian
styling gaps is relevant for the layout only: the layout manager has its own requirements depending if this is a horizontal or vertical layout or a grid, and if flex is used (this becomes even more complex with multicolumn layouts, primarily used as containers for text, but not only) But there's a separate need for "::between" to generate contents, not necessarily boxes, without effect on the layout of these boxes. Styling lists with added punctuation/separators is different from styling gaps because they don't add necessarily any new box if the "between" content is a simple text or icon span (it could as well be breaks, or rules inserted inline but still within the same layout box.... So separate the design between generic content separators and layout-specific tuning of their gaps between layout-specific margins of each child (these gaps are complex also because of the need to manage collapsing margins when there's no gap).
Note that gaps may also have negative values (e.g. showing a grid of elements with no gap by default between children, but when hovering the grid with the mouse, negative gap would create a mask layer partially over the children without necessarily resizing or moving them, so the relative layouts of children would remain the same: this may be useful to perform visual selection in a way currently not supported by borders/margins which are always outside the content and never on top of them): negative gaps would then allow to show on top of existing margins, borders, paddings, and contents of the child.
When building toolbars, navbars and lists, often there needs to be separators. They are currently implemented by using :before and/or :after but this is a hacky:
(1) the separator is not semantically a part of the toolbar item or list item itself; (2) the separator messes with hit-testing i.e. hovering the separator would either select the previous or next item which may not be preferred (3) relying on more specific selectors to turn off the selector at the start and/or end of the list.
The effect could be more elegantly accomplished by providing a way to insert generated content between a given node's children.
Example: