In Chrome and Safari, a parent styled with display: grid doesn't seem to take into account the fact that its child is width: min-content when calculating its own width or its children's positions. See for yourself:
#parent {
position: absolute;
background: lightgreen;
display: grid;
justify-content: flex-end;
}
#child {
padding: 25px;
box-shadow: inset 0 0 0 3px red;
width: min-content;
}
<div id="parent">
<div id="child">
<p>hello jello allegro rhino cello
</div>
</div>
The behavior I would naively expect would be:
to have the red box (child) aligned to the right (because of justify-content: flex-end)
to have the green box (parent) take the width of the red box (because it simply has no reason to be this wide, except that it's exactly the width of the child if it weren't min-content)
Question:
Is this an expected behavior? Do the specs say anything about this? Or is this a bug and Firefox got it right?
My assumption is that calculating a grid layout isn't O(1) or even O(n) and browsers need to bail-out early on edge cases, and width: min-content is probably kind of the same thing. But I'm just guessing here.
Bonus points if you can point me in the direction of an open ticket for this "bug" in either of the 3 big browsers!
Related
I want to have a square div inside a flexbox. So I use:
.outer {
display: flex;
width: 100%;
background: blue;
}
.inner {
width: 50%;
background: yellow;
padding-bottom: 50%;
}
<div class="outer">
<div class="inner">
<a>hehe</a>
</div>
</div>
This works fine in Chrome. But in Firefox, the parent squeezes to just one line.
How do I solve this in Firefox? I use version 44.
You can also view the code at https://jsbin.com/lakoxi/edit?html,css
2018 Update
The flexbox specification has been updated.
4.2. Flex Item Margins and Paddings
Percentage margins and paddings on flex items, like those on block
boxes, are resolved against the inline size of their containing block,
e.g. left/right/top/bottom percentages all resolve against their
containing block’s width in horizontal writing modes.
Original Answer - applies to FF and Edge versions released before 2018
From the flexbox specification:
Authors should avoid using percentages in paddings or margins on flex items entirely, as they will get different behavior in different browsers.
Here's some more:
4.2. Flex Item Margins and Paddings
Percentage margins and paddings on flex items can be resolved against either:
their own axis (left/right percentages resolve against width, top/bottom resolve against height), or,
the inline axis (left/right/top/bottom percentages all resolve against width)
A User Agent must choose one of these two behaviors.
Note: This variance sucks, but it accurately captures the current state of the world (no consensus among implementations, and no consensus within the CSSWG). It is the CSSWG’s intention that browsers will converge on one of the behaviors, at which time the spec will be amended.
In addition to Michael_B's answer, here is a possible workaround.
When using percent we often relate that to the viewport width, so with that in mind, viewport units vw/vh can be an option, since it works similar (responsive).
Stack snippet
.outer {
display: flex;
width: 100%;
background: blue;
}
.inner {
width: 50%;
background: yellow;
padding-bottom: 50vw;
}
<div class="outer">
<div class="inner">
<a>hehe</a>
</div>
</div>
Updated based on a comment
If a square is a must, and viewport units or script can't be used, here is another trick using a dummy image.
Note, as image also a SVG or a Base64 could be used as a datauri to save an extra round trip to the server
.outer {
display: flex;
width: 100%;
background: blue;
}
.inner {
width: 50%;
background: yellow;
}
.inner img {
display: block;
width: 100%;
visibility: hidden;
}
<div class="outer">
<div class="inner">
<img src="http://placehold.it/10" alt="">
</div>
</div>
I've made a grid template with rows of 1fr 1fr 1fr. In the middle row, there are a list of inline images.
In Chrome and Firefox, the images respect the height of the grid row and adapt properly. However, in Safari 10.1.2 and Safari TP 31, there appears to be a combination of the images overflowing the row and not scaling the image widths appropriately.
Perhaps I'm doing something wrong? Or is this a Safari bug? And if so, is there a workaround?
Safari 10.1
Safari TP
Chrome 60
#grid {
height: 100vh;
display: grid;
grid-template-rows: 1fr 1fr 1fr;
}
#thumbnailContainer {
position: inherit;
overflow-x: auto;
overflow-y: hidden;
white-space: nowrap;
}
img {
display: inline;
height: 100%;
width: auto;
}
header,
footer {
background-color: dodgerblue;
}
<div id="grid">
<header>Header</header>
<div id="thumbnailContainer">
<img src="https://c2.staticflickr.com/8/7591/16903911106_b7ced9d758.jpg">
<img src="https://c1.staticflickr.com/9/8740/16927517701_810fcb2a7c.jpg">
<img src="https://c2.staticflickr.com/8/7637/16902583636_15138a68f0.jpg">
<img src="https://c2.staticflickr.com/8/7614/16927530091_6755845b13.jpg">
<img src="https://c1.staticflickr.com/9/8700/16741099010_d0ecd9df1f.jpg">
<img src="https://c1.staticflickr.com/9/8745/16927567841_74fd20d01d.jpg">
</div>
<footer>Footer</footer>
</div>
https://jsfiddle.net/fqkjhh6m/1/
Short Answer
The problem is that Safari is not recognizing the height: 100% on the img elements.
Explanation
This is not a Safari bug. It's just a different interpretation of the spec.
When dealing with percentage heights, some browsers (like Safari) adhere to the traditional interpretation of the spec, which requires a defined height on the parent.
10.5 Content height: the height
property
<percentage>
Specifies a percentage height. The percentage is calculated with
respect to the height of the generated box's containing block. If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned, the used height is calculated as if auto was specified.
In other words, a percentage height on an in-flow element will be recognized only when the parent has a defined height.
Some browsers, such as Chrome and Firefox, have moved past this interpretation and now accept flex and grid heights as an adequate parent reference for a child with a percentage height.
But Safari is stuck in the past. This doesn't mean it's wrong, invalid or a bug.
The last substantive update to the CSS height definition was in 1998 (CSS2). With so many new CSS properties and technologies since that time, the definition has become obsolete, unclear and woefully incomplete. Until the definition is updated for modern use, browser rendering variations can be expected.
Solution
Since Safari doesn't recognize the height: 100% on the img elements, and you can't specify a height on the parent (#thumbnailContainer) because that height is defined by grid-template-rows: 1fr on the top-level container, you can try using flexbox.
By making #thumbnailContainer a flex container, you can define the size of the images (flex items) using flex properties.
#grid {
height: 100vh;
display: grid;
grid-template-rows: 1fr 1fr 1fr;
}
#thumbnailContainer {
display: flex;
overflow-x: auto;
overflow-y: hidden;
min-width: 0;
min-height: 0;
}
img {
flex: 0 0 35%;
min-width: 0;
object-fit: cover;
}
header, footer {
background-color: dodgerblue;
}
<div id="grid">
<header>Header</header>
<div id="thumbnailContainer">
<img src="https://c2.staticflickr.com/8/7591/16903911106_b7ced9d758.jpg">
<img src="https://c1.staticflickr.com/9/8740/16927517701_810fcb2a7c.jpg">
<img src="https://c2.staticflickr.com/8/7637/16902583636_15138a68f0.jpg">
<img src="https://c2.staticflickr.com/8/7614/16927530091_6755845b13.jpg">
<img src="https://c1.staticflickr.com/9/8700/16741099010_d0ecd9df1f.jpg">
<img src="https://c1.staticflickr.com/9/8745/16927567841_74fd20d01d.jpg">
</div>
<footer>Footer</footer>
</div>
jsFiddle
More information
Working with the CSS height property and percentage values
Chrome / Safari not filling 100% height of flex parent
Why doesn't flex item shrink past content size?
Why isn't object-fit working in flexbox?
Don't ask me why, but wrapping the grid parent with a simple div solved my problem.
This article (https://newbedev.com/why-is-css-grid-row-height-different-in-safari) mentions:
Put display:grid on the div surrounding your grid container.
My problem was solved just by wrapping the grid container with a div. Just wanted to mention another solution. I hope someone can add an explanation for what is happening here.
This is best illustrated with a simple example.
I have a container with display: flex and flex-direction: column, with a single div inside with height: 300px and flex: 1.
Chrome renders the nested div at 300px tall, but Firefox renders it as a single line. Is this just a nuance between the implementation of flexbox between the two browsers, or is this bad code somehow? If a nuance, what's the best way to mitigate?
.container {
display: flex;
flex-direction: column;
}
.container > div {
background-color: #666;
color: white;
flex: 1;
height: 300px;
}
<div class="container">
<div>Single line in Firefox, but 300px tall in Chrome!</div>
</div>
The flex: 1 shorthand rule breaks down as follows:
flex-grow: 1
flex-shrink: 1
flex-basis: 0
Chrome sees this, but overrides flex-basis with height: 300px.
Firefox sees this, but does not override flex-basis with height: 300px.
The simple cross-browser solution is to get rid of the height rule and just use:
flex: 1 0 300px
In terms of the spec, Firefox has the correct behavior:
7.1. The flex
Shorthand
When a box is a flex item, flex is consulted instead of the main
size property to determine the main size of the box.
The flex item’s main size
property is
either the width or height property.
I want to have a square div inside a flexbox. So I use:
.outer {
display: flex;
width: 100%;
background: blue;
}
.inner {
width: 50%;
background: yellow;
padding-bottom: 50%;
}
<div class="outer">
<div class="inner">
<a>hehe</a>
</div>
</div>
This works fine in Chrome. But in Firefox, the parent squeezes to just one line.
How do I solve this in Firefox? I use version 44.
You can also view the code at https://jsbin.com/lakoxi/edit?html,css
2018 Update
The flexbox specification has been updated.
4.2. Flex Item Margins and Paddings
Percentage margins and paddings on flex items, like those on block
boxes, are resolved against the inline size of their containing block,
e.g. left/right/top/bottom percentages all resolve against their
containing block’s width in horizontal writing modes.
Original Answer - applies to FF and Edge versions released before 2018
From the flexbox specification:
Authors should avoid using percentages in paddings or margins on flex items entirely, as they will get different behavior in different browsers.
Here's some more:
4.2. Flex Item Margins and Paddings
Percentage margins and paddings on flex items can be resolved against either:
their own axis (left/right percentages resolve against width, top/bottom resolve against height), or,
the inline axis (left/right/top/bottom percentages all resolve against width)
A User Agent must choose one of these two behaviors.
Note: This variance sucks, but it accurately captures the current state of the world (no consensus among implementations, and no consensus within the CSSWG). It is the CSSWG’s intention that browsers will converge on one of the behaviors, at which time the spec will be amended.
In addition to Michael_B's answer, here is a possible workaround.
When using percent we often relate that to the viewport width, so with that in mind, viewport units vw/vh can be an option, since it works similar (responsive).
Stack snippet
.outer {
display: flex;
width: 100%;
background: blue;
}
.inner {
width: 50%;
background: yellow;
padding-bottom: 50vw;
}
<div class="outer">
<div class="inner">
<a>hehe</a>
</div>
</div>
Updated based on a comment
If a square is a must, and viewport units or script can't be used, here is another trick using a dummy image.
Note, as image also a SVG or a Base64 could be used as a datauri to save an extra round trip to the server
.outer {
display: flex;
width: 100%;
background: blue;
}
.inner {
width: 50%;
background: yellow;
}
.inner img {
display: block;
width: 100%;
visibility: hidden;
}
<div class="outer">
<div class="inner">
<img src="http://placehold.it/10" alt="">
</div>
</div>
I have a flexbox layout.
The html is as follows:
<div class="grid">
<div class="row">
<div class="column">Content</div>
<div class="column">Content2</div>
<div class="column">Content2</div>
</div>
<div class="row">
<div class="column">Content</div>
<div class="column">Content2</div>
<div class="column">Content2</div>
</div>
</div>
and the css:
.grid {
overflow: auto;
width: 500px;
height: 400px;
background-color: #eee;
display: flex;
flex-direction: column;
}
.row {
background-color: #ddd;
align-items: stretch;
display: flex;
border: 2px solid black;
}
.column {
flex: 1 0 20em;
padding: 0.2em;
border: 2px solid lightblue;
/*background-color: hsla(0, 100%, 80%, 50%);*/
}
(see https://jsfiddle.net/bz71qptu/1/)
In the previous code, the .box element does not expand to the width of its children. How do I make it do this?
Edit
I have added an example of what I am hoping to achieve visually to the jsfiddle
Edit 2
I needed to change the question slightly to fit my particular issue. The parent element is aligned with flex-direction: column which means that using min-width doesn't seem to work. The min-width solution would be perfect without this.
Edit 3
I'm very thankful to everyone for helping, but I'm not sure I've exactly captured the behaviour I wanted to in my example, and even with all the advice I've been given I can't seem to make it do what I want. Here is a much better jsfiddle, if you look at this I've put borders up to show where everything is. I've read through the answers to see if I can adapt them to my situation, but I can't quite see it. I apologise if this fiddle is already answered.
Revised Answer
Your revised question changes the flex-direction from row to column.
With this adjustment, the flex property applied to .box is no longer relevant for your purposes, as it now handles vertical sizing. In other words, with column the flex property controls height not width.
As I mentioned in the comments, however, adding overflow: auto to .box seems to work perfectly (tested in Chrome, FF and IE11).
DEMO
You mentioned in your comments that it breaks the layout engine. The layout broke for me, as well in jsFiddle. Just hit [RUN] it again.
Ever since jsFiddle launched their upgrade a few days/weeks(?) ago it's been causing some confusion, as it now caches code. You may need to clear jsFiddle cookies (go to chrome://settings/cookies in your browser) or run revised code again after loading.
Original Answser
Instead of content for the flex-basis value, try auto or 0.
The content value isn't supported yet.
In fact, maybe simply flex: 1 will work for you.
See here:
CSS-Tricks ~ Common Values for flex
W3C Flexbox Spec ~ Common Values for flex
class .box is a flexbox container and a flexed child of class
.container
display: flex makes it act as a flexbox container
flex: 1 0 auto defines how it behaves as a child (of .container)
class .element is a flexed child of class .box
display: flex makes .element act as a flexbox container and yields no effect in your fidde (only when .element has children)
flex: 1 0 auto defines how it behaves as a child (of .box)
As you have not defined any sizes but 1000em for class .element, overflow: auto for class .container and flex-shrink: 0 (in flex: 1 0 auto) for both class .box and .element all elements react on the defined 1000em and can only grow to 1000em.
Change both flex: 1 0 auto to flex: 1 (defaults to flex: 1 1 auto) and your question has been answered!
Tiny update: .element change to flex: 1; min-width: 1000em
Fiddle