Skip to content

[css-flex] Gap between flexed items when parent has flex-wrap: wrap; set causes the last item to wrap prematurely #5399

Closed

Description

@JacobDB

Issue

I was experimenting with the new gap support on display: flex; containers, however I ran in to an odd issue that appears to occur in every implementation. With the following code, the fourth column wraps to a new line, even though its flex-basis is set to 25% (and thus should remain on the first line).

.row {
    display: flex;
    flex-wrap: wrap;
    gap: 50px;
}

.col {
    flex: 1 1 25%;
}
<div class="row">
    <div class="col">
        Hello
    </div>
    <div class="col">
        World
    </div>
    <div class="col">
        Hello
    </div>
    <div class="col">
        World
    </div>
</div>

I believe this occurs because the flex-basis isn't taking in to account the gap that has been set. This sort of makes sense, but in practice it severely limits how gap can be used.

Proposed Solution

For this particular example, one possible workaround would be to set flex-basis: calc(25% - 37.5px);, which can be determined via the formula ($number-of-gaps * $gap) / $number-of-columns), however that doesn't take in to account situations where you have different sized columns within a flexed container (i.e. setting one of them to flex-basis: 50%). In theory, you could just work out the math each time you set up a flexed container, but this seems overly burdensome, especially if you want to re-use your grid system in multiple places throughout a project.

Similar to box-sizing: border-box; including borders within the box model for an element, there needs to be a property along the lines of flex-sizing: gap-box; that would include gap in to calculations based on flex-basis.

Demo

https://codepen.io/JacobDB/pen/ZEbJaNm

Activity

  1. rachelandrew commented on Aug 5, 2020

    @rachelandrew
    Contributor

    The problem here is that you are essentially disabling the flexibility of flexbox to make it act like a grid system. I think you would be better off in this situation using grid (even if the layout is essentially one dimensional). If you use the fr unit the gap will be taken into account.

  2. JacobDB commented on Aug 5, 2020

    @JacobDB
    Author

    The particular example I gave is very simplified just so that I could clearly illustrate the issue I'm seeing. In an actual project, I'd more likely be using a mix of percentage-sized columns, auto-sized columns, and "fill in the remaining space" columns.

    .col--auto {
        flex: 0 0 auto;
        /* some child of this would have `width: 250px;` */
    }
    
    .col--0 {
        flex: 1 1 0%;
        /* this would take up any remaining space not taken up by `.col--auto`  */
    }

    As you can see, this isn't restricted to a specific number of columns, which (to my understanding) renders grid unusable for my purposes. This is a grid system that I use extensively throughout projects, and therefore needs to be extremely adaptable; using grid restricts me to always relying on a fixed number of variable-width columns.

    I have experimented with switching my grid system to use grid, which you can view at the link below – if you can provide some guidance on how I can achieve my goals with grid alone, I'll happily close this issue, but from my perspective it just seems like a combination of flex for some purposes and grid for others is always going to be necessary. That being said, I could very well just be missing something obvious here.

    https://codepen.io/JacobDB/pen/rNBdxOg

  3. tabatkins commented on Nov 4, 2020

    @tabatkins
    Member

    Unfortunately, percent sizes on flex items aren't able to take gaps into account. Making them consider gaps means the base size of the item depends on the number of items in the line which depends on the base sizes of the other items... which creates a cycle. Instead, the percentages are resolved without consideration of siblings, only of the container, same as percentages in other layout modes like Block.

    As for your examples, we're not exactly understanding what you're trying to do...
    If you want a grid with four equally-sized columns, you do it like this:

    grid-template-columns: repeat(4, 1fr);
    

    and if you want one that has a content-sized column and a fill-remaining-space column, you do it like this:

    grid-template-columns: auto 1fr;
    

    From your last two examples, it appears that your ".col-auto" class would make the flex item fully flexible so it takes up all remaining space that isn't taken by other items already. It is indeed not possible to have a grid item automatically span columns based on unoccupied space in the grid. If you want that, you generally design your grid with an 1fr column as shown above, or if you do need something like a 12-col grid to start with, you instead count how many columns are taken up by the other items and give your "auto" item the correct span to fill the remaining columns.

    If there's a need to combine both kinds of layout (fixed-column and auto-spanning) in a single grid, please raise that as a separate issue with some clear examples, as we'll need to close this issue (percentage resolution in consideration of gaps) as no change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions