Wrapping Flexbox Without Extra Width - css

I'm trying to display a bunch of boxes in a container, such that they fill a row then wrap around when they reach the container's maximum width.
I can make the basic layout easily by putting the following styles on the container <div>:
border: 1px solid black;
display: flex;
flex-wrap: wrap;
max-width: calc(100vw - 500px);
That gets me what I want, but the problem is ... let's say each inner box takes up 300px, and on my screen the container has a width of 800px. I'll get two boxes per row.
However, the flexbox and its border won't stop at 600px. It will keep going to the full 800px, even though there's nothing in the remaining 200px.
I've tried playing with the width and max-width properties, but nothing (eg. fit-content, max-content, 100%) made the container constrain itself to the size of its boxes (ie. 600px).
Is it possible to have a wrapping flexbox where the flexbox's width doesn't extend past the boxes inside of it (when there is leftover space)?

Is it possible to have a wrapping flexbox where the flexbox's width doesn't extend past the boxes inside of it (when there is leftover space)?
Yes, though not in the way envisioned in this question.
A parent of dynamic width containing children with explicit width will result in remainder width.
The standard approach is to divide the remainder width among children, growing them dynamically until enough remainder width exists to fit another child.
Drag the bottom right corner to resize this parent horizontally and get a feel for how this approach attacks the problem.
.parent {
background-color: navy;
display: flex;
flex-wrap: wrap;
gap: 2px;
padding: 2px;
width: 400px;
overflow: scroll;
resize: horizontal;
}
.child {
flex-basis: 150px; /* Desired width */
flex-grow: 1; /* Fill up remaning space at a rate of 1 */
background-color: crimson;
height: 75px;
}
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
There are also many good solutions to this problem using Grid layout.
The approach in dealing with remainder width envisioned in this question appears to be removing it from the parent entirely, which is not possible.
I've tried playing with the width and max-width properties, but nothing (eg. fit-content, max-content, 100%) made the container constrain itself to the size of its boxes (ie. 600px).
In order to calculate how many children can fit at the dynamic width, said width has to be set on the parent, at which point the parent is committed and can't then re-adjust its width. This is the issue with any container and not just Flexbox.

Related

Setting margin-left on a button pushes it beyond the right side of the container

Although I can work around this, I'm curious: why is it when I set a button's width to 100% and set the margin-left property, that it pushes it beyond the containing box (on the right side)? I've tried changing the display property on the button to other values, but I'm getting the same result. Example here:
https://codesandbox.io/s/sharp-nobel-r5x8k
<h1>Hello Vanilla!</h1>
<div id="one">
<button>Beyond bounds</button>
<div id="two">Stays in bounds</div>
</div>
div#one {
background-color: blue;
width: 200px;
padding-top: 1rem;
padding-bottom: 1rem;
}
div#two {
background-color: green;
margin-left: 2rem;
}
button {
width: 100%;
margin-left: 2rem;
}
There are a few things to understand here.
div#one has a fixed pixel width (200px).
The button has a set width 100%. 100% means it inherits the full
width of the parent container.
div#two has no defined width, which means it defaults to auto.
margin property creates extra space around an element.
With these things in mind, we can now get into specifics as to why this scenario occurs.
Since div#one is working with a set width, the space inside the container will be confined within that dimensional space.
div#two does not have any specific width, which means it defaults to auto.
What does that mean? It means that:
width: auto; will try as hard as possible to keep an element the
same width as its parent container when additional space is added
from margins, padding, or borders. This is why that in your current scenario, div#two stays within bounds, because it has yet to break into an overflow case.
width: 100%; will make the element as wide as the parent container.
Extra spacing will be added to the element's size without regards to
the parent. This is why the button exceeds its parent container with exactly 2rem.

For a CSS flexbox, allow an element to shrink to minimum(its intrinsic width, an absolute length) [duplicate]

