Flex-box with child with overflow-x:auto and flex-grow:1 - html

I'm trying to create a header with some items in a flex-box.
One of these items is a div "box" with flex-grow:1 to fill the remaining space of the line.
The div "box" has overflow-x: auto to create a horizontal scroll if necessary.
The problem is that if I do not set a max-width, the scroll of the div "box" does not appears and some items of the container go out of the container bounds...
I want to use all the remaining space used by the flex-grow:1. How can I solve this?
JSFiddle
.container {
display: flex;
width: 400px;
background-color: #fff;
}
.container > div {
flex-shrink: 0;
}
.box {
flex-grow: 1;
border: 1px solid #ff0000;
display: flex;
overflow-x: auto;
//max-width: 180px;
}
.scroll-box {
overflow-x: auto;
// max-width: 180px;
display: flex;
}
.box > div {
flex-shrink: 0;
width: 80px;
border: 1px solid black;
margin: 2px;
padding: 2px;
}
<div class="container">
<div>element1</div>
<div class="box">
<div>A</div>
<div>B</div>
<div>C</div>
<div>D</div>
</div>
<div>element 2</div>
<div>element 3</div>
</div>

Instead of flex-grow: 1 use flex: 1.
When you use flex-grow you set that particular property. But the other flexibility properties remain their default values. Namely, flex-shrink: 0 and flex-basis: auto.
With flex: 1, you're switching to:
flex-grow: 1
flex-shrink: 1
flex-basis: 0
So, the box is now allowed to shrink. But, more importantly, instead of the width of the box being auto (content-driven) it starts from 0. This is what enables the scroll function.

Related

Flex box isn't filling remaining space when using flex-grow 1

I am trying to fill the remaining space of a containing flex box with the green div. I want the top flex row (blue) to only be the height of its contents and then the row below (green) to fill the rest. For some reason it just seems to split the flex rows evenly down the div. I have read a few questions on here already which all say to make sure the containing div has its height set to 100%. I have set the containing div height to 200px as this is my desired height, but I have also tried adding another container within this to 100% to no avail. I've also made sure to set the flex-grow property on the second row to 1. Every time I think I'm beginning to understand flex it throws another curve ball and it's driving me up the wall. Please help! Thank you.
P.S. for some reason the HTML code snippet below refuses to include the first line of my html but it is contained in the following div: <div class="rmCtrlList_item"
.rmCtrlList_item {
width: 80vw;
margin: 3vw 8.5vw;
height: 200px;
background-color: $primary-color;
border-radius: 10px;
padding: 5px;
display: flex;
flex-flow: row;
flex-wrap: wrap;
// ROWS
&_row {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
#row-1 {
//max-height: 20px;
background-color: blue;
}
#row-2 {
flex-grow: 1;
align-items: center;
justify-content: center;
background-color: green;
}
// COLUMNS
&_col {
text-align: left;
flex-direction: column;
}
#col-1b {
flex-grow: 1;
}
}
<div class="rmCtrlList_item">
<div class="rmCtrlList_item_row" id="row-1">
<div class="rmCtrlList_item_col" id="col-1a">
<i class="icon__panel-2 fas fa-lightbulb"></i>
</div>
<div class="rmCtrlList_item_col" id="col-1b">
<a href="lights.html">
<h1 class="panel__title">Lights</h1>
</a>
</div>
<div class="rmCtrlList_item_col" id="col-1c">
<i class="icon__enlarge fas fa-plus-circle"></i>
</div>
</div>
<div class="rmCtrlList_item_row" id="row-2">
div to fill remaining space
</div>
</div>
how about to use flex-direction and below code what I used? green will fill ramaining space automatically, if you use its height's 100%
.container{
display: flex;
flex-direction: column;
width: 200px;
height: 300px;
border: 1px solid black;
}
.blue{
width: 100%;
height: 90px; /*change only blue's height size, green will be filled automatically*/
background: blue;
}
.green{
width: 100%;
height: 100%;
background: green;
}
<div class="container">
<div class="blue"></div>
<div class="green"></div>
</div>

