Question about flex will not fill the width of the parent container - css

.outside {
/* Note line3, the top and bottom will be the same, why add the flex on the different */
display: flex;
}
.content {
background: skyblue;
display: flex;
flex-wrap: wrap;
}
.item {
width: 20%;
}
<div class="outside">
<div class="content">
<div class="item">apple</div>
<div class="item">apple</div>
<div class="item">apple</div>
<div class="item">apple</div>
<div class="item">banana</div>
<div class="item">banana</div>
<div class="item">banana</div>
</div>
</div>
========
<div class="content">
<div class="item">apple</div>
<div class="item">apple</div>
<div class="item">apple</div>
<div class="item">apple</div>
<div class="item">banana</div>
<div class="item">banana</div>
<div class="item">banana</div>
</div>
the screenshot is how the two cases work
enter image description here
Questions:
I don't know why the with of element with class outside do not fill the screen(like the element with class content)
I would like to know on what basis the 20% of item is calculated

Whenever you specify display: flex on an element, you're inherently adding the following styling to the child elements:
.child {
flex-grow: 0;
flex-shrink: 1;
flex-basis: auto;
}
In the top example, this gets applied to the element with class 'content'. If you were to set flex-grow: 1 on the style block for .content, you would see it take up the whole width.
In your current example, the 20% width is determined from the width of the element with class 'content'.

You have .content inside .outside.
And you set display: flex; for .outside, which changes the width of .content (flex changes widths of children). It is now a single element in the flex row. If you set width: 100%; for .content it will fill that row.
.outside {
/* Note line3, the top and bottom will be the same, why add the flex on the different */
display: flex;
}
.content {
background: skyblue;
display: flex;
flex-wrap: wrap;
width: 100%;
}
.item {
width: 20%;
}
<div class="outside">
<div class="content">
<div class="item">apple</div>
<div class="item">apple</div>
<div class="item">apple</div>
<div class="item">apple</div>
<div class="item">banana</div>
<div class="item">banana</div>
<div class="item">banana</div>
</div>
</div>
<div class="content">
<div class="item">apple</div>
<div class="item">apple</div>
<div class="item">apple</div>
<div class="item">apple</div>
<div class="item">banana</div>
<div class="item">banana</div>
<div class="item">banana</div>
</div>

To make the flex full width display please update your styles as follows;
.outside {
/* Note line3, the top and bottom will be the same, why add the flex on the different */
display: flex;
flex-direction: column;
}
.content {
background: skyblue;
display: flex;
}
.item {
width: 20%;
}
Also you need to read more about flex here. Hope this will work for you.

You just need to use flex-grow:1 on .content as:
.content {
background: skyblue;
display: flex;
flex-grow: 1;
flex-wrap: wrap;
}
This means the child will now take all the remaining space available. By default, the flex child just takes space as per its content.
You can check it here: https://codesandbox.io/s/dazzling-buck-mumtl3?file=/index.html

Related

Make flex children width the same and also fit-content

