Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

extra space when centering elements using flexbox

Tags:

html

css

flexbox

I'm using align-items and justify-content to center the elements, my html is:

<div class="flex-container">
    <div class="item-1">div</div>
    <div class="item-2">w=250px</div>
    <div class="item-3">h=250px</div>
    <div class="item-4">w/h=300px</div>
    <div class="item-5">w=350px</div>
    <div class="item-6">w=350px</div>
</div>

my css code is something like:

.flex-container {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    align-content: center;
}

(I leave out some unimportant css code.)

so the result will be like:

enter image description here

but if I shrink the browser window, it will be like: enter image description here

I don't understand why there is so much space between two lines (I know using align-content: center; can fix, but I want to know how those excess space is there in the first place)

* {
  box-sizing: border-box;
  font-size: 1.5rem;
}

html {
  background: #b3b3b3;
  padding: 5px;
}

body {
  background: #b3b3b3;
  padding: 5px;
  margin: 0;
}

.flex-container {
  background: white;
  padding: 10px;
  border: 5px solid black;
  height: 800px;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
}

.item-1 {
  background: #ff7300;
  color: white;
  padding: 10px;
  border: 5px solid black;
  margin: 10px;
}

.item-2 {
  background: #ff9640;
  color: white;
  padding: 10px;
  border: 5px solid black;
  margin: 10px;
  width: 250px;
  /* font-size: 1.8rem; */
}

.item-3 {
  background: #ff9640;
  color: white;
  padding: 10px;
  border: 5px solid black;
  margin: 10px;
  height: 250px;
}

.item-4 {
  background: #f5c096;
  color: white;
  padding: 10px;
  border: 5px solid black;
  margin: 10px;
  width: 300px;
  height: 300px;
}

.item-5 {
  background: #d3c0b1;
  color: white;
  padding: 10px;
  border: 5px solid black;
  margin: 10px;
  width: 350px;
}

.item-6 {
  background: #d3c0b1;
  color: white;
  padding: 10px;
  border: 5px solid black;
  margin: 10px;
  width: 350px;
}
<div class="flex-container">
  <div class="item-1">div</div>
  <div class="item-2">w=250px</div>
  <div class="item-3">h=250px</div>
  <div class="item-4">w/h=300px</div>
  <div class="item-5">w=350px</div>
  <div class="item-6">w=350px</div>
</div>

and if I shrink the browser window more, then there is no such excess space:

enter image description here

like image 904
amjad Avatar asked Nov 02 '18 13:11

amjad


People also ask

How do I reduce space on my flexbox?

The flexbox layout even works when the size of the items is unknown or dynamic. To set space between the flexbox you can use the flexbox property justify-content you can also visit all the property in that link. We can use the justify-content property of a flex container to set space between the flexbox.

Why is flexbox overflowing?

min-width in a flex context: While the default min-width value is 0 (zero), for flex items it is auto . This can make block elements take up much more space than desired, resulting in overflow.


2 Answers

align-content

Note that align-content: stretch is also in play here.

The align-content property distributes free space among flex lines. It's default value is stretch.

So when your items wrap to two lines, align-content: stretch distributes free space equally across lines.


align-items

Remove align-items: center from the container. You'll then notice that when items wrap, there is no gap between lines (or "rows", in this case). demo

Line heights are set by align-content, the height of the items, and the content of the items.

enter image description here


align-content and align-items working together

Restore align-items: center. Now when items wrap, there is a visible gap between lines.

enter image description here

This is because align-items: center positions the items in the vertical center of the line, based on line heights established by align-content: stretch, item heights, and item content.

The line heights are set here (with align-content: stretch and align-items: stretch):

enter image description here

... and continue here (with align-content: stretch and align-items: center):

enter image description here

align-items is having no effect on the height of the flex line. That job is andled by align-content.

However, by changing the value of align-content (to flex-start, flex-end, space-between, center, etc.), you pack the flex lines, squeezing out the free space, and hence removing the gaps.

enter image description here


Why is the first row taller than the second row with align-content: stretch?

The container is set to height: 800px.

There are two items with defined heights:

  • .item-3 { height: 250px }
  • .item-4 { height: 300px }

When .item-5 and .item-6 form the second row, the free space in the container is, in its simplest form, 500px (800px - 300px).

So, in a container with two rows and align-content: stretch, 250px is distributed to the height of each row.

  • first row is 300px (defined height) plus 250px (free space)
  • second row is 250px (free space)

That's why the first row is taller.

Just note that the free space calculation above is slightly off in the actual layout. That's because there is text in the items, which consumes free space. You can factor in the height of the text to get the precise figures, or remove the text altogether to see the calculations above fall into place.


