Flex items not wrapping correctly inside my flex contianer - css

I want all items to be equally wide (as wide as the widest item) and wrap to the next line when there is no more space. My following code is however not working because the width of the items is just being set to 1/7th of the container instead of the width of the content inside it. How can I fix?
.flex-container {
display: flex;
flex-wrap: wrap;
background-color: rgba(255, 0, 0, 0.3);
max-width: 25rem;
gap: 1rem;
padding: 1rem;
}
.flex-item {
flex: 1 1 auto;
width: 0;
box-sizing: border-box;
background: rgba(0, 0, 255, 0.3);
}
<div class='flex-container'>
<div class='flex-item'>A</div>
<div class='flex-item'>AB</div>
<div class='flex-item'>ABC</div>
<div class='flex-item'>ABCD</div>
<div class='flex-item'>ABCDE</div>
<div class='flex-item'>ABCDEF</div>
<div class='flex-item'>ABCDEFG</div>
</div>

Set max-width value in flex-basis property
.flex-container {
display: flex;
flex-wrap: wrap;
background-color: rgba(255, 0, 0, 0.3);
max-width: 25rem;
gap: 1rem;
padding: 1rem;
}
.flex-item {
flex-basis: 8ch;
box-sizing: border-box;
background: rgba(0, 0, 255, 0.3);
}
<div class='flex-container'>
<div class='flex-item'>A</div>
<div class='flex-item'>AB</div>
<div class='flex-item'>ABC</div>
<div class='flex-item'>ABCD</div>
<div class='flex-item'>ABCDE</div>
<div class='flex-item'>ABCDEF</div>
<div class='flex-item'>ABCDEFG</div>
</div>

Related

How can I achieve a reversed stack of elements in a scrollable container in Google Chrome?

I have achieved the effect I desire with the code below, but it only seems to work in Firefox and Edge. In Chrome, the elements are stacked as desired, but there is no horizontal scroll bar so the right most items are hidden and inaccessible to the user.
As you can see, the header and footer stay in place and the my-app element is the only part that is scrollable. The items on the left appear above the ones to the right and the items all the way to the right are available through scrolling.
body {
margin: 0;
height: 100vh;
}
my-app {
display: flex;
height: 100vh;
flex-direction: column;
}
header, footer {
height: 25px;
background-color: black;
color:white;
}
main {
display: flex;
flex-direction: row-reverse;
flex-grow: 1;
justify-content: flex-end;
margin: 0;
overflow-x: auto;
width: 100vw;
}
.card {
--card-height: 200px;
--card-width: 250px;
align-items: center;
background: linear-gradient(rgba(179, 156, 95, 1), rgba(150, 117, 24, 1));
border-radius: 5px;
box-shadow: 1.5rem 0 2rem #222;
color: #000;
display: flex;
flex-direction: column;
height: var(--card-height);
justify-content: center;
min-width: var(--card-width);
position: relative;
text-align: center;
transition: all .15s ease-in-out;
transition: margin .3s ease-in-out;
width: var(--card-width);
}
.card:not(:last-of-type) {
margin-left: calc(var(--card-width) * -.5);
}
.card:hover:not(:last-of-type) {
margin-left: 0;
}
<my-app>
<header>Header</header>
<main>
<div class="card">1</div>
<div class="card">2</div>
<div class="card">3</div>
<div class="card">4</div>
<div class="card">5</div>
<div class="card">6</div>
<div class="card">7</div>
<div class="card">8</div>
<div class="card">9</div>
<div class="card">10</div>
<div class="card">11</div>
<div class="card">12</div>
<div class="card">13</div>
<div class="card">14</div>
<div class="card">15</div>
</main>
<footer>Footer</footer>
</my-app>
If I change the css applied to main to:
main {
...
flex-direction: row;
...
justify-content: flex-start;
...
}
Then the scroll bar appears, but the items aren't stacked correctly(the ones on the right overlay the ones on the left).
If I go one step further and add direction: rtl; to the main style as well, the layout works as expected, but the default scroll position is all the way to the right of the screen(which makes sense). I could probably keep this and add some javascript to change the scroll location on page load, but that all seems quite hacky. Is there a better way to achieve the layout I'm looking for that will work in Chrome, Firefox and Edge?
Looks like an additional wrapper solves your problem:
body {
margin: 0;
height: 100vh;
}
my-app {
display: flex;
height: 100vh;
flex-direction: column;
}
header,
footer {
height: 25px;
background-color: black;
color: white;
}
main {
flex-grow: 1;
margin: 0;
overflow-x: auto;
width: 100vw;
}
.wrapper {
display: flex;
flex-direction: row-reverse;
justify-content: flex-end;
}
.card {
--card-height: 200px;
--card-width: 250px;
align-items: center;
background: linear-gradient(rgba(179, 156, 95, 1), rgba(150, 117, 24, 1));
border-radius: 5px;
box-shadow: 1.5rem 0 2rem #222;
color: #000;
display: flex;
flex-direction: column;
height: var(--card-height);
justify-content: center;
min-width: var(--card-width);
position: relative;
text-align: center;
transition: all .15s ease-in-out;
transition: margin .3s ease-in-out;
width: var(--card-width);
}
.card:not(:last-of-type) {
margin-left: calc(var(--card-width) * -.5);
}
.card:hover:not(:last-of-type) {
margin-left: 0;
}
<my-app>
<header>Header</header>
<main>
<div class="wrapper">
<div class="card">1</div>
<div class="card">2</div>
<div class="card">3</div>
<div class="card">4</div>
<div class="card">5</div>
<div class="card">6</div>
<div class="card">7</div>
<div class="card">8</div>
<div class="card">9</div>
<div class="card">10</div>
<div class="card">11</div>
<div class="card">12</div>
<div class="card">13</div>
<div class="card">14</div>
<div class="card">15</div>
</div>
</main>
<footer>Footer</footer>
</my-app>

