Marcus Junius Brutus Marcus Junius Brutus - 26 days ago 12
CSS Question

alignment breaks when placed inside other container

I am exploring Flexbox and am trying to align some items. The following code works and shows what I want to achieve (successful codepen here):



.labelinput {
display: flex;
flex-flow: row;
margin: 1px;
}
.labelinput > *:first-child {
flex-basis: 10em;
flex-grow: 0;
flex-shrink: 0;
}
.labelinput > *:nth-child(2) {
flex-grow: 1;
flex-shrink: 1;
border: 3px solid purple;
}

<div class='labelinput'>
<div>1st input</div>
<div>this is just a div</div>
</div>
<div class='labelinput'>
<div>2nd:</div>
<input type="text" name="foo" value="this is an input box" />
</div>





The above code produces the nicely align output shown below:

enter image description here

My reading of the above code is that it works because the first child in every
div
has a determined size (
10em
) and is totally inflexible (
flex-grow
and
flex-shrink
set to 0) whereas the second child has no determined size and will grow and shrink as appropriately.

What breaks though is when I try to embed the two top-level
div
elements (of class
labelinput
) into yet another container (failing codepen here):



#container {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
margin: 5px;
border: 1px solid grey;
}
.labelinput {
display: flex;
flex-flow: row;
margin: 1px;
}
.labelinput > *:first-child {
flex-basis: 7em;
flex-grow: 0;
flex-shrink: 0;
}
.labelinput > *:nth-child(2) {
flex-grow: 1;
flex-shrink: 1;
border: 3px solid purple;
}

<div id='container'>
<div class='labelinput'>
<div>1st input</div>
<div>this is just a div</div>
</div>
<div class='labelinput'>
<div>2nd:</div>
<input type="text" name="foo" value="this is the input box" />
</div>

</div>





The above produces the following unsatisfactory output:

enter image description here

I can't explain why this fails as I am just inserting the content of the successful case into a container that simply performs the default vertical stacking (
flex-direction: column;
).

By experimentation I have discovered that removing the
align-items
property from the outer level container (
#container
) fixes the problem but I can't explain that either.

I understand that the outermost container (
#container
) is asked to layout two other containers (of class
labelinput
) so whatever property I set for
align-items
in the outermost container should apply to the inner containers as a whole, not change the layout of their internal items.

Moreover I can't explain why the layout is changed based on the element type when there's nothing in my CSS that differentiates between items of element
div
versus items of element
input
.

Answer

When you nest the .labelinput flex containers in a larger container (#container), then the .labelinput elements become flex items, in addition to flex containers.

Since the #container flex container is set to flex-direction: column, the main axis is vertical and the cross axis is horizontal.

The align-items property works only along the cross axis. It's default setting is align-items: stretch, which causes flex items to expand the full width of the container.

By experimentation I have discovered that removing the align-items property from the outer level container (#container) fixes the problem but I can't explain that either.

Because stretch is the default value for align-items, when you omit this property altogether, you get the behavior you want.

When you override the default with align-items: flex-start (like in your code), you pack the two labelinput items to the start of the container (as illustrated in your image).

I understand that the outermost container (#container) is asked to layout two other containers (of class .labelinput) so whatever property I set for align-items in the outermost container should apply to the inner containers as a whole, not change the layout of their internal items.

The outermost container is not changing the layout of the inner container's children. At least not directly.

The align-items: flex-start rule on the outermost container is applying directly to the inner containers. The internal items of the inner containers are just responding to the sizing adjustment of their parent.

Here's an illustration of align-items: flex-start impacting .labelinput (red borders added).

#container {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: flex-start;
  margin: 5px;
  border: 1px solid grey;
}
.labelinput {
  display: flex;
  flex-flow: row;
  margin: 1px;
  border: 2px dashed red;
}
.labelinput > *:first-child {
  flex-basis: 7em;
  flex-grow: 0;
  flex-shrink: 0;
}
.labelinput > *:nth-child(2) {
  flex-grow: 1;
  flex-shrink: 1;
  border: 3px solid purple;
}
<div id='container'>
  <div class='labelinput'>
    <div>1st input</div>
    <div>this is just a div</div>
  </div>
  <div class='labelinput'>
    <div>2nd:</div>
    <input type="text" name="foo" value="this is the input box" />
  </div>
</div>

Comments