More details:

  • How does flex-wrap work with align-self, align-items and align-content?
  • Equal height rows in a flex container
like image 170
Michael Benjamin Avatar answered Sep 20 '22 03:09

Michael Benjamin


To make it easy, I will reduce the code so we can better understand the behavior.

Let's consider this initial code:

* {
  box-sizing: border-box;
  font-size: 1.5rem;
}

html {
  background: #b3b3b3;
  padding: 5px;
}

body {
  background: #b3b3b3;
  padding: 5px;
  margin: 0;
}

.flex-container {
  background: white;
  padding: 10px;
  border: 5px solid black;
  height: 400px;
  display: flex;
  flex-direction: row;
  flex-wrap:wrap;
}

.item-1 {
  background: #ff7300;
  color: white;
  padding: 10px;
  border: 5px solid black;
  margin: 10px;
}

.item-2 {
  background: #ff9640;
  color: white;
  padding: 10px;
  border: 5px solid black;
  margin: 10px;
  width: 250px;
}

.item-3 {
  background: #ff9640;
  color: white;
  padding: 10px;
  border: 5px solid black;
  margin: 10px;
  height: 150px;
}
<div class="flex-container">
  <div class="item-1">div</div>
  <div class="item-2">w=250px</div>
  <div class="item-3">h=150px</div>
</div>

The container has a fixed height and only one element has a fixed height and the other will be stretched to fill the parent height since by default align-items is stretch.

Now let's decrease the width of the container in order to make the third element in the second row:

* {
  box-sizing: border-box;
  font-size: 1.5rem;
}

html {
  background: #b3b3b3;
  padding: 5px;
}

body {
  background: #b3b3b3;
  padding: 5px;
  margin: 0;
}

.flex-container {
  background: white;
  padding: 10px;
  border: 5px solid black;
  height: 400px;
  display: flex;
  flex-direction: row;
  flex-wrap:wrap;
  width:500px;
}

.item-1 {
  background: #ff7300;
  color: white;
  padding: 10px;
  border: 5px solid black;
  margin: 10px;
}

.item-2 {
  background: #ff9640;
  color: white;
  padding: 10px;
  border: 5px solid black;
  margin: 10px;
  width: 250px;
}

.item-3 {
  background: #ff9640;
  color: white;
  padding: 10px;
  border: 5px solid black;
  margin: 10px;
  height: 150px;
}
<div class="flex-container">
  <div class="item-1">div</div>
  <div class="item-2">w=250px</div>
  <div class="item-3">h=150px</div>
</div>

Here we have a complex behavior where we have a multiline flex container where item1 and item2 belong to the first line and item3 to the second line. I cannot explain very well how the height of each line is defined (the complex part). After this each flex item will stretch to fill the height of its line unless it has a fixed height like item3 or we change the alignment.

Now, if we change align-items to something different than stretch we will have the gap:

* {
  box-sizing: border-box;
  font-size: 1.5rem;
}

html {
  background: #b3b3b3;
  padding: 5px;
}

body {
  background: #b3b3b3;
  padding: 5px;
  margin: 0;
}

.flex-container {
  background: white;
  padding: 10px;
  border: 5px solid black;
  height: 400px;
  display: flex;
  flex-direction: row;
  flex-wrap:wrap;
  width:500px;
  align-items:flex-start;
}

.item-1 {
  background: #ff7300;
  color: white;
  padding: 10px;
  border: 5px solid black;
  margin: 10px;
}

.item-2 {
  background: #ff9640;
  color: white;
  padding: 10px;
  border: 5px solid black;
  margin: 10px;
  width: 250px;
}

.item-3 {
  background: #ff9640;
  color: white;
  padding: 10px;
  border: 5px solid black;
  margin: 10px;
  height: 150px;
}
<div class="flex-container">
  <div class="item-1">div</div>
  <div class="item-2">w=250px</div>
  <div class="item-3">h=150px</div>
</div>

If we compare the above code with the previous one we can see that item3 kept his place and only the height of item1 and item2 have changed. This explain that align-items will align items inside their lines that was previously defined due to wrapping.

In other words, when we have a multiline flex container we first define the lines (considering the height of the container, the height of elements and other flexbox properties) then we align the items inside their line and the gap we have is due to how the alignment is done.

Here is a better example to show different cases:

.flex-container {
  background: white;
  padding: 10px;
  border: 5px solid black;
  height: 200px;
  display: inline-flex;
  vertical-align:top;
  flex-direction: row;
  flex-wrap:wrap;
  width:100px;
}

.item-1 {
  background: #ff7300;
  color: white;
  border: 1px solid black;
  margin: 2px;
}