This question already has answers here:
Flexbox children shrink up to a certain point (but don't expand if they don't need to)
(3 answers)
Closed 2 years ago.
I have a box that displays a number of text elements, one after the other along a row. I do not want the text within each element to wrap. Instead if there is insufficient room then it should truncate the text and show an ellipse.
This is easy to obtain using display: flex, and allowing each element to shrink to zero.
But the smaller elements are shrunk so much that the text almost completely disappears. In that case I would rather shrink the smaller elements a little less, and shrink the bigger elements more. This can also be obtained by giving each element a bigger min-width (say 100px) so that it cannot shrink beyond a certain point.
My problem occurs when one of the text element's intrinsic width is already smaller than 100px. Since I just specified that the element had a longer min width, the browser leaves extra space after the element. I don't want that extra space.
I would prefer not to use java-script. I'm seeking a solution using CSS. It's so close that I feel that it should be possible, but none of my attempts have come out correctly.
If I knew in advance which text elements were tiny, then I can specify that the tiny elements should not flex at all, and get the desired outcome. But without using javascript I do not know which elements are tiny.
If I could set the min-width of an element to the minimum of its intrinsic width and 100px then I would get the desired outcome. Although CSS does have a min() function which may be used for min-width, unfortunately it appears that I am not allowed to use max-content as an argument to that function.
The description of min-width on MDN (https://developer.mozilla.org/en-US/docs/Web/CSS/min-width) states that fit-content(100px) is a syntactically valid way of specifying the min-width. I hoped to craft an element whose minimal content size is zero, and max size is the text element's intrinsic length. Then fit-content(100px) would either be 100px, or if that's larger than the intrinsic length, the intrinsic length. But whenever I use fit-content() with an argument the browser says that the expression is invalid.
Finally I tried to use a grid display. But then fit-content() either uses the intrinsic width or 100px, but does not expand further. I tried experimenting with minmax with no luck (it seems I cannot put fit-content() as an argument to minmax()). Besides I do not know the number of text elements, but a grid display wants me to specify that number so I don't think a grid can be made to work.
So is there any way to obtain the desired outcome using just CSS. Since this text is for an Electron program, I only care about Chrome as a browser. I have an example below showing each of my attempts.
main {
display: flex;
flex-direction: column;
width: 600px;
border-style: solid;
border-color: black;
border-width: 1px;
}
span {
background-color: skyblue;
padding: 10px;
margin: 0 10px 10px 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex: 0 1 auto;
}
section {
width: 100%;
display: flex;
}
.set-min-width span {
min-width: 100px;
}
.set-min-width .no-shrink {
flex: none;
min-width: initial;
}
.use-max-expression span {
min-width: min(100px, max-content);
}
.use-fit-content div {
flex: 0 1 auto;
min-width: fit-content(100px);
display: flex;
}
.use-fit-content div span {
min-width: 0;
}
.use-grid {
display: grid;
grid-template-columns: fit-content(100px) fit-content(100px) fit-content(100px);
}
.use-grid span {
min-width: 0;
}
<main>
<h4>The hidden overflow allows each text item to shrink to nothing<br> Both small and medium elements are heavily truncated<br></h4>
<section>
<span>Medium length</span>
<span>Tiny</span>
<span>Longer text that has to be truncated to fit within the section. It is far far far far too big to fit.</span>
</section>
<h4>By setting a min-width to 100px I can control truncation of medium element. But the tiny element now has extra space after it that I do not want.</h4>
<section class="set-min-width">
<span>Medium length</span>
<span>Tiny</span>
<span>Longer text that has to be truncated to fit within the section. It is far far far far too big to fit.</span>
</section>
<h4>1: This is what I want.<br> But to obtain it I had to specify a different style for the tiny element so that it would not flex. But I don't know in advance which elements are tiny.</h4>
<section class="set-min-width">
<span>Medium length</span>
<span class="no-shrink">Tiny</span>
<span>Longer text that has to be truncated to fit within the section. It is far far far far too big to fit.</span>
</section>
<h4>2: I want the min-width to be the element's max-content if this is smaller than the truncation limit<br> `min(100px, max-content)` would return the correct result, but it is not valid CSS and so is ignored</h4>
<section class="use-max-expression">
<span>Medium length</span>
<span>Tiny</span>
<span>Longer text that has to be truncated to fit within the section. It is far far far far too big to fit.</span>
</section>
<h4>3: I tried to use fit-content(arg)<br> The inner element has min-width 0, so its min-content size should be 0<br> Its max-content size is the intrinsic width of the text<br> So the fit-content(100px) size should be 100px if that's smaller than intrinsic
width, or the intrinsic width otherwise.<br> Despite MDN stating that fit-content with argument is valid CSS for min-width, the browser rejects `fit-content(100px)`</h4>
<section class="use-fit-content">
<div><span>Medium length</span></div>
<div><span>Tiny</span></div>
<div><span>Longer text that has to be truncated to fit within the section. It is far far far far too big to fit.</span></div>
</section>
<h4>4: Using fit-content(100px) in a grid does not work either. The elements are indeed not expanded if natural width is smaller than 100px. But the elements do not flex to take rest of space.<br> Besides a grid won't work because the number of columns is
not known in advance.
</h4>
<section class="use-grid">
<span>Medium length</span>
<span>Tiny</span>
<span>Longer text that has to be truncated to fit within the section. It is far far far far too big to fit.</span>
</section>
</main>
I was giving this a little play around and this was the best I could come up width. The problem that I can see is that flex-box is terrible for not obeying boxes without setting its inner elements with a max-width of some kind. There is a few other answers I found on Stackoverflow but none of them seem to really fix what you are asking for. In my answer I used max-width on the spans, along with text-overflow: ellipsis and overflow: hidden to create something close to what you had requested.
code below and codepen - here https://codepen.io/rl4444/pen/oNLQVRr?editors=1100
HTML
<main>
<h4>my solution</h4>
<section class="box-items">
<span>Medium length</span>
<span>Tiny</span>
<span>Longer text that has to be truncated to fit within the section. It is far far far far too big to fit.</span>
</section>
</main>
CSS
main {
max-width: 600px;
width: 100%;
border-style: solid;
border-color: black;
border-width: 1px;
position: relative;
box-sizing: border-box;
}
span {
background-color: skyblue;
padding: 10px;
margin: 0 10px 10px 0;
white-space: nowrap;
text-overflow: ellipsis;
max-width: 300px;
}
section {
display: flex;
box-sizing: border-box;
max-width: 100%;
}
.box-items span {
border: 1px solid red;
overflow: hidden;
}

Adapt div to image size and proportion, constrained by maximum dimensions

I have some images in divs.
<div class="container">
<img src="http://placehold.it/200x400">
</div>
<div class="container">
<img src="http://placehold.it/300x150">
</div>
I can't find the combination of CSS that fulfils all 3 conditions:
Maximum length of any dimension: 5em
Minimum length of at least 1 dimension: 5em (i.e. either height or width should be 5em) (this is where I think I may need javascript for the boolean OR)
div to completely enclose the img with no excess space (so, the div should have the same aspect ratio as the img)
I'm trying to do the CSS sizing stuff on the divs and then just set the image to width: 100%, height: auto, because I do other sizing functionality on the divs too (resize, move, etc).
Here's the fiddle http://jsfiddle.net/1zvq1rg6/
Use display: inline-block for your divs as you are trying to modify the default display of a div here (size adapting to content).
For the image maximum width/height, the OR you are describing here can be written with max-height and max-width.
Then, if you want no space in your div, just set the padding to 0.
.container {
display: inline-block;
padding: 0;
}
.container > img {
max-width: 5em;
max-height: 5em;
}
http://jsfiddle.net/a1bec8zd

Square Blocks with Flex Box

Is there a way to get all boxes to be equal to the height (and width) of the largest box using display: flex; with flex-wrap: wrap;. It appears to only work on folks in the same line.
This pen illustrates the problem some more: http://codepen.io/komplexb/pen/gbqgXq
Given that you are already setting a height on the parent element (and that the parent element is square), you would just need to give the children flexbox items a height of 50%.
In doing so, the flex-basis (shorthand) value of 50% combined with a height of 50% will result in perfectly square flexbox items since the parent is square.
Updated Example
li {
flex: 0 0 50%;
height: 50%;
color: white;
text-align: center;
}

scrolling flex container does not fit centered items [duplicate]

This question already has answers here:
Can't scroll to top of flex item that is overflowing container
(12 answers)
Closed 6 years ago.
HTML:
<div id="container">
<div class="item">Foo</div>
<div class="item">Bar</div>
</div>
CSS:
#container {
display: flex;
justify-content: center;
overflow: auto;
}
.item {
flex-grow: 1;
min-width: 200px;
max-width: 300px;
}
When the above container shrinks to less than 400px, a horizontal scroll bar appears as expected. However, the first item becomes partially obscured by the left edge of the container, even when scrolled all the way to the left. As the container shrinks, more of the item is obscured.
Demo: http://jsfiddle.net/FTKcQ/. Resize result frame to observe. Tested in Chrome 30 and Firefox 24.
If justify-content is changed from center to to any other value (e.g. space-between), then all content is visible by scrolling. Why do centered items behave differently?
The goal here is to have a row of centered items, each of which will grow in width between some range. If the container cannot fit all minimal-width items, it should scroll to display them all.
According to MDN (Flex item considerations), this behavior is expected for now:
Flexbox's alignment properties do "true" centering, unlike other centering methods in CSS. This means that the flex items will stay centered, even if they overflow the flex container. This can sometimes be problematic, however, if they overflow past the top edge of the page, or the left edge, as you can't scroll to that area, even if there is content there! In a future release, the alignment properties will be extended to have a "safe" option as well.
For now, if this is a concern, you can instead use margins to achieve centering, as they'll respond in a "safe" way and stop centering if they overflow. Instead of using the align- properties, just put auto margins on the flex items you wish to center. Instead of the justify- properties, put auto margins on the outside edges of the first and last flex items in the flex container.
So, you can achieve then expected result, using margins for alignment. Just add margin-left: auto for first item and margin-right:auto for last.
My demo: http://jsfiddle.net/WFxQk/
try with style sheet
#container {
background-color: green;
display: flex;
/* justify-content: center */ ;
align-items: center;
overflow: auto;
}
.item {
background-color: white;
border: 1px solid black;
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;
min-width: 200px;
max-width: 300px;
margin: auto;
}
I removed justify-content, making it to the default flex-start. And, added margin:auto which seems that it makes center alignment.
Updated Demo: http://jsfiddle.net/FTKcQ/1/

Resources