flexbox + bootstrap 4. How to stretch child of .col-**-*? - css

I love flexbox and I love bootstrap also. But looks like flexbox features is kind of useless with bootstrap flex for some frequent cases and a lot of custom tweaking is required
For example I use .col-**-* to make grid and add child classes for custom styles, like background
My common problem with nested child is that child doesn't behave as flex child and do not fill the container.
I have to add .child block do .col-**-* to make background and tweak margin/paddings, which is not very handy. Are there any better ways to do so?
http://codepen.io/dpmango/pen/VPKKMw
body
.row
.col-sm-6
.child.child--red
p This block is bigger than sibling! This block is bigger than sibling! This block is bigger than sibling! This block is bigger than sibling! This block is bigger than sibling!
.col-sm-6
.child.child--blue
p I want to grow :-
CSS
// demo
.col-sm-6
padding-top: 20px
padding-bottom: 20px
background: black
border: 1px solid red
// OK - it's same height and stretched
.child
color: white
padding: 30px
&--red
background: tomato
&--blue
background: blue
//this one is not same height

By using display: flex and flex: 1 / flex-basis: 100% it grows
.col-sm-6
padding-top: 20px
padding-bottom: 20px
background: black
border: 1px solid red
display: flex
.child
flex: 1 /* fill remaining height */
flex-basis: 100% /* set full width */
Updated codepen
Or like this, using flex-direction: column and flex: 1
.col-sm-6
padding-top: 20px
padding-bottom: 20px
background: black
border: 1px solid red
display: flex
flex-direction: column /* full width by default */
.child
flex: 1 /* fill remaining height */
Updated codepen 2

Related

My dividers change size and move about oddly when the window is resized

Below is the main container, side and card containers for my site.
when I resize the window they move and resize themselves and stack on top of each other, I would like them to stay the same size and just have a horizontal scroll bar.
.main {
width: 75%;
}
.side {
background-color: #232323;
border-left: 4px solid #395d9e;
float: left;
width: 16%;
padding: 57px 15px;
height: 100%;
}
.card {
float: left;
background-color: #232323;
padding: 0 15px;
margin: 80px 0 0 20px;
padding: 15px;
width: 82%;
border-radius: 4px;
}
It would help to see your relevant html also, but you have a few things going on here. First, your total for .main, .side and .card total 173%. This might not matter if .card is inside .main or .side.
Next, consider using the css property box-sizing:border-box. In CSS, width is calculated as the sum of (element width + padding + border + margin). Using border-box, the padding and border are considered part of the total width. In other words, for .side, the 16% will include your 15px right and left padding.
Finally, even using border-box, your right and left margins affect total width. If both .card and .side are located inside .main, you could set your right margin for .card as a percent (e.g. margin: 80px 0 0 2%;) and a percentage for the .side element as well.
What is happening here is when you resize your browser window to a small width, the fixed padding and margin can force your elements to float below the others. Assuming .side and .card are inside .main, they have a total declared width of 98% + 80px. You would need (if this is the case) a width of 4000px to contain both .side and .card.
Try using box-sizing:border-box for all 3 elements, and use percentage based margin and possibly padding.

CSS Flexbox height

I'm trying to make a chat layout. So i have 3 divs, activeUSer - top, messages middle (has to fill the space between 1 and 3), actions - bottom
Now, I've put flex-direction row. and it works fine. I needed the bottom div to grow if the input grows (if you have 2 or more lines of writing)
It worked ok untill I added display:flex to the Actions div (bottom). I needed another flex layout for input and buttons. Now it does not care for the padding i've set on the last div
Here is my codepen https://codepen.io/capraruioan/pen/XKWxrV
#content {
height: 300px;
display: flex;
flex-direction: column;
}
.activeUser {
height: 66px;
background-color: yellow;
}
.Messages {
flex: 1 1 100%;
}
.Actions {
flex-grow: 1;
display: flex;
padding-top: 2px;
padding-bottom: 20px;
}
.aa { //the inputbox
border: 1px solid black;
min-height: 10px
}
fixed it by letting display default on the 3rd div and placing a div with display flex inside

Collapsing margin on Flexbox children