.item-2 {
  background: #ff9640;
  color: white;
  border: 1px solid black;
  margin: 2px;
  width: 70px;
}

.item-3 {
  background: #ff9640;
  color: white;
  border: 1px solid black;
  margin: 2px;
  height: 50px;
}
<div class="flex-container">
  <div class="item-1">A</div>
  <div class="item-2">B</div>
  <div class="item-3">C</div>
</div>
<div class="flex-container" style="align-items:flex-start;">
  <div class="item-1">A</div>
  <div class="item-2">B</div>
  <div class="item-3">C</div>
</div>
<div class="flex-container" style="align-items:center;">
  <div class="item-1">A</div>
  <div class="item-2">B</div>
  <div class="item-3">C</div>
</div>
<div class="flex-container" style="align-items:flex-end;">
  <div class="item-1">A</div>
  <div class="item-2">B</div>
  <div class="item-3">C</div>
</div>
<div class="flex-container" style="align-items:flex-end;">
  <div class="item-1">A</div>
  <div class="item-2">B</div>
  <div class="item-3" style="margin-bottom:auto;">C</div>
</div>

<div class="flex-container">
  <div class="item-1" style="margin-top:auto;">A</div>
  <div class="item-2">B</div>
  <div class="item-3" >C</div>
</div>

We can clearly notice that we have the same lines accross all the container and only the alignment is changing which create different gaps.


In case there is no element with a fixed height, the lines will have the same height, so the container will be splitted equally.

.flex-container {
  background: white;
  padding: 10px;
  border: 5px solid black;
  height: 200px;
  display: inline-flex;
  vertical-align:top;
  flex-direction: row;
  flex-wrap:wrap;
  width:100px;
}

.item-1 {
  background: #ff7300;
  color: white;
  border: 1px solid black;
  margin: 2px;
}

.item-2 {
  background: #ff9640;
  color: white;
  border: 1px solid black;
  margin: 2px;
  width: 70px;
}

.item-3 {
  background: #ff9640;
  color: white;
  border: 1px solid black;
  margin: 2px;
}
<div class="flex-container">
  <div class="item-1">A</div>
  <div class="item-2">B</div>
  <div class="item-3">C</div>
</div>
<div class="flex-container" style="align-items:flex-start;">
  <div class="item-1">A</div>
  <div class="item-2">B</div>
  <div class="item-3">C</div>
</div>
<div class="flex-container" style="align-items:center;">
  <div class="item-1">A</div>
  <div class="item-2">B</div>
  <div class="item-3">C</div>
</div>
<div class="flex-container" style="align-items:flex-end;">
  <div class="item-1">A</div>
  <div class="item-2">B</div>
  <div class="item-3">C</div>
</div>
<div class="flex-container" style="align-items:flex-end;">
  <div class="item-1">A</div>
  <div class="item-2">B</div>
  <div class="item-3" style="margin-bottom:auto;">C</div>
</div>

<div class="flex-container">
  <div class="item-1" style="margin-top:auto;">A</div>
  <div class="item-2">B</div>
  <div class="item-3" >C</div>
</div>

By changing align-content we will change how the lines are created before considering align-items to align the items inside their lines:

.flex-container {
  background: white;
  padding: 10px;
  border: 5px solid black;
  height: 200px;
  display: inline-flex;
  vertical-align:top;
  flex-direction: row;
  flex-wrap:wrap;
  width:100px;
}

.item-1 {
  background: #ff7300;
  color: white;
  border: 1px solid black;
  margin: 2px;
}

.item-2 {
  background: #ff9640;
  color: white;
  border: 1px solid black;
  margin: 2px;
  width: 70px;
}

.item-3 {
  background: #ff9640;
  color: white;
  border: 1px solid black;
  margin: 2px;
  height:50px;
}
<div class="flex-container">
  <div class="item-1">A</div>
  <div class="item-2">B</div>
  <div class="item-3">C</div>
</div>
<div class="flex-container" style="align-content:flex-start;">
  <div class="item-1">A</div>
  <div class="item-2">B</div>
  <div class="item-3">C</div>
</div>
<div class="flex-container" style="align-content:center;">
  <div class="item-1">A</div>
  <div class="item-2">B</div>
  <div class="item-3">C</div>
</div>
<div class="flex-container" style="align-content:flex-end;">
  <div class="item-1">A</div>
  <div class="item-2">B</div>
  <div class="item-3">C</div>
</div>

In order to understand the complex part of this answer (how lines are defined) you can refer to the specification : https://www.w3.org/TR/css-flexbox-1/#layout-algorithm

like image 41
Temani Afif Avatar answered Sep 21 '22 03:09

Temani Afif