Shrink flexbox to the size of its children - html

I need to arrange a bunch of blocks of fixed size into a grid. I am using flex-wrap: wrap to get as many in each row as will fit. But, I would like this whole wrapped column to be centered in the page. Ideally, I would like it to look something like this:
But, in the snippet I have below, the green flexbox fills to fit any space it can, so all the blue boxes are pushed all the way to the left. I don't want to set the flexbox to a fixed width because I want it to be able to flow to fit as many boxes in a row as possible, but I just don't want it to take up any more space beyond that.
Obviously, I could use justify-content: center to center the boxes within the container, but the incomplete row at the bottom gets out of alignment, which I don't want.
Is there any way to achieve the effect I am looking for with CSS?
I saw this question which suggested using display: inline-flex. That does seem to work when you are not wrapping, but as soon as you put on flex-wrap: wrap and add enough items to make it wrap, it jumps back to filling the full width.
.page {
width: 100%;
background-color: pink;
padding: 10px;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
}
.flex-column {
display: flex;
flex-direction: row;
flex-wrap: wrap;
background-color: green;
justify-content: flex-start;
gap: 10px;
}
.flex-child {
display: block;
width: 200px;
height: 100px;
background-color: blue;
}
.button {
display: inline-block;
padding: 20px;
background-color: red;
}
.
<div class='page'>
<div class="flex-column">
<div class="flex-child"></div>
<div class="flex-child"></div>
<div class="flex-child"></div>
<div class="flex-child"></div>
<div class="flex-child"></div>
<div class="flex-child"></div>
<div class="flex-child"></div>
<div class="flex-child"></div>
</div>
<div class="button">Load more</div>
</div>

Since the width is always the same, CSS grid can help you here:
.page {
background-color: pink;
display: grid;
grid-template-columns:repeat(auto-fit,200px); /* same width as child */
gap:10px; /* the same gap here */
justify-content:center; /* center everything */
}
.flex-column {
display: flex;
flex-direction: row;
flex-wrap: wrap;
background-color: green;
grid-column:1/-1; /* take all the columns */
gap: 10px;
}
.flex-child {
width: 200px;
height: 100px;
background-color: blue;
}
.button {
padding: 20px;
background-color: red;
grid-column:1/-1; /* take all the columns */
margin:auto; /* center the button */
}
<div class='page'>
<div class="flex-column">
<div class="flex-child"></div>
<div class="flex-child"></div>
<div class="flex-child"></div>
<div class="flex-child"></div>
<div class="flex-child"></div>
<div class="flex-child"></div>
<div class="flex-child"></div>
<div class="flex-child"></div>
</div>
<div class="button">Load more</div>
</div>

In mine it is working like this you can see:
.page {
width: 100%;
background-color: pink;
padding: 10px;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
}
.flex-column {
display: flex;
flex-direction: row;
flex-wrap: wrap;
background-color: green;
justify-content: flex-start;
gap: 10px;
display: flex;
padding: 20px;
}
.flex-child {
display: block;
width: 200px;
height: 100px;
background-color: blue;
flex: 0 1 auto;
}
.button {
display: inline-block;
padding: 20px;
background-color: red;
}
.
<div class='page'>
<div class="flex-column">
<div class="flex-child"></div>
<div class="flex-child"></div>
<div class="flex-child"></div>
<div class="flex-child"></div>
<div class="flex-child"></div>
<div class="flex-child"></div>
<div class="flex-child"></div>
<div class="flex-child"></div>
</div>
<div class="button">Load more</div>
</div>

Related

Flex basis shrinks element but not parent