Setting two collapsing columns in a row equal in width, with a center column that shrinks and grows to fit content

I'm trying to achieve a certain column layout in CSS. I've explored using Flexbox as well as CSS Grid, but all of my peers I've talked to cannot figure out a way to make this work. I know I can achieve it using JavaScript, but I'd like to avoid that if at all possible.
I want to create a layout of three columns. Column 1 and Column 3 should be matching in width (defined by the content of the longer column), and column 2 should shrink and grow to allow content to fit (but not expand to fill the parent container).
It's a bit difficult to paint a picture of what I'm going for, so please take a look at this CodePen where I've broken down the rudimentary code and showed a mocked up example of what I'm going for.
Here's the HTML structure
<div class="container">
<div class="col col--Z">Let's match cols, but also collapse!</div>
<div class="col col--Y">No! 😣 Let me shrink!</div>
<div class="col col--Z">Yes!</div>
</div>
And here's the SCSS structure
.container {
display: grid;
justify-content: center;
grid-template-columns: 1fr auto 1fr;
.col {
padding-left: 6px;
padding-right: 6px;
&.col--Z {
background: rgba(0,255,55,0.2);
}
&.col--Y {
background: rgba(0,0,255,0.2);
}
}
}
* {
font-family: 'Arial', Sans-Serif;
}
.container {
display: grid;
justify-content: center;
grid-template-columns: 1fr auto 1fr;
}
.container .col {
padding-left: 6px;
padding-right: 6px;
}
.container .col.col--Z {
background: rgba(0, 255, 55, 0.2);
}
.container .col.col--Y {
background: rgba(0, 0, 255, 0.2);
}
.container-faked {
display: grid;
justify-content: center;
grid-template-columns: 260px auto 260px;
}
.container-faked .col {
padding-left: 6px;
padding-right: 6px;
}
.container-faked .col.col--Z {
background: rgba(0, 255, 55, 0.2);
}
.container-faked .col.col--Y {
background: rgba(0, 0, 255, 0.2);
}
<!-- This is the actual code -->
<h1>CSS Grid Attempt (actual code)</h1>
<div class="container">
<div class="col col--Z">Let's match cols, but also collapse!</div>
<div class="col col--Y">No! 😣 Let me shrink!</div>
<div class="col col--Z">Yes!</div>
</div>
<br>
<hr>
<br>
<!-- This is the objective, mocked up! -->
<h1>CSS Grid Attempt (faked example)</h1>
<div class="container-faked">
<div class="col col--Z">Let's match cols, but also collapse!</div>
<div class="col col--Y">No! 😣</div>
<div class="col col--Z">Yes!</div>
</div>
And the CodePen containing both the rudimentary code (not working) as well as the mocked up example of what I'd like to achieve, but using fixed pixel values to simulate equal width columns.
https://codepen.io/seanmaisch/pen/MZdqoW
You can use display: inline-grid to make grid container width according to content. To center it you can use some .wrapper block.
* {
font-family: 'Arial', Sans-Serif;
}
.wrapper {
display: flex;
justify-content: center;
}
.container {
display: inline-grid;
grid-template-columns: 1fr auto 1fr;
}
.container .col {
padding-left: 6px;
padding-right: 6px;
}
.container .col.col--Z {
background: rgba(0, 255, 55, 0.2);
}
.container .col.col--Y {
background: rgba(0, 0, 255, 0.2);
}
<div class="wrapper">
<div class="container">
<div class="col col--Z">Let's match cols, but also collapse!</div>
<div class="col col--Y">No! 😣 Let me shrink!</div>
<div class="col col--Z">Yes!</div>
</div>
</div>

