1

I am trying to find a way to distribute an uneven number of elements across the horizontal axis that satisfies the following:

  • the left border of the first child overlaps the left border of the container
  • the right border of the last child overlaps the right border of the container
  • uneven number of children (that is, there exists a middle item)
  • the middle item must be properly centered
  • the remaining items (i.e. items between the first and middle items and between the middle and last items) are evenly distributed
  • the items can vary in width (no fixed width)

Here is an example of the problem I encounter (4th condition not satisfied) with my current implementation:

#container {
  display: flex;
  justify-content: space-between;
}

#container > div {
  background-color: black;
}

#container > div:nth-child(1) {
  width: 100px;
  height: 20px;
}

#container > div:nth-child(2) {
  width: 80px;
  height: 30px;
}

#container > div:nth-child(3) {
  width: 50px;
  height: 50px;
}

#container > div:nth-child(4) {
  width: 40px;
  height: 30px;
}

#container > div:nth-child(5) {
  width: 90px;
  height: 10px;
}

p {
  width: 100%;
  text-align: center;
}
<div id="container">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>
<p>
&#8593;<br>
actual center
</p>

Another possible approach is given here:

#container {
  display: flex;
}

#container > div {
  flex: 1;
  display: flex;
  justify-content: center;
}

#container > div > div {
  background-color: black;
}

#container > div:nth-child(1) > div {
  width: 100px;
  height: 20px;
  margin-right: auto;
}

#container > div:nth-child(2) > div {
  width: 80px;
  height: 30px;
}

#container > div:nth-child(3) > div {
  width: 50px;
  height: 50px;
}

#container > div:nth-child(4) > div {
  width: 40px;
  height: 30px;
}

#container > div:nth-child(5) > div {
  width: 90px;
  height: 10px;
  margin-left: auto;
}

p {
  width: 100%;
  text-align: center;
}
<div id="container">
  <div><div></div></div>
  <div><div></div></div>
  <div><div></div></div>
  <div><div></div></div>
  <div><div></div></div>
</div>
<p>
&#8593;<br>
center
</p>

While aesthetically more pleasing, this is not ideal because the second and fourth divs are centered relative to their given flow space instead of their surrounding space:

enter image description here

By contrast, here is what I am trying to achieve:

enter image description here

Kathandrax
  • 914
  • 14
  • 26

1 Answers1

1

One possible solution would be to break the container into three flex children; left, center, and right.

To keep the center anchored, apply flex: 1; to left and right.

To get even space on the last child of left, and the first child of right, you can add an empty block psuedo-element.

#container {
  display: flex;
  justify-content: space-between;
}

#container>div {
  display: flex;
  justify-content: space-between;
}

#container>div.left,
#container>div.right {
  flex: 1;
}

#container>div.left::after,
#container>div.right::before {
  display: block;
  content: '';
}

#container>div>div {
  background-color: black;
}

#container>div.left>div:nth-child(1) {
  width: 100px;
  height: 20px;
}

#container>div.left>div:nth-child(2) {
  width: 80px;
  height: 30px;
}


#container>div.center>div {
  width: 50px;
  height: 50px;
}

#container>div.right>div:nth-child(1) {
  width: 40px;
  height: 30px;
}

#container>div.right>div:nth-child(2) {
  width: 90px;
  height: 10px;
}

p {
  width: 100%;
  text-align: center;
}
<div id="container">
  <div class="left">
    <div></div>
    <div></div>
  </div>
  <div class="center">
    <div></div>
  </div>
  <div class="right">
    <div></div>
    <div></div>
  </div>
</div>
<p>
  &#8593;<br> actual center
</p>
Tyler Roper
  • 21,445
  • 6
  • 33
  • 56
  • Great solution that satisfies all of the conditions. I think the structure change is de facto necessary and was not a concern in the first place. Thanks for your contribution! – Kathandrax Oct 04 '19 at 20:22
  • Quick note: I think `justify-content: space-between` is unnecessary for the `container` because `flex: 1` on both `left` and `right` guarantees the middle item is properly centered. I think `display: flex; justify-content: space-between` is also unnecessary for the middle item because it only consists of a single element: https://jsfiddle.net/cx3tbye2/ – Kathandrax Oct 04 '19 at 20:49