NeuroAgent

Equal Spacing in Flexbox: A Complete Guide

Learn how to create equal spacing between blocks in Flexbox. Solutions for uneven spacing issues and best practices for responsive design.

Question

How to create equal spacing between four blocks using Flexbox?

I have the following HTML code:

html
<div class="modal__box-nominal-list">
    <ul>
        <li><a href="javascript:void(0);" class="active_nominal">10 000 ₽</a></li>
        <li><a href="javascript:void(0);">30 000 ₽</a></li>
        <li><a href="javascript:void(0);">100 000 ₽</a></li>
    </ul>
    <label class="input-container" for="free_nominal">
        <input id="free_nominal" name="free_nominal" class="input" type="text" placeholder="Amount must be a multiple of 100 and greater than 900" value="" inputmode="numeric">
    </label>
</div>

I’m using the following CSS for Flexbox:

css
.modal__box-nominal-list {
    width:100%;
    display: flex;
    gap: 10px;
    flex-direction: column;
}

ul {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;    
}

li {
    display:block;
    width:calc(33% - 6px); //half of gap +1px, as it will wrap on small screens
    margin-top:0;
}

Problem: The spacing between the blocks is uneven. Between the first blocks, I have 13px and 11px, and between the third block and the input - 10px. What is the error in my code?

NeuroAgent

Your code contains several common errors that lead to uneven spacing. The main issues are related to incorrect width calculations of elements and the conflict between justify-content: space-between and flex-wrap: wrap.

justify-content: space-between creates uneven spacing when elements wrap to a new line because it tries to distribute space between all elements in a row, including the edge elements, which results in different intervals.

To create equal spacing between four blocks, it’s better to use modern approaches with the gap property and proper width calculations.

Table of Contents

Solution using gap

The most modern and reliable method uses the gap property to create equal intervals:

css
.modal__box-nominal-list {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

ul {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin: 0;
    padding: 0;
    list-style: none;
}

li {
    flex: 1 1 calc(50% - 10px); /* 2 elements per row accounting for gap */
    min-width: calc(50% - 10px);
}

Why this works:

  • gap: 10px creates equal intervals between elements
  • flex: 1 1 calc(50% - 10px) automatically distributes space accounting for margins
  • No need for complex calculations with justify-content

Alternative methods

Method with negative margins

css
.modal__box-nominal-list {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

ul {
    display: flex;
    flex-wrap: wrap;
    margin: 0 -5px; /* negative margin to compensate */
    padding: 0;
    list-style: none;
}

li {
    width: calc(50% - 10px); /* 50% - 10px (2 with 5px margin each) */
    margin: 5px; /* equal margins on both sides */
}

This approach is mentioned in sources as a reliable way to create equal spacing source.


Optimizing your code

The main errors in your original code:

  1. Incorrect width calculation: calc(33% - 6px) doesn’t account for the actual amount of gap
  2. Conflict between space-between and flex-wrap: These properties don’t work well together
  3. Missing list style reset: Default margin and padding disrupt the layout

Correct calculation for 3 elements per row with gap:

css
li {
    flex: 1 1 calc(33.333% - 6.666px); /* 100% / 3 - (2 * 10px) / 3 */
    min-width: calc(33.333% - 6.666px);
}

Complete corrected example

html
<div class="modal__box-nominal-list">
    <ul>
        <li><a href="javascript:void(0);" class="active_nominal">10 000 ₽</a></li>
        <li><a href="javascript:void(0);">30 000 ₽</a></li>
        <li><a href="javascript:void(0);">100 000 ₽</a></li>
    </ul>
    <label class="input-container" for="free_nominal">
        <input id="free_nominal" name="free_nominal" class="input" type="text" placeholder="Amount must be a multiple of 100 and greater than 900" value="" inputmode="numeric">
    </label>
</div>
css
.modal__box-nominal-list {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

ul {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin: 0;
    padding: 0;
    list-style: none;
}

li {
    flex: 1 1 calc(33.333% - 6.666px);
    min-width: calc(33.333% - 6.666px);
}

li a {
    display: block;
    padding: 10px;
    text-align: center;
    background: #f5f5f5;
    border-radius: 4px;
    text-decoration: none;
    color: #333;
}

.input-container {
    margin-top: 0; /* remove additional gap margin */
}

Responsiveness tips

For better responsiveness, use media queries:

css
@media (max-width: 768px) {
    li {
        flex: 1 1 calc(50% - 10px);
        min-width: calc(50% - 10px);
    }
}

@media (max-width: 480px) {
    li {
        flex: 1 1 100%;
        min-width: 100%;
    }
}

Important: Modern browsers well support the gap property, but for older browsers you may need to use negative margins or prefixed stylesheets.

Sources

  1. Gap — a bright future for spacing in Flexbox (like in Grid)
  2. Simple way to set spacing between flexbox elements
  3. Vertical distance between elements in Flexbox: solution
  4. Flexbox guide — CSS — Doka

Conclusion

  • Main problem: The conflict between justify-content: space-between and flex-wrap: wrap leads to uneven spacing
  • Best solution: Use the gap property to create equal intervals
  • Correct calculation: Element width should account for the number of gaps between them
  • Responsiveness: Use media queries to change the number of elements per row on different screens
  • Compatibility: gap is well supported in modern browsers, for older ones use negative margins

Your layout will work correctly if you abandon justify-content: space-between and use the modern approach with gap and automatic space distribution via the flex property.