I am dealing with a flex-box issue. It seems that a flex item with flex basis is shrunk accordingly but the parent maintains its size as if the child still occupied its full size.
These two images are the exact same code except the .earnings-claim-wrapper in the second one does not have the flex property. The last image shows how chrome "represents" that empty space.
Expected behaviour:
I've reduced the code to this:
div{
padding:10px;
}
.earnings-container {
display: flex;
background-color: red;
}
.earnings-info-container {
background-color: orange;
}
.earnings-info {
display: flex;
flex-wrap: wrap;
justify-content: left;
align-items: flex-start;
background-color: green;
}
.earnings-info .earnings-claim {
align-self: flex-start;
background-color: yellow;
}
.earnings-claim-wrapper {
flex: 0 1 100px;
position: relative;
display: flex;
display: flex;
flex-direction: column;
background-color: purple;
}
<div class="earnings-container">
<div class="earnings-info-container">
<div class="earnings-info">
<div class="earnings-icon student-points"></div>
<div class="earnings-title">earnings-title</div>
<div class="earnings-claim-wrapper">
<div class="earnings-claim not-enough-effort">earnings-claim</div>
<span class="effort-message">Some long text text text text text text long text</span>
</div>
</div>
</div>
<div class="earnings-info-container">
<div class="earnings-info">
<div class="earnings-icon diamonds"></div>
<div class="earnings-title">earnings-title</div>
</div>
</div>
</div>
Instead of using flex: 0 1 100px; on earnings-claim-wrapper class, use width:100px;
div{
padding:10px;
}
.earnings-container {
display: flex;
background-color: red;
}
.earnings-info-container {
background-color: orange;
}
.earnings-info {
display: flex;
flex-wrap: wrap;
justify-content: left;
align-items: flex-start;
background-color: green;
}
.earnings-info .earnings-claim {
align-self: flex-start;
background-color: yellow;
}
.earnings-claim-wrapper {
width:100px;
position: relative;
display: flex;
display: flex;
flex-direction: column;
background-color: purple;
}
<div class="earnings-container">
<div class="earnings-info-container">
<div class="earnings-info">
<div class="earnings-icon student-points"></div>
<div class="earnings-title">earnings-title</div>
<div class="earnings-claim-wrapper">
<div class="earnings-claim not-enough-effort">earnings-claim</div>
<span class="effort-message">Some long text text text text text text long text</span>
</div>
</div>
</div>
<div class="earnings-info-container">
<div class="earnings-info">
<div class="earnings-icon diamonds"></div>
<div class="earnings-title">earnings-title</div>
</div>
</div>
</div>
I've got to be honest that I can't fully reproduce what happens in your code that makes .earning-info expand. But I did find out it has to do with setting a flex-basis on the .earnings-claim-wrapper elements.
Giving all it's parents a flex-basis as well did the trick here.
Also, I think you can remove some properties, I've commented them out in the snippet.
div{
padding:10px;
}
.earnings-container {
display: flex;
background-color: red;
}
.earnings-info-container {
flex: 0 1 1%;
background-color: orange;
display: flex;
align-items: flex-start;
}
.earnings-info {
flex: 0 1 1%;
display: flex;
/*flex-wrap: wrap;*/
/*justify-content: left;*/
/*align-items: flex-start;*/
background-color: green;
}
.earnings-info .earnings-claim {
/*align-self: flex-start;*/
background-color: yellow;
}
.earnings-claim-wrapper {
flex: 0 1 100px;
/*position: relative;
display: flex;*/
display: flex;
flex-direction: column;
background-color: purple;
}
<div class="earnings-container">
<div class="earnings-info-container">
<div class="earnings-info">
<div class="earnings-icon student-points">x</div>
<div class="earnings-title">earnings-title</div>
<div class="earnings-claim-wrapper">
<div class="earnings-claim not-enough-effort">earnings-claim</div>
<span class="effort-message">Some long text text text text text text long text</span>
</div>
</div>
</div>
<div class="earnings-info-container">
<div class="earnings-info">
<div class="earnings-icon diamonds">x</div>
<div class="earnings-title">earnings-title</div>
</div>
</div>
</div>

How to wrap last row of flexbox with "space-around"? [duplicate]

