Center flex item in container, when surrounded by other flex items

Flex alignment properties work by distributing free space in the container.

Hence, there’s no single-step method to center one flex item when it shares space with other items, unless the total length of the siblings is equal on both sides.

In your second example, the total length of the spans is equal on either side of the h2. As a result, the h2 is perfectly centered in the container.

.container {
    display: flex;
    justify-content: center;
    align-items: center;
    border: 1px solid red;
    margin: 5px;
    padding: 5px;
}
p { text-align: center;}
p > span { background-color: aqua; padding: 5px; }
<div class="container">
  <span>I'm span 1</span>
  <span>I'm span 2</span>
  <span>I'm span 3</span>
  <h2>I'm an h2</h2>
  <span>I'm span 4</span>
  <span>I'm span 5</span>
  <span>I'm span 6</span>
</div>
<p><span>TRUE CENTER</span></p>

Just keep in mind that centering the h2 with justify-content: center (or space-around or space-between), only works because there is equal balance on both sides. Each pixel of difference between sides will throw off the h2 by a commensurate amount.

In your first and last examples there is a clear imbalance between sides. Standard alignment properties such as justify-content and margin will not work because they center within the available space, not the total space.

You could insert duplicate spans on opposite sides with visibility: hidden to achieve equal balance. But this bloats your mark-up with semantically worthless elements.

Instead, if you have the ability to calculate the width of each span, you can insert pseudo-elements to achieve equal balance.

.container {
  display: flex;
  justify-content: center;
  align-items: center;
  border: 1px solid red;
  margin: 5px;
  padding: 5px;
}
span {
  flex: 0 0 75px;
  border: 1px dashed black;
  box-sizing: border-box;
}
div.container:first-child::before {
  content: "";
  width: 225px;
}
.container:nth-child(2)::after {
 content: "";
  width: 75px;
}
p { text-align: center;}
p > span { background-color: aqua; padding: 5px; border: none; }
<div class="container">
  <h2>I'm an h2</h2>
  <span>I'm span 1</span>
  <span>I'm span 2</span>
  <span>I'm span 3</span>
</div>
<div class="container">
  <span>I'm span 1</span>
  <span>I'm span 2</span>
  <h2>I'm an h2</h2>
  <span>I'm span 3</span>
</div>
<p><span>TRUE CENTER</span></p>

Ultimately, as a last resort with CSS, you can center the h2 with absolute positioning. This will remove the element from the document flow, but keep it perfectly centered in the container at all times.

.container {
  display: flex;
  justify-content: center;
  align-items: center;
  border: 1px solid red;
  position: relative; /* NEW */
  height: 50px;
}
h2 {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%);
  margin: 0;
}  
.container:nth-child(1) { justify-content: flex-end; }
.container:nth-child(2) > span:nth-of-type(4) { margin-left: auto; }  
.container:nth-child(3) > span:nth-of-type(2) { margin-right: auto; }

p { text-align: center;}
p > span { background-color: aqua; padding: 5px; }
<div class="container">
  <h2>I'm an h2</h2>
  <span>I'm span 1</span>
  <span>I'm span 2</span>
  <span>I'm span 3</span>
</div>
<div class="container">
  <span>I'm span 1</span>
  <span>I'm span 2</span>
  <span>I'm span 3</span>
  <h2>I'm an h2</h2>
  <span>I'm span 4</span>
  <span>I'm span 5</span>
  <span>I'm span 6</span>
</div>
<div class="container">
  <span>I'm span 1</span>
  <span>I'm span 2</span>
  <h2>I'm an h2</h2>
  <span>I'm span 3</span>
</div>
<p><span>TRUE CENTER</span></p>

UPDATE (based on revised question)

Basically, the theory is that while the amount of total <span>s are unknown, what is known is that there will be a total of three elements: <div><h2><div>.

So, if we know there will always be three elements, there is a potential solution using flex properties.

.container {
  display: flex;
}
.container > * {
  flex: 1;  /* KEY RULE */
}
h2 { 
  text-align: center;
  margin: 0;
}
.container > div {
  display: flex;
  justify-content: space-around;
}

/* non-essential decorative styles */
.container { background-color: lightgreen; border: 1px solid #ccc; padding: 5px; }
.container > * { border: 1px dashed red; }
p { text-align: center;}
p > span { background-color: aqua; padding: 5px; }
<div class="container">
  <div>
    <span>I'm span 1</span>
    <span>I'm span 2</span>
    <span>I'm span 3</span>
  </div>
  <h2>I'm an h2</h2>
  <div>
    <span>I'm span 4</span>
    <span>I'm span 5</span>
    <span>I'm span 6</span>
  </div>
</div>
<p><span>TRUE CENTER</span></p>

Here’s what’s happening:

  • The three elements are flex items, as their parent is a flex container
  • Each item is given a flex: 1, which causes them to distribute container space equally among themselves. The end result is three items of equal width.
  • Now, centering the h2 text in the h2 element will also center the text in the container.
  • Each div can be made a nested flex container, and the spans can be aligned with flex properties.

More information and solutions:

Leave a Comment