My scenario
I have these two flex containers (the difficulty options and the max-score options):
I want the 'easy', 'medium' and 'hard' button to share the same width, but also to fit they're content (in this case, because 'medium' is the longest, they should all equal its width).
I want the same behavior with the bottom buttons (but for them to have a smaller width since they need to accommodate for smaller content).
Right now the flex containers for both of them is set to:
display: flex;
flex-direction: wrap;
flex-wrap: wrap;
And the flex children are each set to their default flex values, with a set height and an auto width.
Approaches I've tried
First approach - flex-basis and flex-grow
Setting the children to flex-basis: 0 and flex-grow: 1, as I've seen in past questions, but then my wrapped child fills the entire width, and the top buttons aren't the same width:
Second approach - -- hardcoded flex-basis
Setting all children to flex-basis: 90px (90px to accommodate for the biggest button, 'medium') which does make them all the same width, but then the width is fixed and doesn't adjust to only fit the content (specifically this is desired so the score buttons can fit in two rows instead of three).
Third approach - max-width
The closest I've got to is to set the children to:
```
max-width: 90px;
flex-basis: 0;
flex-grow: 1;
```
Which makes them behave as wanted:
But when the screen width shrinks, the buttons start to differ in width (the obvious one is the '200' button bigger than the other scores, but also 'medium' is bigger than 'easy' and 'hard'):
My code:
.flex-col,
.flex-row {
display: flex;
flex-wrap: wrap;
gap: 4px;
justify-content: center;
}
.flex-col {
flex-direction: column;
}
.flex-row {
flex-direction: row;
}
.button {
border-style: solid;
padding: 4px;
}
.parent {
height: auto;
width: auto;
}
<div class="parent flex-col">
<div class="flex-col">
<div class="flex-row">
DIFFICULTY
</div>
<div class="flex-row">
<div class="button">EASY</div>
<div class="button">MEDIUM</div>
<div class="button">HARD</div>
</div>
</div>
<div class="flex-col">
<div class="flex-row">
MAX SCORE
</div>
<div class="flex-row">
<div class="button">50</div>
<div class="button">75</div>
<div class="button">100</div>
<div class="button">150</div>
<div class="button">200</div>
</div>
</div>
</div>
Help appreciated, thanks!
The closest way to do this with CSS only, is to use a grid instead of a flexbox for reasons well explained here.
The only way to truly do what you are asking (make all children have the same width as the widest child), is with JavaScript. Loop through the elements to find the biggest width and set them all to have the found width.
Here is a snippet demonstrating both concepts:
const equalizers = document.querySelectorAll('.equalize')
let r = 0
equalizers.forEach(equalizer => {
const widths = []
for (const btn of equalizer.children) {
const w = btn.getBoundingClientRect().width
// Math.ceil() is optional to avoid long floats
widths.push(Math.ceil(w)) // 82
// widths.push(w) // 81.31945037841797
}
const biggest = Math.max(...widths)
console.log(`biggest width found in row[${r++}]:`, biggest)
for (const btn of equalizer.children) {
btn.style.width = `${biggest}px`
}
})
.flex-col,
.flex-row {
display: flex;
flex-wrap: wrap;
gap: 4px;
justify-content: center;
}
.flex-col {
flex-direction: column;
}
.flex-row {
flex-direction: row;
}
.button {
border-style: solid;
padding: 4px;
}
.parent {
height: auto;
width: auto;
}
.grid-row {
display: grid;
gap: 4px;
}
.grid-row>* {
text-align: center;
}
#media (min-width: 25em) {
.grid-row {
grid-auto-flow: column;
grid-auto-columns: 1fr;
}
}
.flex-row>* {
text-align: center;
}
<hr>
<strong>JavaScript</strong> (only ever as wide as the widest sibling, with wrapping)
<hr>
<div class="parent flex-col">
<div class="flex-col">
<div class="flex-row">
DIFFICULTY
</div>
<div class="flex-row equalize">
<div class="button">EASY</div>
<div class="button">MEDIUM</div>
<div class="button">HARD</div>
</div>
</div>
<div class="flex-col">
<div class="flex-row">
MAX SCORE
</div>
<div class="flex-row equalize">
<div class="button">50</div>
<div class="button">75</div>
<div class="button">100</div>
<div class="button">150</div>
<div class="button">200</div>
</div>
</div>
</div>
<hr>
<strong>Grid</strong> (always as wide as posible and no wrapping, either all stacked, or all inline with breakpoint)
<hr>
<div class="parent flex-col">
<div class="flex-col">
<div class="flex-row">
DIFFICULTY
</div>
<div class="grid-row">
<div class="button">EASY</div>
<div class="button">MEDIUM</div>
<div class="button">HARD</div>
</div>
</div>
<div class="flex-col">
<div class="flex-row">
MAX SCORE
</div>
<div class="grid-row">
<div class="button">50</div>
<div class="button">75</div>
<div class="button">100</div>
<div class="button">150</div>
<div class="button">200</div>
</div>
</div>
</div>

Flex: How do I set items to take up MAX 1/3 of their container, unless their content overflows

Let's say I have a flex container, I want to be display between 1 and 3 items within.
I would like the items to be:
By default 1/3 of the width of the container (even if there's only 1 item)
If one of the item's text content expands slightly beyond the 33% width, I'd like that item to try and expand if it can (i.e. by one of the other items shrinking).
Justified using flex-start
.container {
display: 'flex';
flex-direction: 'row';
background-color: 'red';
width: '100%';
justify-content: 'flex-start';
}
.item {
flex: 1;
border: 1px solid red;
flex-wrap: 'no-wrap';
}
<div class="container">
<div class="item">blahhhhhhhhhhhhhhhhhhhhhhhhhh</div>
<div class="item">blahhh</div>
<div class="item">blahhh</div>
</div>
<div class="container">
<div class="item">I should take up 1/3</div>
</div>
The above works for the 3 item case, however when a singular item is placed there it expands to fill the space.
Is this possible?
You can use CSS-Grid for that.
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
margin-bottom: 1em;
}
.item {
height: 50px;
border: 1px solid red;
}
.item.wide {
width: 250px;
}
<div class="container">
<div class="item wide"> I'm wider than 1/3</div>
<div class="item"></div>
<div class="item"></div>
</div>
<div class="container">
<div class="item"></div>
</div>
<div class="container">
<div class="item"></div>
<div class="item"></div>
</div>

how to make columns the same width with css flex

