Making a child of a flex container NOT a flex item - html

I believe this goes exactly against the way the display: flex property is supposed to work, but I wonder if it's possible, or if there's a hack for it.
Is it possible to have a child of a flex container not behave as a flex item? Example:
http://jsbin.com/jusehedumi/edit?html,css,output
Is there any way in which child three could be made behave as a normal display block? Without it automatically aligning due to the justicity-content: center of the parent flex container?
A purely css solution would be awesome. Thinking about it, adding some extra HTML would probably make this issue easier to fix/solvable.
.flex{
display: flex;
justify-content: center;
width: 400px;
height: 400px;
background: #ccc;
}
.child{
width: 100px;
height: 100px;
background: red;
margin: 20px;
}
.child.three{
background: blue;
display: block;
}
Is there any way to make child three not behave as a flex child?
<div class="flex">
<div class="child one"></div>
<div class="child two"></div>
<div class="child three"></div>
</div>
Edit: I know a child can be taken out of the flex container by using position: absolute or the likes. What I'm looking for is a way of making one of the children behave as a block element (or inline for that matter) while remaining a child of the flex container.

Updated based on a question edit
No, there is no property that can be set, to make a flex container child stop being a flex item.
What can be done though, is to not use any flex properties on one, and by that make it behave as a block or inline-block element.
E.g., combined with flex-wrap: wrap enabling items to wrap, giving the third item flex: none will make it behave as an inline block, giving it width: 100% it will behave as a block (as shown below).
When it comes to flex container properties, some can be overridden on the item, like align-items / align-self, some cannot, like justify-content.
To mimic justify-content in your given code sample, auto margins could be used, and with that, together with a trick using the order property and a pseudo element, one could make the third behave like an inline block:
.flex{
display: flex;
flex-wrap: wrap;
align-content: flex-start;
width: 400px;
height: 400px;
background: #ccc;
}
.child{
width: 100px;
height: 100px;
background: red;
margin: 20px;
}
.child.one{
margin-left: auto;
}
.child.two{
margin-right: auto;
}
.flex::after{
content: '';
width: 100%;
order: 1;
}
.child.three{
background: blue;
order: 2;
}
Is there any way to make child three not behave as a flex child?
<div class="flex">
<div class="child one"></div>
<div class="child two"></div>
<div class="child three"></div>
</div>
As a note, here is a good answer that describes the flex item's display type:
What are allowed values of the `display` property for a flex-item? (layout of flex-item’s children is irrelevant)
Initial answer
Is it possible to have a child of a flex container not behave as a flex item?
There is no good, cross browser solution to make a flex container child not behave as a flex item.
One can use absolute positioning, though as it will take the element out of flow, it won't behave like a block element when it comes to content flow.
Is there any way in which child three could be made behave as a normal
display block?
Based on the fact that a normal block element take a row of its own, filling its parent's width, you can, by adding flex-wrap: wrap to the container and give the third item a width of 100%, make it behave like one.
Note, I also added align-content: flex-start; so the items won't stretch/spread along the parent's height, instead align at its top.
.flex{
display: flex;
flex-wrap: wrap;
justify-content: center;
align-content: flex-start;
width: 400px;
height: 400px;
background: #ccc;
}
.child{
width: 100px;
height: 100px;
background: red;
margin: 20px;
}
.child.three{
background: blue;
width: 100%;
}
Is there any way to make child three not behave as a flex child?
<div class="flex">
<div class="child one"></div>
<div class="child two"></div>
<div class="child three"></div>
</div>
If you want the third item to keep the same width as the first two, a wrapper could help you.
.flex{
display: flex;
flex-wrap: wrap;
justify-content: center;
align-content: flex-start;
width: 400px;
height: 400px;
background: #ccc;
}
.child{
width: 100px;
height: 100px;
background: red;
margin: 20px;
}
.child.three{
background: blue;
}
.wrapper{
width: 100%;
}
Is there any way to make child three not behave as a flex child?
<div class="flex">
<div class="child one"></div>
<div class="child two"></div>
<div class="wrapper">
<div class="child three"></div>
</div>
</div>
If a wrapper can't be used, you could use a right margin, though since percent based margin might render different on different browsers, you need to test it properly, or use another unit, e.g. viewport units, like vw.
.flex{
display: flex;
flex-wrap: wrap;
justify-content: center;
align-content: flex-start;
width: 400px;
height: 400px;
background: #ccc;
}
.child{
width: 100px;
height: 100px;
background: red;
margin: 20px;
}
.child.three{
background: blue;
margin-right: calc(100% - 120px);
}
Is there any way to make child three not behave as a flex child?
<div class="flex">
<div class="child one"></div>
<div class="child two"></div>
<div class="child three"></div>
</div>
If neither of the above solutions is an option, the same layout can be achieved using block and inline block elements.
.flex{
/* removed the Flexbox properties
display: flex;
flex-wrap: wrap;
justify-content: center;
*/
text-align: center; /* added */
width: 400px;
height: 400px;
background: #ccc;
}
.child{
display: inline-block; /* added */
width: 100px;
height: 100px;
background: red;
margin: 20px;
}
.child.three{
background: blue;
display: block;
}
<strike>Is there any way to make child three not behave as a flex child?</strike>
<div class="flex">
<div class="child one"></div>
<div class="child two"></div>
<div class="child three"></div>
</div>

