简体   繁体   中英

How to evenly distribute width between flexbox children with nested flexboxes?

I am working on some css3 for a website I'm building. I'm attempting to make a "container" class that uses flexbox to make all its children have equal width. This works properly, but when I put a "container" and a normal element inside another "container", the two children are not of equal width.

I'm not sure why this isn't working, as it works for any element that is not a container.

HTML:

<div class="container">
  <div class="container">
    <div class="content-box">
      One Sixth
    </div>
    <div class="content-box">
      One Sixth
    </div>
    <div class="content-box">
      One Sixth
    </div>
  </div>
  <div class="content-box">
    One half
  </div>
</div>

CSS:

.container {
    display: flex;
    align-items: flex-start;
}

.container > * {
    flex-basis: 100%;
    min-width: 0;
}

.container > :not(:first-child) {
    margin-left: 2%;
}

Codepen example: https://codepen.io/NetworkOverflow/pen/XLbdqa

The problem is when you put a container inside of a container it's adding the margin so you see double the space on the right.

I would set your container to justify-content: space-between; which pushes content elements to the outside edges. I'm using flex:1 instead of flex-basis to tell the browser that each element should take up the same amount of space.

Your CSS becomes:

.container {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
}

.container > * {
    flex: 1;
    margin-left: 2%;
    min-width: 0;
}

.container > *:first-child {
    margin-left:0;
}

/* not needed
.container > :not(:first-child) {
    margin-left: 2%;
}
*/

Update:

Depending on the usage, it's sometimes helpful to add "sizing" classes that force a flex-basis based on the number of items. Here's a codepen example.

.third {
  flex-basis: calc(33.3333% - 2%);
}
.half {
  flex-basis: calc(33.3333% - 2%);
}

You're paying a price for setting all elements to flex-basis: 100% .

Because you're telling all elements, regardless of the number of siblings they may have, to occupy the full width of the container, you're forcing flex-shrink to calculate the space necessary to accommodate them all.

This involves a relatively complex flexbox algorithm, which gets even more complex when you factor in padding and box-sizing: border-box , both of which exist in your code.

The algorithm is explained here: How does flex-shrink factor in padding and border-box?

The quickest and easiest solution would be to specify the actual width of the containers.

For the row illustrating the problem (with a container, and a container within a container), instead of setting them to flex-basis: 100% , which triggers flex-shrink , set them to flex-basis: 50% . Now the flex-shrink process is avoided and you get what you want.

I added this to your code:

.container > .demo50 {
  flex-basis: 50%;
}

revised demo

 div.content { float: left; width: 100%; height: 100%; background-color: var(--background-color2); padding: 2% 10%; } div.banner { background-color: var(--scheme-color2); box-shadow: 0px 0px 50px 10px rgba(23, 196, 167, 0.5); padding: 1rem; text-align: center; margin-bottom: 2em; } .content-box { background-color: var(--background-color1); box-shadow: 0px 0px 10px 5px rgba(84, 84, 84, 1); padding: 1rem; overflow-wrap: break-word; margin-bottom: 2em; } .container { display: flex; align-items: flex-start; } .container > * { flex-basis: 100%; min-width: 0; } .container > :not(:first-child) { margin-left: 2%; } .two-thirds { flex-basis: calc(100% / 3 * 2); } .container > .demo50 { flex-basis: 50%; } * { margin: 0; padding: 0; box-sizing: border-box; } :root { --background-color1: #707070; --background-color2: #424242; --background-color3: #afafaf; --scheme-color1: #20f9d5; --scheme-color2: #17c4a7; --scheme-color3: #89e5d6; --text-color: #e3edeb; } body { font-family: "Open Sans", sans-serif; color: var(--text-color); } 
 <div class="content"> <div class="container"> <div class="banner"> <h1>Example</h1> </div> </div> <div class="container"> <div class="content-box"> <p>Using 'flex-basis: 100%' seems to work perfectly well for evenly sizing and spacing elements in a row. However, when you put a .container inside a .container and attempt to do something like you see two rows below, the .container element and the element that follows do not space themselves at half and half width.</p> </div> </div> <div class="container"> <div class="content-box"> One Half </div> <div class="content-box"> One Half </div> </div> <div class="container"> <div class="container demo50"> <div class="content-box"> One Sixth </div> <div class="content-box"> One Sixth </div> <div class="content-box"> One Sixth </div> </div> <div class="content-box demo50"> One half </div> </div> <div class="container"> <div class="content-box"> One Third </div> <div class="content-box"> Two Thirds </div> <div class="content-box"> Three Thirds </div> </div> <div class="container"> <div class="content-box two-thirds"> Two Thirds </div> <div class="content-box"> One Third </div> </div> <div class="container"> <div class="content-box"> One Third </div> <div class="content-box two-thirds"> Two Thirds </div> </div> </div> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM