I'm having a problem with CSS flexbox. I had a working code yesterday yet today when I tested my solution it stopped working for some reason. It has to do with flexbox.
This is the result I want to have:
To be able to position the content with justify-content. This fails
Content should take all the available space so it has flex-grow: 1. This fails, as well.
The footer should be at the bottom since the content would push it down by taking all the available space thanks to flex-grow: 1. This fails.
It seems that whole flexbox stopped working correctly for me.
I believe the problem is that for some reason flexbox does not even respond correctly to this:
`justify-content: flex-start`
If I try any other values there like center, flex-end, etc nothing happens.
Funny thing is that yesterday flexbox was behaving correctly, I could position it around with justify-content and today I can't.
What am I missing here why is not at least justify-content: flex-end or justify-content: center doing behaving correctly and positioning the content?
If I fix the problem that causes justify-content to stop working I believe flex-grow will also work.
Does anyone have an idea why it's misbehaving?
I can get flex to behaving using this playground so I know my code should be working, My code above is exactly what I did here in the playground:
https://demos.scotch.io/visual-guide-to-css3-flexbox-flexbox-playground/demos/
.ikigai {
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.header, .footer {
height: 80px;
margin: 10px;
border: 1px dashed lightgray;
}
.content {
margin: 10px;
border: 1px dashed lightgray;
flex-grow: 1;
}
<div class="ikigai">
<div class="header">this is a header</div>
<div class="content">content</div>
<div class="footer">footer 12</div>
</div>
https://jsfiddle.net/re01pn2x/
Your flex container has no height defined.
Therefore, it defaults to height: auto (content-driven height).
Add this to your code:
.ikigai {
height: 100vh;
}
.ikigai {
display: flex;
flex-direction: column;
/* justify-content: flex-start; */ /* default value; not necessary */
height: 100vh;
}
.header, .footer {
height: 80px;
flex-shrink: 0; /* optional; if you don't want items to shrink vertically */
margin: 10px;
border: 1px dashed lightgray;
}
.content {
margin: 10px;
border: 1px dashed lightgray;
flex-grow: 1;
}
body {
margin: 0; /* override default margins; prevents vertical scrollbar */
}
<div class="ikigai">
<div class="header">this is a header</div>
<div class="content">content</div>
<div class="footer">footer 12</div>
</div>
More details: How to make div 100% height of the browser window?
justify-content
Note that justify-content wasn't working in your code because there was no free space available. This property works by distributing free space in the container. In this case, because the container was defaulting to height: auto, there was only enough space to accommodate the content.
justify-content & flex-grow
Also note that even with a height defined that creates extra space, justify-content will not work if you use flex-grow. Why? Because flex-grow will consume that free space, again leaving no space for justify-content to distribute.
You can fixed using height:100vh;
.ikigai {
display: flex;
flex-direction: column;
justify-content: flex-start;
height: 100vh;
}
.header, .footer {
height: 80px;
margin: 10px;
border: 1px dashed lightgray;
}
.content {
margin: 10px;
border: 1px dashed lightgray;
flex-grow: 1;
}
Related
I am constructing a form where the field's width percentage is dynamically set by clients.
My first approach was to create a flex container with wrapping enabled and space the fields evenly using gap: 16px. To my surprise, flex-wrap and gap don't behave as I would expect.
main {
width: 400px;
background-color: gray;
display: flex;
gap: 16px;
flex-wrap: wrap;
}
div {
background-color: blue;
}
.first {
width: 50%;
}
.second {
width: 50%;
}
<main>
<div class="first">First</div>
<div class="second">Second</div>
</main>
I expected them to be in the same line and have the gap in-between. This happens when I remove the flex-wrap.
The only solution I found was to use calc(50% - 16px), but this is far from ideal. Maybe I'm approaching the problem wrongly?
I have a layout that gets customized by many different clients so the html structure is locked down to
<div class="container">
<div>content</div>
<div>content</div>
<div>content</div>
<div>content</div>
</div>
NOTE: not using bootstrap, container is just the applicable name
In the UI I need to be able to use CSS to make many different layouts from this structure without altering it. There is one in particular I can't figure out. The desired layout is this:
I know that if it were all vertical it would be easily doo-able with simple width and float styles. I also know that throwing a containing div around the first two children would be an easy solution but again requirements are to leave the html unchanged.
I've tried:
.container {
display: flex;
flex-wrap: wrap;
}
.container > div {
width: 33.33335;
height: 400px;
}
.container > div:nth-child(1),
.container > div:nth-child(2) {
height: 200px;
}
setting appropriate heights to the child divs where the first two are half the height of the others.
Similarly, I've tried:
.container > div {
float: left;
}
.container > div {
height: 400px;
width: 33.33333%;
}
.container > div:nth-child(1),
.container > div:nth-child(2) {
height: 200px;
}
and again giving the first two children a height that is half the others. Nothing has worked, in all outcomes either the first two stack and the others do not float/flex up or the the first two do not stack at all.
Can anyone figure a CSS method of styling this structure for the desired UI?
Appreciate the help.
If you can set a fixed height on the container, you can use flexbox with flex-flow: column wrap. The fixed height is necessary to tell flex items where to wrap. Here's an example:
.container {
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: space-around; /* vertical alignment */
align-content: center; /* horizontal alignment */
height: 320px; /* essential for this method to work */
background-color: lightyellow;
border: 1px dashed red;
}
.container>div {
flex: 0 0 90%; /* flex-grow, flex-shrink, flex-basis */
width: 30%;
margin: 5px;
background-color: lightgreen;
}
.container>div:nth-child(1),
.container>div:nth-child(2) {
flex-basis: 40%; /* override flex-basis from rule above */
}
<div class="container">
<div>content</div>
<div>content</div>
<div>content</div>
<div>content</div>
</div>
I've recently starting using flexbox and this is the first problem I've run into. I want my .wrp class below to remain display: inline-block; but one line seems to disable this value. That line is: flex-direction: column. When I remove that line my .wrp class starts behaving like an inline-block element again but then of course it loses it's flex-direction value. Is there a simple solution that doesn't require restructuring my HTML too much to keep the flex-direction behavior of flexbox but also keep the inline-block behavior on .wrp?
.contr {
display: flex;
flex-direction: column; /* this line seems to be breakig my display on .wrp */
justify-content: center;
height: 10rem;
background-color: #eee;
}
.wrp {
display: inline-block;
height: 5rem;
background-color: #ddd;
}
p {
width: 100%;
background-color: #ccc;
}
<div class="contr">
<div class="wrp">
<p>I want this paragraph to stretch to fit it's content. Not full width.</p>
</div>
</div>
You can't have an inline-block element within a flex. It looks like you may be looking for display: inline-table:
.contr {
display: flex;
flex-direction: column; /* this line seems to be breakig my display on .wrp */
justify-content: center;
height: 10rem;
background-color: #eee;
}
.wrp {
display: inline-table;
height: 5rem;
background-color: #ddd;
}
p {
width: 100%;
background-color: #ccc;
}
<div class="contr">
<div class="wrp">
<p>I want this paragraph to stretch to fit it's content. Not full width.</p>
</div>
</div>
Hope this helps! :)
Given this CSS:
div.container {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
border: 1px solid blue;
}
div.container div {
width: 200px;
border: 1px solid gray;
display: inline-block;
text-align: center;
}
This layout has the first item in each row aligned to the left, and the last item aligned to the right, as required.
As the browser window is made narrower, the distributed div elements will move closer together until they touch, at which point they are re-arranged over an additional row. Again, the first div on each row is aligned left, and the last aligned right with space between.
Is there any way of setting a minimum spacing so that the inner div elements always have a gap between them.
padding and margin will probably not work, as the alignment
<-- 1st left in row and last right in row --> will not hold.
Bit late the the party but I ran into the same issue. The way I solved it probably wont work for everyone but here it is for those who can use it.
The basic idea is that you have a min gap of x. You set the left and right margins of each item to x/2 so that the distance between the items will be x (margin + margin). Then you wrap all of the items in a container with a left and right margin of -x/2. This will hide the margin on the items at the edges of each row.
Here is a working example:
.box {
border: 1px solid black;
overflow-x: hidden;
}
.container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
margin: 0 -1em;
}
.item {
display: flex;
border: 1px solid grey;
padding: 1em;
width: 20%;
margin: 0 1em;
}
<div class="box">
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
</div>
</div>
The overflow-x: hidden; on .box is to prevent the horizontal scrollbar that shows up in some browsers because of the margin overflowing.
If you want the gap to always be consistent and for rows with only one item to have that item span the whole row then you can add flex-grow: 1 to .item.
You can add another div with flex style for holding the needed gap between inner divs. and for the minimum width for that gap use this property (as mentioned in W3Schools.com):
flex: flex-grow flex-shrink flex-basis|auto|initial|inherit;
which flex-shrink is :
flex-shrink: A number specifying how much the item will shrink relative to the rest of the flexible items
so, for example you set this css code for the gap div :
flex: 1 0 10px;
that tells gap div will have 10px width, and will grow relative to the rest of the flexible items, but WON'T SHRINK. so the minimum width will be 10px at the narrowest width of the screen.
In 2022 you can just use gap CSS property:
div.container {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
border: 1px solid blue;
gap: 20px;
}
To support older browsers you may use margin hack.
div.container > * {
margin: 12px 0 0 12px;
}
div.container {
display: inline-flex;
flex-wrap: wrap;
margin: -12px 0 0 -12px;
width: calc(100% + 12px);
}
Since April 2021 support for flexbox-gap has arrived in all major browsers (IE considered dead). Combining it w/ space-between solves your problem.
div.container {
display: flex;
gap: 10px; /* minimum gap between flex-items */
justify-content: space-between;
}
It's a couple of days passed since this question was asked, but I thought I should add my solution if anybody comes past and has the same issue.
I suggest using calc, width, and media to solve this issue. Yes, it's a little work but it's a visual clean solution in my opinion.
.main{
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
.main > div{
width: 100%;
height: 125px;
border: 1px solid red;
}
#media (min-width: 576px) {
.main > div{
width: calc(100% / 2 - 5px);
margin-bottom: 5px;
}
}
#media (min-width: 992px) {
.main > div{
width: calc(100% / 3 - 5px);
}
}
#media (min-width: 1140px) {
.main > div{
width: calc(100% / 6 - 5px);
margin-bottom: 0;
}
}
<div class="main">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
</div>
For the needed breakpoints I calculate the width I want the divs to use and subtract the space I want them to have.
I hope this helps someone and that I explained it understandable.
Regards.
Setting a flex-basis with percentage also will do the trick. Then the min space between will be also in percentage.
For instance, with 3 elements, flex: 0 0 30% will allow a fixed 10% space reparted between elements.
with 6 elements, flex: 0 0 15% and so on.
I'm using flex box to align two items to left and right of the container, while vertically centre-aligning them. Here's a very simple example of what I'm trying to achieve.
HTML:
<div class="container">
<div class="first"></div>
<div class="second"></div>
</div>
CSS:
.container {
width:100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
}
.first {
background-color: yellow;
width: 200px;
height: 100px;
}
.second {
background-color: blue;
width: 200px;
height: 100px;
}
Here's the jsfiddle of the example.
This works perfectly well if the screen is wide enough to fit both internal divs on one row. However when the screen size is small (e.g. a mobile phone) and the divs wrap onto the second line, the second one also becomes aligned to the left side (i.e. flex-start). How can I force the second div to always be aligned against the right border, regardless of whether it's on the first row or wrapped onto the second one?
EDIT: In the example, I assigned fixed width to the two child elements - this is for simplicity only. In the real life application, all widths are dynamically changing based on the content read from the database at run-time. Hence, any solution that's based on fixed sizes will not work.
You can try adding some left margin to push your .second element to the right:
.second {
margin-left: auto;
}
.container {
width:100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
}
.first {
background-color: yellow;
width: 200px;
height: 100px;
}
.second {
background-color: blue;
width: 200px;
height: 100px;
margin-left: auto;
}
<div class="container">
<div class="first"></div>
<div class="second"></div>
</div>
Or, similarly, justify all elements to the right but push .first element to the left:
.container {
justify-content: flex-end;
}
.first {
margin-right: auto;
}
.container {
width:100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-end;
align-items: center;
}
.first {
background-color: yellow;
width: 200px;
height: 100px;
margin-right: auto;
}
.second {
background-color: blue;
width: 200px;
height: 100px;
}
<div class="container">
<div class="first"></div>
<div class="second"></div>
</div>
I found a solution but it is rather "hacky" in nature (see demo here, explanation later), in the sense that it requires you to explicitly know the width of the parent container which will trigger a layout change based on #media.
The reason why your code is not working is because of the confusion over how align-self works. In the flexbox model, "align" refers to alignment along the cross-axis (i.e. in a conventional sense of a "row" layout direction, that will refer to vertical alignment), while "justify" refers to alignment along the main axis (i.e. the row). To better explain my point, I hereby attach an image made by Chris Coyier from his flexbox guide:
Therefore, align-self: flex-start means telling the .first to align to the top of the container, and align-self: flex-end means telling .second to align to the bottom of the container. In this case, since you have not declared an explicit height for the parent, the parent will take on the height of its tallest child. Since both .first and .second are 100px tall, the parent will also have a computed height of 100px, therefore making no difference in the alignment (because both with be flush with the start and end of the cross axis).
A hack would be switching the flex-direction to row, with the following restrictions: You know how wide your container will be, or the explicit widths of its children. In this case the breakpoint will be at 400px, where .first and .second will intersect each other.
.container {
width:100%;
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: space-between;
height: 100px;
}
.first {
background-color: yellow;
width: 200px;
height: 100px;
align-self: flex-start;
}
.second {
background-color: blue;
width: 200px;
height: 100px;
align-self: flex-end;
}
#media screen and (max-width: 400px) {
.container {
height: 200px;
}
}
Then again, here is a proof-of-concept fiddle, modified from your original one: http://jsfiddle.net/teddyrised/cncozfem/2/