Only elements that are in-flow children of a flex container are flex items.
Therefore, elements that are absolutely-positioned children or descendants beyond the children of a flex container are not flex items and ignore flex properties.
See my answer here for more details:
Absolutely positioned flex item is not removed from the normal flow in IE11

Related

Is flex's "align-items:flex-end" causing fixed-height divs inside flex-wrapped boxes to be vertically aligned according to each box's tallest one?

Doing a fairly basic HTML page I found myself perplexed by the following issue with flex in CSS.
First assume the following configuration:
A div wrapper with display: flex and applying justify-content: space-evenly, containing three inner boxes (could be more or less) each one also using flex (applying flex-wrap: wrap and align-items: end).
Each one of those inner boxes contains, in turn, two div elements: a top one and a bottom one (each with width: 100%); the bottom element has the same height while the top element has a different height per box; all of them are fixed heights in px.
This configuration looks more or less like this in HTML:
<div class="wrapper">
<div class="box">
<div class="top-element one"></div>
<div class="bottom-element one"></div>
</div>
<div class="box">
<div class="top-element two"></div>
<div class="bottom-element two"></div>
</div>
<div class="box">
<div class="top-element three"></div>
<div class="bottom-element three"></div>
</div>
</div>
And here's the CSS (written in SCSS to save space, I will include a snippet below where you can check the compiled CSS should you prefer); the commented line: "align-content: flex-end" indicates that I've already evaluated the effect of this property.
.wrapper {
display: flex;
justify-content: space-evenly;
.box {
display: flex;
align-items: flex-end;
// align-content: flex-end;
flex-wrap: wrap;
width: 30%;
.top-element {
width: 100%;
background-color: teal;
&.one {
height: 200px;
}
&.two {
height: 300px;
}
&.three {
height: 100px;
}
}
.bottom-element {
width: 100%;
background-color: lightblue;
&.one {
height: 100px;
}
&.two {
height: 100px;
}
&.three {
height: 100px;
}
}
}
}
Here's the snippet.
.wrapper {
display: flex;
justify-content: space-evenly;
}
.wrapper .box {
display: flex;
align-items: flex-end;
flex-wrap: wrap;
width: 30%;
}
.wrapper .box .top-element {
width: 100%;
background-color: teal;
}
.wrapper .box .top-element.one {
height: 200px;
}
.wrapper .box .top-element.two {
height: 300px;
}
.wrapper .box .top-element.three {
height: 100px;
}
.wrapper .box .bottom-element {
width: 100%;
background-color: lightblue;
}
.wrapper .box .bottom-element.one {
height: 100px;
}
.wrapper .box .bottom-element.two {
height: 100px;
}
.wrapper .box .bottom-element.three {
height: 100px;
}
<div class="wrapper">
<div class="box">
<div class="top-element one"></div>
<div class="bottom-element one"></div>
</div>
<div class="box">
<div class="top-element two"></div>
<div class="bottom-element two"></div>
</div>
<div class="box">
<div class="top-element three"></div>
<div class="bottom-element three"></div>
</div>
</div>
The issue is: It doesn't matter if you change the height of any of the top elements on any inner box, these remain vertically center-aligned according to the tallest element among all boxes, while the bottom ones remain at the bottom, and the space between top and bottom elements on each box is proportionally kept.
Now the question(s): is this correct css? and if so, I'm suspicious of align-items:"end" on each box to be the one to blame for this result, am I right? and if I'm wrong, why does this happen then?
Why didn't I use grid? well I'm in my flex phase... bear with me please.
You forget to define a vertical flex main direction for the elements with the CSS class .box.
Setting CSS property's flex-direction value to column for those elements fixes your problem.
SCSS
.box {
display: flex;
flex-direction: column;
...

change grid layout based on generic container size (not using classes)

In the following example I have two containers for a flex item. When the container is 300px I want the two 150px boxes to be side by side (as seen in the example). When the container is 150 however I'd like to change the container display to block to have them stacked on each other (we shouldn't see the yellow below).
Is it possible to write CSS WITHOUT leveraging the example_1 or example_2 classes and just referencing their container? I tried Chromes #container query but this didn't work... any help appreciated!!
.example_1 {
width: 300px;
height: 30px;
background-color: yellow;
}
.example_2 {
width: 150px;
height: 60px;
background-color: yellow;
}
.flex-thing {
display: flex;
flex-direction: row;
width: max-content;
justify-content: stretch;
}
.flex-thing .item {
background-color: red;
width: 150px;
height: 30px;
border: solid 1px black;
}
<div class="example_1">
<div class="flex-thing">
<div class="item"></div>
<div class="item"></div>
</div>
</div>
<br>
<div class="example_2">
<div class="flex-thing">
<div class="item"></div>
<div class="item"></div>
</div>
</div>
If you want the red box to auto wrap down to second line, you need to add flex-wrap: wrap; to the container. or you can add
.example_2 .flex-thing{
flex-direction: column;
}

