Interesting, wasn't aware of this. I'm just thinking about it though and I think I'm missing the usecase. If it ignores the parent element for styling, why not just not have the parent element at all? Or is this for situations where you don't have control over the markup but you do over the CSS?
Semantic HTML sometimes creates layers of nesting that make it impossible to achieve certain css effects without either breaking the semantic markup or adding a lot of "pointless" divs.
In an ideal world HTML would be exclusively semantic content (eg, no div elements) and CSS would be exclusively styling (eg, no contents: property). display: contents; does allow us to get a little closer to that ideal.
IMO, it doesn't really do much useful. Imagine you have a grid of titles which may take 1-3 lines and photos beneath the title, and you want to align it to a grid... to make it work, it needs to be
<div display="grid">
<h2>one line</h2><img />
<h2>text that spans two lines</h2><img />
</div>
With this it could be:
<div display="grid">
<Card style="display:contents"><h2>1 line</h2><img /></Card>
<Card style="display:contents"><h2>text that spans two lines</h2><img /></Card>
</div>
But the rub is that you can't both make the "Card" look like a card, and make all the h2's also be the same (minimal) height.
1. Some frameworks (Angular, old React) require a "component" to be have host element.
2. It can sometimes be helpful to group/ungroup elements for responsive layouts.
3. It can be difficult to create semantic HTML (if you care about that sort of thing), because the structure in fact places a huge role in the display.
I have a case where the desktop and mobile layouts are very different: having a few container boxes makes desktop version easy (a couple of vertical flex boxes with content) but on mobile everything is flattened into a single box, and everything has a different sorting order than on desktop.
display-contents makes this simple. The Javascript workaround for MSIE11 is not so nice.
Now you can easily select any h2-level group (heading and elements "belonging" to that heading) by just using the `.h2-group` selector. To my knowledge, there is no way to do this with css selectors alone, so you need the divs, or some other element for grouping. But layout might be getting screwed up because of those divs, so add `.h-group { display: contents; }` and it's like those divs were never there to begin with. Problem solved!
This should be accomplished with the more semantic sectioning tags, i. e. <article> and <section>.
It's possible that there are other examples where this isn't possible, but I can't think of any right now. Tags can also be nested, and levels can be selected using CSS dsecendant and child combinators.
Ironically, I actually used section tags in my original snippets but changed to divs before posting simply because I didn't want the discussion to turn into this-vs-that. :o)
In any case, the point of course is that at times these groups are added to create a kinship between elements that is otherwise not possible to express via css selections, or because it just makes manipulation easier, and you don't want these grouping elements to participate in layout but the children should. In those cases, `display: contents` is the knight in shining armor.
I've been using this a lot recently in an electron app I'm making. Because it's electron I know the target browser and so don't really have to care about compatibility, and man the ignorance is bliss. This value makes grid layouts a million times easier since you can effectively flatten (for styling purposes) even a very deeply nested tree of elements, without ever touching the DOM.
Widespread support for this value can't come soon enough!
Is there a valid reason for not splitting this into 2 properties?
I mean, this has always been a pain, and it's great that they are refactoring it. But the way a block behaves and the way it treats its children really are two distinct concepts.
If I have a list of items, I may very well want the same "outer display" and a different "content display", and yet, I'll have to define outer display everywhere.
Not a massive issue, but display: block flow could be a shorthand for display-outer: block; display-content: flow. In the same way margins or padding work...
That could (hopefully) be part of the plan. Other multi-value properties like border and padding can be specified (or overridden) as a series of more granular properties that target their different values individually.
The existing values for "display" have long conflated "inside" and "outside" display models, so it can't really be separated now.
But at one point there was a proposal to add two new properties, "display-inside" and "display-outside". And "display" was then redefined as a shorthand which combined both. This have been removed (https://www.w3.org/TR/css-display-3/#changes-wd) with this justification:
Removed display-inside, display-outside, and display-extras longhands, in favor of just making display multi-value. (This was done to impose constraints on what can be combined. Future levels of this specification may relax some or all of those restrictions if they become unnecessary or unwanted.)
It seems this is to restrict combinations with "display:none" and "display:content" and the various "display:table-*".
What we really need is the ability to specify these two properties as separate CSS properties. This problem has been the bane of writing reusable components for me. If I want a context to override a component's outer display, I have to go check and make sure I'm preserving its inner display, which is an incredibly fragile practice and prone to being messed up later.
That really does seem like the much saner approach, doesn't it? Like, keep display for outer display as it has the history, and use "flow" for the inner. flow: flex, flow: grid, flow: normal, or something. But HN comments aren't in charge of specs, so I look forward to screwing this up for years to come.
22 comments
[ 3.3 ms ] story [ 80.1 ms ] threadWill make for far easier separation of style and structure, especially with flex/grid layouts.
In an ideal world HTML would be exclusively semantic content (eg, no div elements) and CSS would be exclusively styling (eg, no contents: property). display: contents; does allow us to get a little closer to that ideal.
2. It can sometimes be helpful to group/ungroup elements for responsive layouts.
3. It can be difficult to create semantic HTML (if you care about that sort of thing), because the structure in fact places a huge role in the display.
display-contents makes this simple. The Javascript workaround for MSIE11 is not so nice.
It's possible that there are other examples where this isn't possible, but I can't think of any right now. Tags can also be nested, and levels can be selected using CSS dsecendant and child combinators.
(This obviously wouldn't change OP's point)
In any case, the point of course is that at times these groups are added to create a kinship between elements that is otherwise not possible to express via css selections, or because it just makes manipulation easier, and you don't want these grouping elements to participate in layout but the children should. In those cases, `display: contents` is the knight in shining armor.
There's no way of doing this with css selectors alone, to my knowledge, you need to wrap the elements in some container.
Widespread support for this value can't come soon enough!
I mean, this has always been a pain, and it's great that they are refactoring it. But the way a block behaves and the way it treats its children really are two distinct concepts.
If I have a list of items, I may very well want the same "outer display" and a different "content display", and yet, I'll have to define outer display everywhere.
Not a massive issue, but display: block flow could be a shorthand for display-outer: block; display-content: flow. In the same way margins or padding work...
But at one point there was a proposal to add two new properties, "display-inside" and "display-outside". And "display" was then redefined as a shorthand which combined both. This have been removed (https://www.w3.org/TR/css-display-3/#changes-wd) with this justification:
Removed display-inside, display-outside, and display-extras longhands, in favor of just making display multi-value. (This was done to impose constraints on what can be combined. Future levels of this specification may relax some or all of those restrictions if they become unnecessary or unwanted.)
It seems this is to restrict combinations with "display:none" and "display:content" and the various "display:table-*".