This question already has answers here:
Targeting flex items on the last or specific row
(10 answers)
Closed 3 years ago.
I am trying to create a Bootstrap-like grid of cards using CSS flex properties. I have 10 cards (4 each row). However, when using justify-content: space-around (this is what I need), the last row is not aligning with the others (naturally). What is the workaround?
.card-gallery {
width: 100%;
height: auto;
display: flex;
justify-content: space-around;
flex-wrap: wrap;
align-items: center;
flex-direction: row;
}
.card-box {
width: 270px;
height: 400px;
background: red;
}
<div class="container">
<div class="card-gallery">
<div class="card-box"></div>
<div class="card-box"></div>
<div class="card-box"></div>
<div class="card-box"></div>
<div class="card-box"></div>
<div class="card-box"></div>
<div class="card-box"></div>
</div>
</div>
You could try CSS :last-child as in the example below to use different style in your last div.
.flexbox {
display: flex;
flex-flow: column;
}
.flex-child {
background: red;
align-content: center;
align-self: center;
}
.flex-child:last-child {
align-content: space-around;
align-self: flex-start;
}
<div class="flexbox">
<div class="flex-child">
one
</div>
<div class="flex-child">
two
</div>
<div class="flex-child">
three
</div>
</div>
By the way space-between and applying relative width to your card div works better.
.card-gallery {
width: calc(100% -2rem);
height: auto;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
flex-direction: row;
padding: 1rem;
}
.card-box {
width: 45%;
height: 40px;
background: #ff0;
align-self: center;
}
div.card-box:last-child {
align-self: flex-start;
}
<div class="container">
<div class="card-gallery">
<div class="card-box">1</div>
<div class="card-box">2</div>
<div class="card-box">3</div>
<div class="card-box">4</div>
<div class="card-box">5</div>
<div class="card-box">6</div>
<div class="card-box">7</div>
</div>
</div>
You can't achieve this easily with flexbox.
Instead, set .card-gallery to display:grid to make sure the cards always line up in a grid formation when multiple rows exist. Then give it this style rule:
grid-template-columns: repeat(auto-fill, 120px)
The auto-fill keyword will make sure the items will wrap when the viewport shrinks:
.container{max-width:479px;background:lightblue}
.card-gallery {
width: 100%;
height: auto;
display: grid;
grid-template-columns: repeat(auto-fill, 120px);
justify-content: space-around;
}
.card-box {
height: 100px;
background: #fff;
margin-bottom:30px;
border:solid 2px dodgerblue
}
<div class="container">
<div class="card-gallery">
<div class="card-box">cb</div>
<div class="card-box">cb</div>
<div class="card-box">cb</div>
<div class="card-box">cb</div>
<div class="card-box">cb</div>
<div class="card-box">cb</div>
<div class="card-box">cb</div>
</div>
</div>

CSS flex grow does not work with added div on top

Consider the following fiddle: https://jsfiddle.net/7naxprzd/1/
Requirements are:
two columns with header and contents
tops of columns should align
bottom of columns should align
on top of each column there should be a horizontally centered arrow
The code is working properly if the arrows are eliminated by deleting the div with class .arrow-wrapper, but I need the arrows.
A solution could be to absolute position the arrow, but is there a way to solve this layout issue with flex without absolute positioning the arrow?
Should work for modern browsers and IE11.
.row-wrapper {
display: flex;
}
.col-wrapper-outer {
display: flex;
flex-wrap: wrap;
}
.arrow-wrapper {
width: 100%;
text-align: center;
font-size: 30px;
}
.col-wrapper {
width: 100%;
display: flex;
flex-direction: column;
border: 2px solid red;
color: white;
}
.col-wrapper .header {
background: blue;
}
.col-wrapper .contents {
flex: 1 0 auto;
background: green;
}
<div class="row-wrapper">
<div class="col-wrapper-outer">
<div class="arrow-wrapper">
↓
</div>
<div class="col-wrapper">
<div class="header">Please align tops.</div>
<div class="contents">Let me grow.</div>
</div>
</div>
<div class="col-wrapper-outer">
<div class="arrow-wrapper">
↓
</div>
<div class="col-wrapper">
<div class="header">please align tops.</div>
<div class="contents">Let me grow.<br>Please<br>align<br>bottoms.</div>
</div>
</div>
</div>
In your div with class col-wrapper-outer, instead of this:
.col-wrapper-outer {
display: flex;
flex-wrap: wrap;
}
Use this:
.col-wrapper-outer {
display: flex;
flex-direction: column;
}
Then add flex: 1 to .col-wrapper so it takes the full height of the container.
revised fiddle
.row-wrapper {
display: flex;
}
.col-wrapper-outer {
display: flex;
/* flex-wrap: wrap; */
flex-direction: column; /* NEW */
}
.arrow-wrapper {
width: 100%;
text-align: center;
font-size: 30px;
}
.col-wrapper {
flex: 1; /* NEW */
width: 100%;
display: flex;
flex-direction: column;
border: 2px solid red;
color: white;
}
.col-wrapper .header {
background: blue;
}
.col-wrapper .contents {
flex: 1 0 auto;
background: green;
}
<div class="row-wrapper">
<div class="col-wrapper-outer">
<div class="arrow-wrapper">
↓
</div>
<div class="col-wrapper">
<div class="header">Please align tops.</div>
<div class="contents">Let me grow.</div>
</div>
</div>
<div class="col-wrapper-outer">
<div class="arrow-wrapper">
↓
</div>
<div class="col-wrapper">
<div class="header">please align tops.</div>
<div class="contents">Let me grow.
<br>Please
<br>align
<br>bottoms.</div>
</div>
</div>
</div>