Flexbox children shrink up to a certain point (but don't expand if they don't need to)

I'm a having a bit of an issue here. I have a flexbox container with children of different sizes. Based on quantity and their content children might overflow the parent.
What I want is the children to shrink so they try to fit in the parent container. I did that by adding shrink and overflow properties to the children. So far so good.
.container > div {
background-color: orange;
padding: 5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex-shrink: 1;
}
I end up with something like this:
Now I want them to shrink but up to a certain point (lets say 80px). I don't care if they end up overflowing the container but I don't want to render any smaller than 80px.
Of course, I added min-width: 80px to the children... but here is my problem. I want the children to shrink up to 80px but I don't want any of those that were smaller than 80px already (like Child1, Child4 and Child5) I don't want them to be enlarged by the min-width property (or, I want them to shrink further up to min-content)
In other words. I don't want this:
I would love to have something like this:
I tried doing something like min-width: min(min-content, 80px) but of course, didn't work.
Here is an small codepen with the issue: https://codepen.io/claudiofpen/pen/QWELVJO
.container {
width: 300px;
border: 1px solid black;
display: flex;
flex-direction: row;
padding: 5px;
}
.container > div {
background-color: orange;
padding: 5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex-shrink: 1;
min-width: min-content;
}
.container > div:not(:last-child) {
margin-right: 5px;
}
/* I don't want the following css classes, I cannot
tell in before hand which children are going to have
a larger content */
.container > div:nth-child(2),
.container > div:nth-child(3) {
min-width: 80px;
}
<div class="container">
<div>Child 1</div>
<div>Longer Child 2</div>
<div>Longer Child 3</div>
<div>Child 4</div>
<div>Child 5</div>
</div>
Temani Afif's solution solves the problem of ensuring that a text element will not shrink below the specified width unless its intrinsic width is already below that width (in which case it uses its intrinsic width as the rendered width). But it does not work unless the sum of the specified widths of all the child elements exceeds the container's width.
So I tried giving each outer elements a flex-grow parameter, so that they would grow above their specified width, if the container had room. But I also give the outer elements a maximum width set to their intrinsic maximum content width, so they would never grow beyond the actual size of the text. Thus I added the following styles to the wrapping div.
flex: 1 1 auto;
max-width: max-content;
With that tweak I believe it solves the entire problem. The elements expand fully if there is room in the container. As we add more elements the longer elements start to shrink. But they never shrink below their specified width, so the container overflows once all inserted elements have shrunk down to that width. But elements that started with a shorter width never flex at all.
I have added an example below.
.container {
width: 340px;
border: 1px solid black;
display: flex;
flex-direction: row;
padding: 5px;
}
.container>div {
background-color: orange;
padding: 5px;
flex: 1 1 auto;
width: 80px;
max-width: max-content;
}
.container>div>div {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
width: 100%;
}
.container>div:not(:last-child) {
margin-right: 5px;
}
<h5>When the items fit they expand to their intrinsic length</h5>
<div class="container">
<div>
<div>Medium length</div>
</div>
<div>
<div>Tiny</div>
</div>
<div>
<div>Longer text element</div>
</div>
</div>
<h5>When the container limit is reached the longer elements start shrinking</h5>
<div class="container">
<div>
<div>Medium length</div>
</div>
<div>
<div>Tiny</div>
</div>
<div>
<div>Longer text element</div>
</div>
<div>
<div>Filler</div>
</div>
</div>
<h5>Adding more elements...</h5>
<div class="container">
<div>
<div>Medium length</div>
</div>
<div>
<div>Tiny</div>
</div>
<div>
<div>Longer text element</div>
</div>
<div>
<div>Filler</div>
</div>
<div>
<div>Filler</div>
</div>
</div>
<h5>When there is no room it overflows<br> The tiny element stays at its intrinsic width, but the bigger elements stop shrinking at the specified width</h5>
<div class="container">
<div>
<div>Medium length</div>
</div>
<div>
<div>Tiny</div>
</div>
<div>
<div>Longer text element</div>
</div>
<div>
<div>Filler</div>
</div>
<div>
<div>Filler</div>
</div>
<div>
<div>Filler</div>
</div>
</div>
With an extra wrapper you can do it:
.container {
width: 300px;
border: 1px solid black;
display: flex;
flex-direction: row;
padding: 5px;
}
.container > div {
background-color: orange;
padding: 5px;
flex-shrink: 1;
width: 80px;
}
.container > div > div {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
width: 100%;
}
.container > div:not(:last-child) {
margin-right: 5px;
}
<div class="container">
<div><div>Ch 1</div></div>
<div><div>Longer Child 2</div></div>
<div><div>Longer Child 3</div></div>
<div><div>Child 4</div></div>
<div><div>Child 5</div></div>
</div>
Grid Solution
.container {
width: 300px;
border: 1px solid black;
display: grid;
grid-template-columns: max-content 80px 80px repeat(2,max-content);
padding: 5px;
}
You can use javascript to make the grid-template-column dynamic.
Here is the jquery (javascript) solution using flex
.container {
width: max-content;
border: 1px solid black;
display: flex;
padding: 5px;
}
$(".container > div").each(function(){
($(this).width() < 50) ?
$(this).css('width','max-content') :
$(this).css('flex','0 0 80px');
})
This is more dynamic than the grid solution. The only thing is that you will need to have a desired number in $(this).width() < 50 instead of fifty based on your content.