Bootstrap 4.2.1 Flex-box layout column overflowing browser edge

Using flex-basis for column widths. Why does COLUMN02 extend beyond the browser's edge? What am I doing wrong? Unfortunately it does not show in the code snippets here but it does in the the fiddle. TIA!
http://jsfiddle.net/dragontheory/37b8vkoa/1/
html,
body {
min-height: 100vh;
/* force footer to bottom of browser */
height: 100%;
/*for IE11*/
}
.page-header,
.page-footer {
padding: 20px 10px;
background-color: rgba(0, 0, 0, 0.3);
}
.column01 {
-webkit-box-flex: 0 0 200px;
-ms-flex: 0 0 200px;
flex: 0 0 200px;
background-color: rgba(0, 0, 0, 0.1);
}
.column02 {
-webkit-box-flex: 0 0 auto;
-ms-flex: 0 0 auto;
flex: 0 0 auto;
background-color: rgba(0, 0, 0, 0.2);
}
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body class="container-fluid d-flex flex-column px-0">
<div class="page-footer p-2">HEADER</div>
<main class="row flex-fill no-gutters flex-nowrap">
<div class="col column01 d-flex flex-column">COLUMN01</div>
<div class="col column02 d-flex flex-column">COLUMN02</div>
</main>
<div class="page-footer p-2">FOOTER</div>
</body>
It's your custom CSS that's causing it:
.column02 {
flex: 0 0 auto;
}
.col {
width: 100%;
}
... which translates into:
flex-grow: 0 (do not allow flex to grow this element)
flex-shrink: 0 (do not allow flex to shrink this element)
flex-basis: auto (get flex-basis from width - which is set to 100% by .col)
Which blocks the width of that column to the width of its parent and does not allow it to shrink down, regardless of the fact the sum of the children's widths exceeds the width of the parent.
Setting any of the following on .column02 will fix it:
flex-shrink: 1
width: auto; flex-grow: 1;
flex-basis: 0; flex-grow: 1;
flex: 1;
Or simply remove flex: 0 0 auto; (because .col already sets flex-basis: 0; flex-grow: 1; - third case above).
Addition:
For your resizable panels to work, I recommend placing the entire required markup inside one column:
$(function() {
$(".panel-left").resizable({
handleSelector: ".splitter",
resizeHeight: false
});
})
html,
body {
min-height: 100vh;
height: 100%;
}
.page-header,
.page-footer {
padding: 20px 10px;
background-color: rgba(0, 0, 0, 0.3);
}
.panel-left {
flex: 0 0 auto;
padding: 10px;
width: 300px;
min-height: 200px;
min-width: 210px;
white-space: nowrap;
background: #838383;
color: white;
}
.splitter {
flex: 0 0 auto;
width: 18px;
background: url(https://raw.githubusercontent.com/RickStrahl/jquery-resizable/master/assets/vsizegrip.png) center center no-repeat #535353;
min-height: 120px;
cursor: col-resize;
}
.panel-right {
flex: 1 1 auto;
padding: 10px;
width: 100%;
min-height: 200px;
min-width: 200px;
background: #eee;
}
.panel-container {
display: flex;
flex-direction: row;
border: 1px solid silver;
overflow: hidden;
xtouch-action: none;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js"></script>
<script src="https://rawgit.com/RickStrahl/jquery-resizable/master/src/jquery-resizable.js"></script>
<body class="container-fluid d-flex flex-column px-0">
<div class="page-footer p-2">HEADER</div>
<main class="row flex-fill no-gutters flex-nowrap">
<div class="col panel-container">
<div class="panel-left">
left panel
</div>
<div class="splitter">
</div>
<div class="panel-right">
right panel
</div>
</div>
</main>
<div class="page-footer p-2">FOOTER</div>
</body>

How to force flex children not to overflow the container?

Given a flexbox container, how could I make sure that, if children have lots of content, they don't overflow the container?
.container {
display: flex;
flex-direction: column;
background-color: #ccc;
height: 210px;
width: 200px;
}
.child {
display: flex;
width: 100px;
}
.first {
background-color: rgba(255, 0, 0, 0.2);
}
.second {
background-color: rgba(0, 255, 0, 0.2);
}
.third {
background-color: rgba(0, 0, 255, 0.2);
}
<div class="container">
<div class="first child">first first first first first first first</div>
<div class="second child">second second second second second second second second second second second second second second second second second second second</div>
<div class="third child">third</div>
</div>
The children overflow their parent element because their intrinsic height (the height of their contents) is larger than the parent's height. You can advise the browser to ignore the intrinsic height by setting min-height: 0 on the child elements. If you add overflow: hidden the result should be what you seem to expect:
.container {
display: flex;
flex-direction: column;
background-color: #ccc;
height: 210px;
width: 200px;
}
.child {
width: 100px;
min-height: 0;
overflow: hidden;
}
.first {
background-color: rgba(255, 0, 0, 0.2);
}
.second {
background-color: rgba(0, 255, 0, 0.2);
}
.third {
background-color: rgba(0, 0, 255, 0.2);
}
<div class="container">
<div class="first child">first first first first first first first</div>
<div class="second child">second second second second second second second second second second second second second second second second second second second</div>
<div class="third child">third</div>
</div>
The children get height distributed among them proportionally to their content height. Overflowing content is hidden.
You could use overflow: auto on child element. In case you want to hide overflow only on largest item then you could use flex: 1 on that item.
.container {
display: flex;
flex-direction: column;
background-color: #ccc;
height: 210px;
width: 200px;
}
.child {
display: flex;
width: 100px;
overflow: auto;
}
.first {
background-color: rgba(255, 0, 0, 0.2);
}
.second {
background-color: rgba(0, 255, 0, 0.2);
flex: 1;
}
.third {
background-color: rgba(0, 0, 255, 0.2);
}
<div class="container">
<div class="first child">first first first first first first first</div>
<div class="second child">second second second second second second second second second second second second second second second second second second second</div>
<div class="third child">third</div>
</div>
flex has
Three values: flex-grow | flex-shrink | flex-basis;
you should apply particular max-height for first child.
.first {
background-color: rgba(255, 0, 0, 0.2);
flex: 0 1 1;
max-height:70px;
}
otherwise if first div height increases it will dominate on other divs.
.container {
display: flex;
flex-direction: column;
background-color: #ccc;
height: 210px;
width: 200px;
}
.child {
width: 100px;
overflow:hidden;
}
.first {
background-color: rgba(255, 0, 0, 0.2);
flex: 0 1 auto;
}
.second {
background-color: rgba(0, 255, 0, 0.2);
flex: 0 1 1;
}
.third {
background-color: rgba(0, 0, 255, 0.2);
flex: 0 1 1;
}
<div class="container">
<div class="first child">first first first first first first first</div>
<div class="second child">second second second second second second second second second second second second second second second second second second second</div>
<div class="third child">third</div>
</div>
Using min-height: 210px; instead of explicitly setting a height on your container gives you the desired affect by letting an extra long child to extend its height.
Also, great question writing! Nice to see diagrams of whats happening vs expected, ect.

Flex CSS: preserving div aspect ratio cross-browser

I need to preserve the aspect ratio of several divs using flex, cross browser. The divs contain charts and diagrams as SVGs, not IMGs.
I have a preferred solution working in firefox (https://jsfiddle.net/2d5hcfbo/4/), and another working in IE (https://jsfiddle.net/229oo3br/2/), but neither solution works in both. These were based on this answer. When looking at the Jsfiddles, if you increase the width of the output window (by dragging the middle column boundary to the left) you'll see the yellow divs turn pink and a Filter column is added (#media queries).
In both cases, the problem is that the divs seem to default to text height + padding. They need to stay oblong, broadly 1.5 times as wide as high. Also in IE the divs overlap each other and the font aligns low.
The FF solution uses flex-basis: 30vw; to set the height based on the width (flex-direction = column). (Height: 30vw doesn't work, not sure why.) This works in Chrome too.
The IE solution uses padding-top: 16.67%; to affect the height. This method has never been intuitive to me but I'd use it if it worked in FF.
I'm using IE 11 and FF45.9. I understand IE11 has/had a bug in this area(https://github.com/philipwalton/flexbugs/issues/71) but I can't avoid the browser. Thanks for any help!
Edit: I can make both declarations. But is there a better way?
CSS:
div#container {
/*position: relative;*/
padding-top: 50px;
display: flex;
/*flex-direction: row wrap;*/
/*align-items: stretch;*/
}
div#column1 {
flex: 0 0 auto;
background-color: white;
box-shadow: 3px 0px 10px #bebebe;
z-index: 9999;
overflow-y: scroll;
}
div#column2 {
display: flex;
flex-direction: column;
}
.row { display: flex; }
.row--top { flex: 2;}
.row--bottom { flex: 1; }
.cell {
flex: 1;
padding: 0.5em;
background-color: white;
margin: 1em;
box-shadow: rgba(0, 0, 0, 0.12) 0px 1px 6px, rgba(0, 0, 0, 0.12) 0px 1px 4px;
}
.cell-wrap {
flex-basis: 31%;
display: flex;
flex-direction: column;
}
.cell-wrap div {
margin-left:0;
}
div.row--top div#cell1,
div.row--top div.cell-wrap div {
margin-bottom: 0;
}
div.fullwidth { width: 100%; }
div.fullheight { height: 100%; }
#media screen and (max-width: 1100px) {
#container {
height: auto;
}
.row { flex-direction: column; }
.cell {
flex-grow: 1;
background-color: pink;
/* flex-basis: 30vw; */
padding-top: 16.67%;
}
/*.flex.padding div {
padding-top: 16.67%;
}*/
#cell4 {
margin-bottom: 0;
}
.cell-wrap {
width: 100%;
flex-direction: column;
}
.cell-wrap div {
margin-left:1em;
}
}
#media screen and (max-width: 700px) {
.cell {
/*flex-grow: 0;*/
background-color: yellow;
padding-top: 16.67%;
/* flex-basis: 50vw; */
}
div#column1 {
display: none;
}
}
HTML:
<div id="container" class="fullheight fullwidth">
<div class="fullheight" id="column1">
<div id="filterRow">
<div class="selectHolder" id="filters"><h1>Filter</h1><div class="spanHolder">
</div></div>
</div>
</div>
<div class="fullheight fullwidth" id="column2">
<div class="row row--top">
<div class="cell" id="cell1">cell one</div>
<div class="cell-wrap">
<div class="cell" id="cell2">cell two</div>
<div class="cell" id="cell3">cell three</div>
</div>
</div>
<div class="row row--bottom">
<div class="cell" id="cell4">cell four</div>
<div class="cell-wrap">
<div class="cell" id="cell5">cell five</div>
</div>
</div>
<!-- </div> -->
</div>
</div>
Perhaps IE requires re-declaration of the default flex property within media queries. Adding back default declaration flex: 0 1 auto did the trick.
Thanks to Michael_B for the pointer. Fix here: https://jsfiddle.net/2d5hcfbo/9/

Resources