Use flexbox to center content while not making elements side by side

I am using flexbox to center content with justify-content: center which works as intended but flexbox also moves divs to be side by side which I don't want.
Here is an example
.flex {
display: flex;
justify-content: center;
}
.content {
width: 100px;
height: 100px;
background-color: #000;
margin: 10px;
}
<div class="flex">
<div class="content">
</div>
<div class="content">
</div>
</div>
How can I use flexbox while retaining the default one div on top of the other positioning.
You can set flex-direction: column and then you have to use align-items: center. Default flex-direction is row.
.flex {
display: flex;
align-items: center;
flex-direction: column;
}
.content {
width: 100px;
height 100px;
color: #000;
border: 1px solid black;
padding: 5px;
margin: 5px;
}
<div class="flex">
<div class="content"></div>
<div class="content"></div>
</div>
Try following code,
.flex {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
}
.content {
width: 100px;
height: 100px;
background-color: #000;
margin: 10px;
}
<div class="flex">
<div class="content">
</div>
<div class="content">
</div>
</div>

CSS: Flexbox within Flexbox

I was playing around with the flexboxes a little and wanted to combine a column and row container. The question I have is:
Why do the row elements placed within the column not span the entire width of the flex-container?
The example code is shown here: js-fiddle
HTML:
/* CSS: */
.flex-container {
color: blue;
background-color:yellow;
text-decoration: bold;
text-size: 1em;
display: flex;
justify-content:space-between;
align-items:center;
}
.horizontal {
flex-direction:row;
background-color: red;
}
.vertical {
flex-direction:column;
}
<body>
<div class="flex-container vertical">
<div class=flex-item>1 </div>
<div class=flex-item>2 </div>
<div class="flex-container horizontal" >
<div class=flex-item>3a </div>
<div class=flex-item>3b </div>
<div class=flex-item>3c </div>
</div>
<div class=flex-item>4 </div>
<div class=flex-item>5 </div>
</div>
</body>
Thanks for any help!
This is because of the way Flexbox works.
Since the .horizontal container is a flex child itself, it automatically adjusts to the size of the other children. Only allowing space for the overflowing content, which are the children of the .horizontal itself.
Manually applying the width will result in the space being created for the items, and the justify-content: space-between will kick in.
Solution, change the following rule:
.horizontal {
flex-direction: row;
background-color: red;
width: 100%;
}
Since you have set align-items:center; on the flex container, in addition to being centered - the items also only take up the minimum amount of space that they need.
If you hadn't set this property - then the default value of stretch would have kicked in and the items would take up the full width.
Then, like #Michael_B pointed out you could apply align-self:center on the flex items to center the items on the cross axis.
.flex-container {
color: blue;
background-color: yellow;
text-decoration: bold;
text-size: 1em;
display: flex;
justify-content: space-between;
}
.horizontal {
flex-direction: row;
background-color: red;
}
.vertical {
flex-direction: column;
}
.flex-item {
align-self: center;
/* center each flex item along the cross axis */
text-align: center;
/* horizontally center content within flex item */
}
<body>
<div class="flex-container vertical">
<div class=flex-item>1 </div>
<div class=flex-item>2 </div>
<div class="flex-container horizontal">
<div class=flex-item>3a </div>
<div class=flex-item>3b </div>
<div class=flex-item>3c </div>
</div>
<div class=flex-item>4 </div>
<div class=flex-item>5 </div>
</div>
</body>
Adding width: 100% to your horizontal flexbox and flex: 1 to the items within it I got this:
body {
background-color: black
}
.flex-container {
color: blue;
background-color: yellow;
display: flex;
justify-content: space-between;
align-items: center;
}
.horizontal {
flex-direction: row;
background-color: red;
width: 100%; /*this line was added*/
}
/*these lines*/
.horizontal .flex-item {
flex: 1;
}
/*ware added*/
.vertical {
flex-direction: column;
}
.flex-item {
background: tomato;
padding: 5px;
width: 100px;
height: 75px;
margin: 5px;
line-height: 75px;
color: white;
font-size: 3em;
text-align: center;
}
<body>
<div class="flex-container vertical">
<div class="flex-item">1 </div>
<div class="flex-item">2 </div>
<div class="flex-container horizontal">
<div class="flex-item">3a</div>
<div class="flex-item">3b</div>
<div class="flex-item">3c</div>
</div>
<div class="flex-item">4</div>
<div class="flex-item">5</div>
</div>
</body>