Cesar
Cesar

Reputation: 4116

Control middle space between 2 flex items in a row

How can I control the middle space between 2 flex items in a row? My goal is to minimize the middle space between the items.

In other words, I want to right and center align the columns, while keeping the text centered.

I would also like to be able to control the middle gutter. Also, maybe be able to say that the middle gutter should be some fixed pixel quantity like 20px.

This doesn't work because there is too much space in the middle

.row {
  display: flex;
  
}

.column {
  border: 1px solid #ccc;
  width: 50%;
}

h2 {
  text-align: center;
}
<div class="row">
  <div class="column first">
    <h2>Centered</h2>
    <h2>Text</h2>
  </div>
  <div class="column second">
    <h2>Centered</h2>
    <h2>Text</h2>
  </div>
</div>

This don't work because the text in not centered

.row {
  display: flex;
  
}

.column {
  border: 1px solid #ccc;
  width: 50%;
}

h2 {
  text-align: center;
}

.first h2 {
  text-align: right;
}

.second h2 {
  text-align: left;
}
<div class="row">
  <div class="column first">
    <h2>Centered</h2>
    <h2>Text</h2>
  </div>
  <div class="column second">
    <h2>Centered</h2>
    <h2>Text</h2>
  </div>
</div>

Upvotes: 2

Views: 4900

Answers (3)

tao
tao

Reputation: 90078

If you want your elements to have a particular proportion in relation to each other or to the whole (i.e: 50%), flexbox is not even the best solution (although it can be crow-bared to fulfill the requirement).

A simple display: inline-block; width: 50%; box-sizing: border-box on the children will do.


Flexbox was designed to allow fluid distribution of positive or negative space.

As in, after the browser determines how much space the children need and how much they have available, by comparing the two it deals with two cases:

  • positive space: when parent > sum of children, redistribute the space to each child, proportionally with their respective flex-grow values (until the space is filled) or, if no children have positive flex-grow values, distribute the space in between the children
  • negative space: if parent < sum of children, shrink each child proportionally with their flex-shrink values.

You have a case of positive space, where the children do not have flex-grow, so the space can be redistributed in between them. You have three options:

  • justify-content: space-between
  • justify-content: space-around
  • justify-content: space-evenly

Notice how the spaces are equally distributed in each case. That's why it's called flexbox, that's what it was designed for and, if you want, that's its superpower.
When you set width: 50% you kind of take all of that away:

.row {
  display: flex;
  width: 100%;
}

.row>* {
  border: 1px solid #ccc;
  text-align: center;
}

.one {
  justify-content: space-between;
}

.two {
  justify-content: space-around;
}

.three {
  justify-content: space-evenly;
}

.grow>* {
  flex-grow: 1;
  margin: 1rem;
}
<code>justify-content: space-between</code>
<div class="row one">
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
</div>
<code>justify-content: space-between  (unequal)</code>
<div class="row one">
  <div>
    <h2>A bigger element here</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
</div>

<hr>
<code>justify-content: space-around;</code>
<div class="row two">
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
</div>
<code>justify-content: space-around; (unequal)</code>
<div class="row two">
  <div>
    <h2>A bigger element here</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
</div>
<hr>
<code>justify-content: space-evenly;</code>
<div class="row three">
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
</div>
<code>justify-content: space-evenly; (unequal)</code>
<div class="row three">
  <div>
    <h2>A bigger element here</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
</div>
<hr>
<code>> flex-grow: 1;</code>
<div class="row grow">
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
</div>
<hr>
<code>> flex-grow: 1; (unequal elements)</code>
<div class="row grow">
  <div>
    <h2>A bigger element here</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
</div>

A more detailed explanation on how flexbox works can be found here.

The official spec is here.


Considering your question, there's a big chance justify-content: space-evenly does what you want, but I can't be sure, as your question is not extremely clear.

Important note: You can always use margin and padding on your elements, which will push them around accordingly. Also note margin: auto on flexbox children will steal the positive space from flexbox and will redistribute it equally between all the margin:autos present in parent space (and will make it look like flexbox doesn't work properly; it actually does, but there's nothing left to redistribute).


If you want to have a particular distance in between your elements and the entire composition should be centered in the available space, you could center a single item in the available space and inside that item you could place the items, so that the entire thing is centered regardless of the fact the items are unequal.

Example:

.row {
  display: flex;
  justify-content: center;
}
.row > *  {
  margin: 0 auto;
  display: flex;
}

.row>*>* {
  border: 1px solid #ccc;
  text-align: center;
  margin: 1rem;
}
<div class="row">
  <div>
    <div>
      <h2>Centered</h2>
      <p>Text</p>
    </div>
    <div>
      <h2>Centered</h2>
      <p>Text</p>
    </div>
    <div>
      <h2>Centered</h2>
      <p>Text</p>
    </div>
  </div>
</div>
<hr>
<div class="row">
  <div>
    <div>
      <h2>Much more text here</h2>
      <p>Text</p>
    </div>
    <div>
      <h2>Centered</h2>
      <p>Text</p>
    </div>
    <div>
      <h2>Centered</h2>
      <p>Text</p>
    </div>
  </div>
</div>
<hr>
<div class="row">
  <div>
    <div>
      <h2>Centered</h2>
      <p>Text</p>
    </div>
    <div>
      <h2>Centered</h2>
      <p>Text</p>
    </div>
    <div>
      <h2>Much more text here</h2>
      <p>Text</p>
    </div>
  </div>
</div>

But, again, that's not something you need flexbox for.
The exact same can be achieved using a simple parent > child structure, where parent has display: block; text-align: center; and children have display: inline-block;

.row {
  text-align: center;
}

.row>* {
  border: 1px solid #ccc;
  text-align: center;
  margin: 1rem;
  display: inline-block;
}
<div class="row">
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
</div>
<hr>
<div class="row">
  <div>
    <h2>Much more text here</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
</div>
<hr>
<div class="row">
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Centered</h2>
    <p>Text</p>
  </div>
  <div>
    <h2>Much more text here</h2>
    <p>Text</p>
  </div>
</div>

Notice the absence of the extra wrapper in markup.

Upvotes: 3

connexo
connexo

Reputation: 56753

Why not simply use a CSS grid for the task? It offers the grid-column-gap property which does exactly what you need:

.row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-column-gap: 10px;
}

.column {
  border: 1px solid #ccc;
}

h2 {
  text-align: center;
}
<div class="row">
  <div class="column">
    <h2>Centered<br />Text</h2>
  </div>
  <div class="column">
    <h2>Centered<br />Text</h2>
  </div>
</div>

Upvotes: 3

Monday A Victor
Monday A Victor

Reputation: 471

Try doing this

.column:not(:last-child){
margin-left: 20px;
}

Upvotes: 0

Related Questions