I have the following arrangement via flexbox with flex-wrap and elements able to stretch using flex-grow:
Each item has a margin on all sides. This is to separate the items from each other, but the side effect is the whole block has margins which I'd like to collapse. It could be done with rules like nth-child(-n+3) { margin-top: 0; } but because the container size could vary, there could be any number of items per row and any number of rows. So I'm wondering if flex-box has any way to collapse the outer margins in a setup like this, while retaining the margins between items.
JSBin
The HTML is simply 6 items inside a container.
The CSS (Sass) is as follows:
.container
display: flex
flex-wrap: wrap
background: #eef
align-items: stretch
.item
flex-grow: 1
margin: 1em
border: 1px solid black
padding: 1em
min-width: 6em
It's a bit of a hack, but you can add a negative margin on the flex container to cancel out the items' margins along the edges, and then move its "background" styling to a parent wrapper-element.
Updated JSBin
Updated CSS (SASS):
.wrapper
background: #eef
border: 1px solid darkgray
.container
display: flex
flex-wrap: wrap
margin: -1em
.item
flex-grow: 1
margin: 1em
border: 1px solid black
padding: 1em
min-width: 6em
Another hack is to split the margin responsibilities between container and item, each caring about half (say $margin is 1em):
• container cares about its bottom margin and half left + half-right of items:
.container {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: wrap; // Go to next line if not enough space
padding-top: 0; // Let items handle top
padding-left: $margin/2; // Handle half of left
padding-bottom: $margin; // Handle bottom
padding-right: $margin/2; // Handle half of right
}
• items care about top and half left + half right:
.item {
flex-grow: 1; // Use available space
margin-left: $margin/2; // Handle other half of left
margin-right: $margin/2; // Handle other half of right
margin-top: $margin; // Handle top
}
Regarding items size, you can set a width if you want items to look the same.
.item.fixed {
width: 15em;
}
See a demo here.

Padding-bottom/top in flexbox layout

I have a flexbox layout containing two items. One of them uses padding-bottom :
#flexBox {
border: 1px solid red;
width: 50%;
margin: 0 auto;
padding: 1em;
display: flex;
flex-direction: column;
}
#text {
border: 1px solid green;
padding: .5em;
}
#padding {
margin: 1em 0;
border: 1px solid blue;
padding-bottom: 56.25%; /* intrinsic aspect ratio */
height: 0;
}
<div id='flexBox'>
<div id='padding'></div>
<div id='text'>Some text</div>
</div>
The blue element maintains its aspect ratio according to its width when the page is resized.
This works with Chrome and IE and looks like :
However, in Firefox and Edge, I get the following (it's ignoring the padding on the blue box, which is what maintains the aspect ratio):
I'm too new to flexbox to really understand if this should or shouldn't work. The whole point of flexbox is to resize things, but I'm not sure why it is ignoring the intrinsic padding, and putting absolute sizes on the blue element.
I guess ultimately I'm not even sure if Firefox or Chrome is doing the correct thing! Can any Firefox flexbox experts help?
Update September 2020
Firefox and edge have implemented the behaviour from the specs and margin + padding for flex elements are both calculated according to the width of the containing block.
Just like block elements.
Update February 2018
Firefox and edge have agreed to change their behaviour on top, bottom margin and padding for flex (and grid) items :
[...] e.g. left/right/top/bottom percentages all resolve against their containing block’s width in horizontal writing modes. [source]
This is not yet implemented (tested on FF 58.0.2).
Update April 2016
(still valid in may 2017)
The specs have been updated to:
Percentage margins and paddings on flex items can be resolved against either:
their own axis (left/right percentages resolve against width, top/bottom resolve against height), or,
the inline axis (left/right/top/bottom percentages all resolve against width)
source: CSS Flexible Box Layout Module Level 1
This means that chrome IE FF and Edge (even if they don't have the same behaviour) follow the specs recommendation.
Specs also say:
Authors should avoid using percentages in paddings or margins on flex
items entirely, as they will get different behavior in different
browsers. [source]
Workaround
You can wrap the first child of the flex container in an other element and put the padding-bottom on the second child :
#flexBox {
border: 1px solid red;
width: 50%;
margin: 0 auto;
padding: 1em;
display: flex;
flex-direction: column;
}
#text {
border: 1px solid green;
padding: .5em;
}
#padding {
margin: 1em 0;
border: 1px solid blue;
}
#padding > div {
padding-bottom: 56.25%; /* intrinsic aspect ratio */
}
<div id='flexBox'>
<div id='padding'><div></div></div>
<div id='text'>Some text</div>
</div>
I tested this in modern browsers (IE, chrome, FF and Edge) and they all have the same behaviour. As the configuration of the 2nd child is the "same as usual", I suppose that older browsers (that also support flexbox layout module) will render the same layout.
Previous answer
According to the specs, Firefox has the right behaviour
Explanation
Unlike block items which calculate their % margin/padding according to the containers width, on flex items:
Percentage margins and paddings on flex items are always resolved
against their respective dimensions; unlike blocks, they do not always
resolve against the inline dimension of their containing block.
source dev.w3.org
This means that padding-bottom/top and margin-bottom/top are calculated according to the height of the container and not the width like in non-flexbox layouts.
As you have not specified any height on the parent flex item, the bottom padding of the child is supposed to be 0px.
Here is a fiddle with a fixed height on the parent that shows that padding bottom is calculated according to the height of the display:flex; container.
The accepted answer is correct but I improved on the solution by using a pseudo-element instead of adding a new element in to the HTML.
Example: http://jsfiddle.net/4q5c4ept/
HTML:
<div id='mainFlexbox'>
<div id='videoPlaceholder'>
<iframe id='catsVideo' src="//www.youtube.com/embed/tntOCGkgt98?showinfo=0" frameborder="0" allowfullscreen></iframe>
</div>
<div id='pnlText'>That's cool! This text is underneath the video in the HTML but above the video because of 'column-reverse' flex-direction. </div>
</div>
CSS:
#mainFlexbox {
border: 1px solid red;
width: 50%;
margin: 0 auto;
padding: 1em;
display: flex;
flex-direction: column-reverse;
}
#pnlText {
border: 1px solid green;
padding: .5em;
}
#videoPlaceholder {
position: relative;
margin: 1em 0;
border: 1px solid blue;
}
#videoPlaceholder::after {
content: '';
display: block;
/* intrinsic aspect ratio */
padding-bottom: 56.25%;
height: 0;
}
#catsVideo {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
I used vh instead of % worked perfectly in Safari, Firefox & Edge

