Issue
The question as given in the title has been addressed to some extent in this other question many years ago but the answer there does not seem to be the full story, as I'll show in this question.
I have a grid, with two columns and two rows. The top two cells have images filling them, and the bottom row has one cell spanning both columns, and an image fills that whole cell.
The layout is going to be different on mobile, and so I will need to use picture elements. For the purposes of this example, however, there's just a single <img>
in each <picture>
.
Now, <picture>
elements are weird. The specification doesn't shed much light on how it's meant to act, and the MDN article doesn't add anything relevant here. Maybe there are other relevant specifications? The weirdness in question is how <picture>
elements interact with CSS styling rules.
The common wisdom (see the other question linked above) seems to be that classes should be applied to the <img>
element rather than to the <picture>
element. This makes sense if we treat it as described in the note in the specification linked above:
the
picture
element itself does not display anything; it merely provides a context for its containedimg
element
This has served me well for years, but now I've found that it seems to break down when <picture>
elements are put as direct children of a CSS grid.
As you'll see in the examples below, I have to apply grid-column
directly to the <picture>
element to have it apply; it won't if set on the <img>
element. On the other hand, I have to apply other styles directly to the <img>
element; they won't do what I want them to if set on the <picture>
element.
I can certainly do that, but it's uncomfortable since it feels like brittle undocumented behaviour. I want to know the rules on what needs to go where.
The behaviour is consistent in Firefox and Chrome.
Can anyone illuminate any relevant specifications? Would you deem the current behaviour correct (according to what?) or a bug? Is it likely to be stable or unstable?
.grid {
display: grid;
gap: 2rem;
aspect-ratio: 1 / 1;
grid-template: 1fr 1fr / 1fr 1fr;
background-color: #ccc;
}
.cell {
background-color: #dfd;
}
.cell-3 {
grid-column: span 2;
}
.fill {
width: 100%;
height: 100%;
object-fit: cover;
}
<h2>1. Grid with divs</h2>
<p>Simple case. Everything is as expected here.</p>
<div class="grid">
<div class="cell cell-1">Cell 1</div>
<div class="cell cell-2">Cell 2</div>
<div class="cell cell-3">Cell 3</div>
</div>
<h2>2. Grid with pictures, all classes on img elements</h2>
<p>I can't find proper documentation but as far as I understand it, classes shouldn't be put on picture elements but rather on the img elements within them, since picture elements aren't displayed, just provide context for the nested img.</p>
<p>So in this example all classes are on the img elements.</p>
<p>The .fill class is getting applied and so the images fill their cells and imagery zooms to fill. But the .cell-3 class is doing nothing; it's meant to make the bottom kitten fill both columns. Dev tools complain that it won't do anything because it's not on grid item.</p>
<div class="grid">
<picture><img src="https://placekitten.com/400/400" width="400" height="400" class="cell cell-1 fill"></picture>
<picture><img src="https://placekitten.com/400/400" width="400" height="400" class="cell cell-2 fill"></picture>
<picture><img src="https://placekitten.com/800/400" width="800" height="400" class="cell cell-3 fill"></picture>
</div>
<h2>3. Grid with pictures, all classes on picture elements</h2>
<p>In this example I've moved all the classes to the picture element rather than the img element.</p>
<p>This time, the correct cell size is applied to cell 3 via the .cell-3 class. The .fill class is not having the expected effect, however; the images don't fill their cells.</p>
<div class="grid">
<picture class="cell cell-1 fill"><img src="https://placekitten.com/400/400" width="400" height="400"></picture>
<picture class="cell cell-2 fill"><img src="https://placekitten.com/400/400" width="400" height="400"></picture>
<picture class="cell cell-3 fill"><img src="https://placekitten.com/800/400" width="800" height="400"></picture>
</div>
<h2>4. Grid with pictures, grid classes on picture elements, size classes on img elements</h2>
<p>This shows the desired output. In this example I've put the .cell* classes on the picture element and the .fill class on the img element.</p>
<div class="grid">
<picture class="cell cell-1"><img src="https://placekitten.com/400/400" width="400" height="400" class="fill"></picture>
<picture class="cell cell-2"><img src="https://placekitten.com/400/400" width="400" height="400" class="fill"></picture>
<picture class="cell cell-3"><img src="https://placekitten.com/800/400" width="800" height="400" class="fill"></picture>
</div>
Solution
The picture element is, by default, display:inline
, so it behaves like a span. And like a span if it's the child of a display:grid
element, then the box it generates is a grid item and is blockified.
One way to get what you want is to set the picture element to display:contents
. That way, it won't generate a box, the img element's box will become the grid-item and the img element can be styled exactly as if it were the child of the grid element.
Given the "the picture element itself does not display anything" statement, had the picture element been invented after display:contents
, there's a fair chance it would have been defined as display:contents
by default, but it wasn't and backward compatibility means it couldn't later be changed.
.grid {
display: grid;
gap: 2rem;
aspect-ratio: 1 / 1;
grid-template: 1fr 1fr / 1fr 1fr;
background-color: #ccc;
}
.cell {
background-color: #dfd;
}
.cell-3 {
grid-column: span 2;
}
.fill {
width: 100%;
height: 100%;
object-fit: cover;
}
picture {
display: contents;
}
<h2>5. Grid with pictures, picture element is display:contents, grid classes on img elements, size classes on img elements</h2>
<p>This shows the desired output. In this example I've put the .cell* classes and the .fill class on the img element.</p>
<div class="grid">
<picture><img src="https://placekitten.com/400/400" width="400" height="400" class="cell cell-1 fill"></picture>
<picture><img src="https://placekitten.com/400/400" width="400" height="400" class="cell cell-2 fill"></picture>
<picture><img src="https://placekitten.com/800/400" width="800" height="400" class="cell cell-3 fill"></picture>
</div>
Answered By - Alohci
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.