Vertical alignment flexbox

I am trying to place child elements in parent element using flexbox like in this image -- >
https://ibb.co/Wpph8fP.
I know that this is possible by doing three columns then use flex, then flex-column in the first column and center other two vertically.
The thing is, that I need do this in one parent div. 4th element is wrapped and it creates column with 1st element, then I need to center vertically two other elements.
This is what I have already done:
the code is here https://codepen.io/MrEyelet/pen/wLxygN?editors=1100
To use one flex, first set flex-direction to column and set wrap toflex-wrap.
And, the part that needs to be on two lines has a variable height to avoid line breaks.
Next, set the flex property to none, setting margin enough to make a line break in the part that needs to be on one line. This will force flex items to break and keep the size of the item.
flex - Values[mdn]
none
The item is sized according to its width and height properties. It is fully inflexible: it neither shrinks nor grows in relation to the flex container. This is equivalent to setting "flex: 0 0 auto".
body {
background: tomato;
margin: 0;
}
.parent {
display: flex;
justify-content: center;
align-items: center;
flex-flow: column wrap;
height: 100vh;
}
.child {
width: 30%;
height: 200px;
margin: 20px 0;
background: indigo;
}
/* add below */
.child:nth-of-type(-n+2) {
flex: 1 0 calc(50% - 40px);
}
/* add below */
.child:nth-of-type(n+3) {
flex: none;
margin: 50% 0;
}
<div class="parent">
<div class="child child-1">
</div>
<div class="child child-2">
</div>
<div class="child child-3">
</div>
<div class="child child-4">
</div>
</div>

Control width of flex items arranged vertically in a flex container