Can I Left justify and Center justify two objects inside the same flex container? [duplicate]

This question already has answers here:
Fill the remaining height or width in a flex container
(2 answers)
Closed 2 years ago.
I have a flex-container(row), where Im looking for the first object to be left justified at a static width, and then for the next object to be centered and fill the remainder of the container.
[ (obj1) | <----------(obj2)---------> ]
I know that I could accomplish this easier with the grid styling below, but my goal here is to educate myself in flex.
display:grid;
grid-template-columns: 100px 1fr;
Thanks!
Please see the code snippets for the flex implementation.
.wrapper {
display: flex;
}
.obj-a {
background: lime;
flex-basis: 100px;
}
.obj-b {
background: skyblue;
flex-grow: 1;
display: flex;
justify-content: center;
}
<div class="wrapper">
<div class="obj-a">obj-a</div>
<div class="obj-b">obj-b</div>
</div>
yes this can be done in flex
best read is here
you need to use
flex-shrink, flex-grow, flex-basis the short form as below
flex: shrink grow basis ie. flex: 1 1 auto
below is the example I use flex short-form and added a border for representation purposes.
* {
borx-sizing: border-box;
}
.flex-container {
display: flex;
flex-direction: row;
border: 1px solid black;
height: 200px;
padding: 1em;
}
.flex-container .left {
width: 100px;
border: 2px solid red;
height: 200px;
}
.flex-container .main {
flex: 1 1 auto;
border: 2px solid green;
height: 200px;
}
<div class="flex-container">
<div class="left"></div>
<div class="main"></div>
</div>

Flex grid with odd numbers of items and fixed margin between