hello I need to basicaly display a table but with flex (only because I need to adjust the look for mobile)
.container {
display: flex
}
<div class="container">
<div class="row">
<div>1000</div>
<div>mary</div>
</div>
<div class="row">
<div>1</div>
<div>john</div>
</div>
<div class="row">
<div>11</div>
<div>mike</div>
</div>
</div>
how can I make each column have the same width? or at least the width of the largest item.
If you apply flex-grow: 1 to each div in the .row then it will expand accordingly. Note that the .row divs need the display flex (flex only apply to the DIRECT children of the flexed element.
The width can be set by using flex-basis and calc() and dividing the full-width by the number of columns you want (2 in this case). I added a border to demonstrate.
I would be remiss if I didn't suggest that the best tool to display a table structure - is a ... table... then you can work out how to modifiy for responsive layout - but the semantic structure of a table is correct for tabulr content.
.container {
width: 100%;
}
.row {
display: flex;
width: 100%;
}
.row div {
flex-grow: 1;
flex-basis: calc(100% / 2);
padding: 4px 8px;
border: solid 1px red;
}
<div class="container">
<div class="row">
<div>1000</div>
<div>mary</div>
</div>
<div class="row">
<div>1</div>
<div>john</div>
</div>
<div class="row">
<div>11</div>
<div>mike</div>
</div>
</div>
Use flex-basis to set the 'default' width first.
Use flex-grow and/or flex-shrink to allow it to grow /shrink
Use max-width' and min-width` to define by how much it can grow/shrink
.container{ #Stack the div inside the conainer
display:flex;
flex-flow: columns nowrap;
}
.row{ # Set div as cell in the row.
display:flex;
flex-flow: row nowrap;
flex-basis: 33%; # Calculate width from there.
flex-grow:1; #Allow resizing bigger
flex-shrink:1; #Allow resize smaller.
max-width:50%; #Adjust to your liking
min-width:25%; #Adjust o your liking
}
Please consider this ressource https://css-tricks.com/snippets/css/a-guide-to-flexbox/
You can add a flex-basis to the .row items by doing this:
.row {
flex-basis:calc(100% / 3);
}
.container {
width: 100%;
}
.row {
display: flex;
width: 100%;
}
.row div {
flex-grow: 1;
flex-basis: calc(100% / 2);
padding:10px;
margin: 5px;
background: #eee;
}
<div class="container">
<div class="row">
<div>1000</div>
<div>mary</div>
</div>
<div class="row">
<div>1</div>
<div>john</div>
</div>
<div class="row">
<div>11</div>
<div>mike</div>
</div>
</div>

Percentage widths in nested flexbox adds unexpected space

I noticed a weird bug in all the major browsers when you use a percentage width on an element in a nested flexbox with its justify-content property set to "flex-end". It renders the parent element as if the child were set to 100% width regardless of the percentage actually used by the child.
I have created a Fiddle to demonstrate the issue: https://jsfiddle.net/u21pe916/
HTML
<div class="wrapper">
<div class="flex-col-1">Column 1</div>
<div class="flex-col-2">
<div class="nested-col-1" id="percent-width">Nested Column 1</div>
<div class="nested-col-2">Nested Column 2</div>
</div>
</div>
<div class="wrapper">
<div class="flex-col-1">Column 1</div>
<div class="flex-col-2">
<div class="nested-col-1" id="unit-width">Nested Column 1</div>
<div class="nested-col-2">Nested Column 2</div>
</div>
</div>
CSS
.wrapper {
display: flex;
justify-content: flex-end;
}
.flex-col-2 {
display: flex;
justify-content: flex-end;
}
.nested-col-1 {
/* Overflow is for display purposes. It does not affect the bug. */
overflow: hidden;
}
#percent-width {
width: 0%;
}
#unit-width {
width: 0px;
}
Screenshot
Is there a fix/work-around so that percentage values can be used without creating the extra space?

How to equalise sibling div heights?

<div class="wrapper">
<div class="sidebar-wrapper"></div>
<div class="content-wrapper"></div>
</div>
The height of content-wrapper is dynamic (auto). Is there any way to get the height of it and use it for the sidebar-wrapper so that it looks nice?
Displaying them like table cells would do it. Table cells can adjust their height automatically to the content, and all cells on the same row get the same height. If you give the side bar a fixed width (which is likely), you can easily get the content wrapper to fill the remaining space.
Whichever has the longest content will determine the height.
.wrapper {
width: 100%;
display: table;
}
.sidebar-wrapper,
.content-wrapper {
display: table-cell
}
.sidebar-wrapper {
width: 200px;
background-color: silver;
}
.content-wrapper {
background-color: yellow;
}
<div class="wrapper">
<div class="sidebar-wrapper">Here is <br>content<br>that is .....<br><br><br><br><br><br>Quite long</div>
<div class="content-wrapper">Smaller content</div>
</div>
Flexbox is an alternative to #GolezTrol's CSS tables.
.wrapper {
display: flex;
}
.sidebar-wrapper {
width: 200px;
background-color: silver;
}
.content-wrapper {
background-color: yellow;
flex: 1;
}
<div class="wrapper">
<div class="sidebar-wrapper">Here is
<br>content
<br>that is .....
<br>
<br>
<br>
<br>
<br>
<br>Quite long</div>
<div class="content-wrapper">Smaller content</div>
</div>

Resources