Vertical-align: middle in table-cell

My markup is:
li
.wrapper
p = #album_count
h3 Albums
The above is in Slim
My styles are:
li
+span-columns(3, 12)
+nth-omega(4)
position: relative
color: $body-text
h3
text-transform: uppercase
text-align: center
.wrapper
position: relative
display: table
display: block
width: 100%
height: 0
padding-bottom: 94.6%
+border-radius(50%)
border: 6px solid $white
border: remCalc(6px) solid $white
text-align: center
background-color: #266997
+box-shadow(inset 3px 3px 3px #0B5486)
+box-shadow(inset remCalc(3px) remCalc(3px) remCalc(3px) #0B5486)
&:after
content: ''
position: absolute
left: 10%
top: 10%
width: 80%
height: 80%
+border-radius(50%)
background-color: white
+box-shadow(3px 3px 3px #0B5486)
+box-shadow(remCalc(3px) remCalc(3px) remCalc(3px) #0B5486)
p
position: absolute
display: table-cell
width: 100%
height: 100%
vertical-align: middle
z-index: 10
Basically, I end up with the .wrapper being a specific width due the Compass Susy column it is sat in and the height becomes the same due to the 94% bottom padding. It's 94% due to the h3 underneath. This is something I will be changing but this isn't the issue here.
The problem I have is with the p, I have absolutely positioned it and set it's height and width to be 100% each so it sits on top of the circle .wrapper. That works fine. I then displays the .wrapper as a css table and the p as a css table cell and added vertical-align: middle. This should work as far as I am aware but it is not making any difference at all in this case.
Is anyone able to help?
You can't display as table-cell an absolutely positioned element: relationships between 'display', 'position', and 'float' (CSS2.1 REC)
EDIT: is there a typo in .wrapper? You've 2 instructions involving display and for compatibility reasons with IE6/7 I can understand why you would first display as block for every browser and then for IE8+ as table but here: .wrapper is a div (I think) and it's already block by default and it's written the other way around (table than block so it's block for everybody)

Resources