I'm trying to achieve the effect where the boxes labeled "HALF", take up only 50% of the width (aka they share the first row evenly).
The base requirement is that they remain in a single container. Is this possible to achieve using flexbox?
I've tried playing around with flex-grow, flex-shrink, and flex-basis but I'm afraid I'm not understanding how to make it work, or if it's even possible, given the single container requirement.
Consider this fiddle: http://jsfiddle.net/GyXxT/270/
div {
border: 1px solid;
}
.container {
width: 400px;
display: flex;
flex-direction: column;
}
.child {
height: 200px;
}
.child.half {
flex: 1 1 10em;
color: green;
}
.child:not(.half) {
flex-shrink: 2;
flex-basis: 50%;
color: purple;
}
<div class="container">
<div class="child half">
HALF
</div>
<div class="child half">
HALF
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
</div>
Instead of flex-direction: column, you can try a wrapping flexbox using flex-wrap: wrap; and you can set:
flex-basis: 50% for the half width divs
flex-basis: 100% for the full width divs
See that I have thrown in box-sizing: border-box to adjust for the widths when using flex-basis.
See demo below:
div {
border: 1px solid;
box-sizing: border-box;
}
.container {
width: 400px;
display: flex;
flex-wrap: wrap;
}
.child {
height: 200px;
}
.child.half {
flex-basis: 50%;
color: green;
}
.child:not(.half) {
flex-basis: 100%;
color: purple;
}
<div class="container">
<div class="child half">
HALF
</div>
<div class="child half">
HALF
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
</div>
The flex sizing properties -- flex-grow, flex-shrink, flex-basis and flex -- work only along the main axis of the flex container.
Since your container is flex-direction: column, the main axis is vertical, and these properties are controlling height, not width.
For sizing flex items horizontally in a column-direction container you'll need the width property.
(Here's a more detailed explanation: What are the differences between flex-basis and width?)
To achieve your layout with a single container, see another answer to this question.
If you want to stay in column-direction, you'll need to wrap the .half elements in their own container.
.container {
display: flex;
flex-direction: column;
width: 400px;
}
.container > div:first-child {
display: flex;
}
.child.half {
flex: 1 1 10em;
color: green;
width: 50%;
}
.child {
height: 200px;
width: 100%;
border: 1px solid;
}
* {
box-sizing: border-box;
}
<div class="container">
<div><!-- nested flex container for half elements -->
<div class="child half">HALF</div>
<div class="child half">HALF</div>
</div>
<div class="child">FULL</div>
<div class="child">FULL</div>
<div class="child">FULL</div>
<div class="child">FULL</div>
</div>
The base requirement is that they remain in a single container.
That can also be done without flexbox, by simply float the 2 half elements
div {
border: 1px solid;
box-sizing: border-box;
}
.container {
width: 400px;
}
.child {
height: 200px;
}
.child.half {
float: left;
width: 50%;
color: green;
}
.child:not(.half) {
width: 100%;
color: purple;
}
<div class="container">
<div class="child half">
HALF
</div>
<div class="child half">
HALF
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
<div class="child">
FULL
</div>
</div>
If the purpose is to hardcode the size in CSS units, or in percentages (which was mentioned the question), #kukkuz's solution is good as it is.
If you want to size element widths according to their own individual contents, then align-tems: flex-start or similar could do the job. It's possible to deal with the dimension perpendicular to that of the flex layout itself. See a tester on the bottom of the doc page
(Old question, but previous answers were incomplete, some are misleading)

inline-flex container with column-reverse impacting alignment of sibling inline-flex containers

In my code, two inline flex divs sit next to each other.
In the first inline flex div, flex items were set to flex-direction:column-reverse. However, this affects its sibling inline flex div's position horizontally. By that I mean, the sibling flex positioned differently when the flex was set to flex-direction: column. I don't understand why this behaves like this.
My understanding is that flex-direction only controls the position of its children, i.e. flex items, and it has no effect on its sibling flex divs. But obviously this seems to be wrong. Can anyone explains why? Thanks!
.flex {
display: inline-flex;
border: solid;
margin: 10px;
}
.box {
background: papayaWhip;
width: 100px;
height: 100px;
margin: 10px;
padding: 10px;
}
.column-reverse {
flex-direction: column-reverse;
}
.column {
flex-direction: column;
}
<div class="flex column-reverse">
<div class="box">item1</div>
<div class="box">item2</div>
</div>
<div class='flex'>
<div class="box">item1</div>
<div class="box">item2</div>
</div>
<div class="flex column">
<div class="box">item1</div>
<div class="box">item2</div>
</div>
It sounds reasonable to expect that flex items in column-reverse in an inline-flex container would simply reverse, and not affect the horizontal alignment of other elements on the line.
In reality, however, this is not the case.
In an inline-flex container, column-reverse switches the direction of the flex items (as expected), but also reverses the flow of the container (upward).
From your code (three inline-flex containers, with an added red border around the parent):
This doesn't seem to be a bug. The behavior is the same cross-browser (tested in Chrome, FF, IE11).
The issue is possibly the result of two factors:
the vertical-align property
column-reverse specification rules
vertical-align
The initial value of the vertical-align property, which applies to inline-level elements, is baseline.
This is the value that is applied whether the container is column or column-reverse.
The alignment of flex item #1 doesn't change probably because (from the spec):
5.1. Flex Flow Direction: the flex-direction
property
column-reverse
Same as column, except the main-start and main-end directions are
swapped.
Note: The reverse values do not reverse box ordering: like
writing-mode and direction, they only change the direction of flow.
Painting order, speech order, and sequential navigation orders are not
affected.
If I'm reading this correctly, column-reverse doesn't actually change the order of flex items. It reverses the flow of the container. This would explain the upward expansion of the first container.
Solution #1
One method of resolving the problem, as described in #NenadVracar's answer, is to adjust the value of vertical-align. Switching from the default baseline value to top does the trick.
.flex {
display: inline-flex;
border: solid;
margin: 10px;
vertical-align: top; /* NEW */
}
.box {
background: papayaWhip;
width: 100px;
height: 100px;
margin: 10px;
padding: 10px;
}
.column-reverse {
flex-direction: column-reverse;
}
.column {
flex-direction: column;
}
<div class="flex column-reverse">
<div class="box">item1</div>
<div class="box">item2</div>
</div>
<div class='flex'>
<div class="box">item1</div>
<div class="box">item2</div>
</div>
<div class="flex column">
<div class="box">item1</div>
<div class="box">item2</div>
</div>
Solution #2
Making the parent of the inline-flex divs a flex container also solves the problem:
body {
display: flex; /* NEW */
align-items: flex-start; /* NEW; optional; to disable equal height columns */
}
.flex {
display: inline-flex;
border: solid;
margin: 10px;
}
.box {
background: papayaWhip;
width: 100px;
height: 100px;
margin: 10px;
padding: 10px;
}
.column-reverse {
flex-direction: column-reverse;
}
.column {
flex-direction: column;
}
<div class="flex column-reverse">
<div class="box">item1</div>
<div class="box">item2</div>
</div>
<div class='flex'>
<div class="box">item1</div>
<div class="box">item2</div>
</div>
<div class="flex column">
<div class="box">item1</div>
<div class="box">item2</div>
</div>
Since default vertical-align is baseline it seems that when you change order of flex items or column-reverse in this case, they are still aligned with item1 but if you change vertical-align to top they are aligned to top, vertical-align: middle will also work here Fiddle
.flex {
display: inline-flex;
vertical-align: top;
border: solid;
margin: 10px;
}
.box {
background: papayaWhip;
width: 100px;
height: 100px;
margin: 10px;
padding: 10px;
}
.column-reverse {
flex-direction: column-reverse;
}
.column {
flex-direction: column;
}
<div class="flex column-reverse">
<div class="box">item1</div>
<div class="box">item2</div>
</div>
<div class='flex'>
<div class="box">item1</div>
<div class="box">item2</div>
</div>
<div class="flex column">
<div class="box">item1</div>
<div class="box">item2</div>
</div>