Ok this is giving me quite an headache...
this is my code/example
https://codepen.io/anon/pen/xXpjYa
.flex {
display: flex;
flex-wrap: wrap;
}
.imageContainer {
flex: 1 0 30%;
height: 200px;
border: 5px solid black;
background-color: deeppink;
margin:15px;
}
.imageContainer:empty {
height: 0;
border: none;
};
<div class="flex">
<div class="imageContainer">a</div>
<div class="imageContainer">a</div>
<div class="imageContainer">a</div>
<div class="imageContainer">a</div>
<div class="imageContainer"></div>
<div class="imageContainer"></div>
</div>
the problem is that I want to achieve/fix two things:
the far left and far right column should be touching the edge of the viewport
the fixed gap should be 30px and only the pink boxes stretch responsively
notice the last item (5) is slightly wider than the others...why??
please help! thanks!
You set the margin to be 15px, on .imageContainer this applies to all sides, including the sides between these imageContainers and the viewport. So basically your first ask and your second ask are fighting against each other.
You can set a margin on .imageContainer and a negative margin on the parent .flex to accomplish both.
The last visible item is longer because the two divs following it are collapsing and not showing, which affects the layout. If you add the css attribute box-sizing: border-box to your .imageContainer rule, it will fix this issue. You can also assigned a fixed height to .imageContainer, or add content to all of the .imageContainer divs to prevent this from happening.
See this codepen for the modified code.
Instead of margin use justify-content: space-between and set flex: 0 0 30% instead of flex: 1 0 30%. Last item is bigger because there is no border on other two.
body {
margin: 0;
}
.flex {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.imageContainer {
flex: 0 0 30%;
height: 200px;
border: 5px solid black;
background-color: deeppink;
margin: 15px 0;
}
.imageContainer:empty {
height: 0;
border: none;
}
<div class="flex">
<div class="imageContainer">a</div>
<div class="imageContainer">a</div>
<div class="imageContainer">a</div>
<div class="imageContainer">a</div>
<div class="imageContainer"></div>
<div class="imageContainer"></div>
</div>

achieving equal height columns with flexbox

I am trying to build a layout which has two separate content groups: one on the left side and right side, with fixed width (20%/80%) for now. On each side, I am trying to arrange contents by using flexbox: left panel with flex-direction: column and right panel with flex-direction: row wrap. The number of contents on each side can be flexible. The panel with less contents should match the height of the other, 'taller' side.
So far, I was able to achieve the basic layout, as shown in this jsfiddle. However, my problem is that I cannot make the the 'shorter' panel to fill the height, even though I set the height to be 100%. In the given example, there is an empty space between 'C' div of left panel and 'Box7' div of the right panel. The html/css code is show below.
How could I fix this problem or is there nicer simpler layout solutions? Any help would be appreciated.
HTML
<div class='top'>
<div class='left'>
<div class='litem'>A</div>
<div class='litem'>B</div>
<div class='litem'>C</div>
</div>
<div class='right'>
<div class='ritem'>Box 1</div>
<div class='ritem'>Box 2</div>
<div class='ritem'>Box 3</div>
<div class='ritem'>Box 4</div>
<div class='ritem'>Box 5</div>
<div class='ritem'>Box 6</div>
<div class='ritem'>Box 7</div>
</div>
</div>
CSS
* { outline: 1px solid Grey; }
html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
background-color: Cornsilk;
}
.top {
margin: 0;
padding: 0;
display: flex;
flex-direction: row;
width: 100%;
height: 100%;
}
.left {
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
width: 20%;
height: 100%;
}
.right {
margin: 0;
padding: 0;
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 80%;
height: 100%;
}
.litem, .ritem {
margin: 0;
padding: 0;
}
.litem { height: 50%; }
.ritem { height: 50%; width: 33.3%;}
.litem:nth-child(1) { background-color: Cyan; }
.litem:nth-child(2) { background-color: DarkCyan; }
.litem:nth-child(3) { background-color: DarkSeaGreen; }
When you apply height: 100% to html and body, you limit the growth of the child elements to 100% of the screen.
In your code, your .left flex item is indeed stretching to height: 100%, as specified. Add a border around .left for an illustration: DEMO
If you remove all the fixed heights, you'll enable the flex container to stretch all flex items, per the default setting: align-items: stretch (the setting that creates equal height columns). DEMO
When you add flex: 1 to the .left flex items (.litem), they then distribute all available space in the container evenly among themselves. DEMO.
In a nutshell, when you use the height property you override align-items: stretch, the flex setting for equal height columns.