How to use css3 'flexbox' to make a layout like this? - css

Here is a div container. I know how to easily use display and width to make it look like this, but how to use CSS3 flexbox to make 4 buttons layout as follow?
.container {
background-color: blue;
width: 200px;
padding: 10px;
}
button {
display: block;
width: 100%;
}
button:nth-of-type(2),
button:nth-of-type(3) {
width: 49%;
display: inline;
}
<div class="container">
<button>Button1</button>
<button>Button1</button>
<button>Button1</button>
<button>Button1</button>
</div>

Use flex-flow:row wrap and make the top / bottom buttons take twice the space
div, div *{box-sizing:border-box;}
div{display:flex;flex-flow:row wrap;padding:50px;}
div button{flex:1;}
div button:first-child,
div button:last-child{flex:2 100%}
<div>
<button>1</button>
<button>2</button>
<button>3</button>
<button>4</button>
</div>

HTML
<div class="container">
<button>Button1</button>
<button>Button2</button>
<button>Button3</button>
<button>Button4</button>
</div>
CSS
.container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
background-color: blue;
width: 200px;
padding: 10px;
}
button { margin: 5px 0; }
button:nth-of-type(1),
button:nth-of-type(4) { flex: 1 1 100%; }
button:nth-of-type(2),
button:nth-of-type(3) { flex: 0 1 45%; }
DEMO

Related

How do I make parent container and other child in Flex to grow as one of the longest child

I need to the container and the green div to grow as the same size as blue whenever things inside the blue div grow.
.container {
background: grey;
height: 200px;
flex-direction: column;
padding: 10px;
display: flex;
}
.normal {
background: green;
}
.wide {
width: 2500px;
background: blue;
flex: 1 0 auto;
}
<div class="container">
<div class="normal">Normal</div>
<div class="wide">Wide</div>
</div>
CodePen
consider inline-flex instead
.container {
background: grey;
height: 200px;
flex-direction: column;
padding: 10px;
display: inline-flex;
min-width:100%; /*to make sure it behave like flex if the content is small*/
box-sizing:border-box;
}
.normal {
background: green;
}
.wide {
width: 2500px;
background: blue;
flex: 1 0 auto;
}
<div class="container">
<div class="normal">Normal</div>
<div class="wide">Wide</div>
</div>
Related: Why does the outer <div> here not completely surround the inner <div>?

Making an input and two buttons aligned using SCSS

I want my two buttons, that are actually <a> tags, stick with my input, and be the same size as input. Image perfectly describes what I want to achieve.
Note that I am just starting to learn SASS and CSS. I have tried with this but no luck
NumberInput.js
<div
className="NumberInput"
data-key={dataKey}>
<div className="numberInputField">
<input
data-key={dataKey}
type="text"
name="number"
value={getValue(datakey)}
onChange={onChange(datakey)}/>
</div>
<div className="buttonsField">
<div className="row">
<ValueChangeButton/>
</div>
<div className="row">
<ValueChangeButton/>
</div>
</div>
</div>
NumberInput.scss
$inputMaxWidth: 450px;
$maxHeight: 80px;
$btnFieldMaxWidth: 150px;
.NumberInput{
max-width: $inputMaxWidth;
max-height: $maxHeight;
.numberInputField{
display: inline-block;
text-align: center;
max-width: inherit;
max-height: inherit;
}
.buttonsField{
display: inline-block;
max-width: $btnFieldMaxWidth;
max-height: $maxHeight;
.button{
width: auto;
height: auto;
}
}
}
The result I get is, buttons are contained in their respective rows, but are not the same size as input, and they are flying all around the page. Also, if I change the className of my input, and set the className of its <div> to "numberInputField", it doesn't change its width and height.
Flexbox is perfect for this:
body {
margin: 1em;
}
.NumberInput {
display: flex;
max-width:450px;
margin:auto;
}
.numberInputField {
flex: 3; /* say 3/4 of width */
display: flex;
flex-direction: column;
}
input {
padding: 1em 4em;
flex: 1;
}
.buttonsField {
flex: 1; /* say 1/4 of width */
display: flex;
flex-direction: column;
}
.row {
flex: 1; /* share width equally */
}
a {
width: 100%;
display: block;
background: rebeccapurple;
text-align:center;
text-decoration: none;
font-size: 1.5em;
color: white;
border:1px solid grey;
}
<div class="NumberInput">
<div class="numberInputField">
<input type="submit" />
</div>
<div class="buttonsField">
<div class="row">
↑
</div>
<div class="row">
↓
</div>
</div>
</div>

Display table on flex item

My question is simple. Is it possible to have display: table on a flex item?
When I set it on an item, the layout doesn't work as expected - the second flex item doesn't grab the available vertical/horizontal space.
.parent {
min-height: 200px;
border: 1px solid black;
display: flex;
flex-direction: column;
text-align: center;
}
.header {
background-color: gray;
}
.content {
flex: 1;
display: table;
background-color: red;
}
.content > span {
display: table-cell;
vertical-align: middle;
}
<div class="parent">
<div class="header">
<span>Header</span>
</div>
<div class="content">
<span>Main content</span>
</div>
</div>
Of course you can, but not necessarily a good solution though.
May I suggest you use flex all the way.
.parent {
min-height: 200px;
border: 1px solid black;
display: flex;
flex-direction: column;
text-align: center;
}
.header {
background-color: gray;
}
.content {
flex: 1;
background-color: red;
display: flex;
align-items: center;
justify-content: center;
}
<div class="parent">
<div class="header">
<span>Header</span>
</div>
<div class="content">
<span>Main content</span>
</div>
</div>
Side note:
A table element is special and doesn't behave as normal block or inline elements. To make it work with display: table, you need to set a height to your parent as well as to the table, like in this sample, http://jsfiddle.net/LGSon/0bzewkf4.
Still, as you can see, the table height is 200px because flex has some flaws when it comes to limit height's, so it is not display:table that breaks your flex, it is flex who is somewhat broken.
Here is another answer of mine, showing yet another workaround where flex doesn't behave: Normalizing Flexbox overflow in IE11
It's a big question why you use table in flexbox...
But you can set width to your table and inherit min-height from parent
.parent {
min-height: 200px;
border: 1px solid black;
display: flex;
flex-direction: column;
text-align: center;
}
.header {
background-color: gray;
}
.content {
display: table;
flex:1;
background-color: red;
width:100%;
min-height:inherit;
}
.content > span {
display: table-cell;
vertical-align: middle;
height: 100%;
}
<div class="parent">
<div class="header">
<span>Header</span>
</div>
<div class="content">
<span>Main content</span>
</div>
</div>
You should not need to use a table layout at all here. Just add align-self: center; to .content- > span {.... And make the span element become a flex item as well, by adding display:flex to the .content element. The reason why the table layout is not working for you is because vertcal-align has no effect on the alignment of flex items. So mixing a flex-layout with a table-layout by changing the display property of a flex-item seems not to be a good idea, because you are loosing the flexibility of the flex-layout.
Properties not affecting flexible boxes
Because flexible boxes use a different layout algorithm, some properties do not make sense on a flex container:
column-* properties of the multiple column module have no effect on a flex item.
float and clear have no effect on a flex item. Using float causes the display property of the element to compute to block.
vertical-align has no effect on the alignment of flex items.
.parent {
min-height: 200px;
border: 1px solid black;
display: flex;
flex-direction: column;
text-align: center;
}
.header {
background-color: gray;
}
.content {
flex: 1;
display: flex;
background-color: red;
}
.content > span {
flex: 1;
align-self: center;
}
<div class="parent">
<div class="header">
<span>Header</span>
</div>
<div class="content">
<span>Main content</span>
</div>
</div>
Tables are row or horizontally oriented so wouldn't you get weird results if placed within a flex-column? I changed everything to a good old block, they stack very well in a column flow--vertical harmony.
.content is dead center by using: position: relative; top: 50%; and translateY(360%); for vertical and text-align: center; for horizontal. Oh and of course turning that span into a useful block.
Changed the following:
.content {
flex: 1;
background-color: red;
}
.content > span {
display: block;
position: relative;
top: 50%;
transform: translateY(360%);
text-align: center;
}
I changed display: table to table-row is this what you wanted?
.parent {
min-height: 200px;
border: 1px solid black;
display: flex;
flex-direction: column;
text-align: center;
}
.header {
background-color: gray;
}
.content {
flex: 1;
background-color: red;
}
.content > span {
display: block;
position: relative;
top: 50%;
transform: translateY(360%);
text-align: center;
}
<div class="parent">
<div class="header">
<span>Header</span>
</div>
<div class="content">
<span>Main content</span>
</div>
</div>

Why isn't `height: 100%` and absolute positioning working in flexbox?

I'm trying to make a child div of a flexbox layout fill its parent. In any other context setting the width/height to 100% causes a div to fill its parent... I only wish to use flexbox for my top level layout.
Problems
#map-container div will not fill #col1 even though it has height 100% set.
#controls div appears outside #col1 completely. I've previously used absolute layout to align boxes to corners without problems. Being inside a flexbox grand-parent seems to cause issues.
What I'm expecting is #map-container and #map to fill #col1 and #controls to align to bottom right-hand corner of #map.
.wrapper, html, body {
height:100%;
margin:0;
}
#col1 {
display: flex;
}
#map-container {
background-color: yellow;
width: 100%;
height: 100%;
}
#map {
background-color: purple;
width: 100%;
height: 100%;
}
#controls {
background-color: orange;
position: absolute;
right: 3px;
bottom: 3px;
width: 100px;
height: 20px;
}
.wrapper {
display: flex;
flex-direction: column;
}
#row1 {
background-color: red;
}
#row2 {
flex:2;
display: flex;
}
#col1 {
background-color: green;
flex: 1 1;
}
#col2 {
background-color: blue;
flex :0 0 240px;
}
<div class="wrapper">
<div id="row1">Header</div>
<div id="row2">
<div id="col1">
<div id="map-container">
<div id="map">
Map
</div>
<div id="controls">Controls</div>
</div>
</div>
<div id="col2">Sidebar</div>
</div>
</div>
#map-container div will not fill #col1 even though it has height 100% set.
It won't work that way, because for a percentage unit to work, it needs to have height set on its parent all the way up. This fights against the flex model, where the flex-items are distributed and arranged by the flex-box layout and have no dimensions set. Why use a flex layout when all your elements are 100%? Either do a 100% on all your element all the way up, or do a flex on all containers.
If you stick to flex layout, then you will have to get into nested flex. Otherwise, you will get #map-container to fill-up, but not the #map.
This fiddle http://jsfiddle.net/abhitalks/sztcb0me illustrates that problem.
#controls div appears outside #col1 completely. I've previously used absolute layout to align boxes to corners without problems. Being
inside a flex-box grand-parent seems to cause issues.
The only issue is that you are positioning it absolutely, but in relation to what? You need to position your #map-container relatively for that to work.
Here is how:
Fiddle: http://jsfiddle.net/abhitalks/sztcb0me/1/
Snippet:
* { box-sizing: border-box; padding: 0; margin: 0; }
html, body, .wrapper { height:100%; width: 100%; }
.wrapper { display: flex; flex-direction: column; }
#row1 { flex: 0 1 auto; background-color: red; }
#row2 { flex: 2 0 auto; display: flex; }
#col1 { flex: 1 0 auto; display: flex; background-color: green; }
#col2 { flex: 0 0 240px; background-color: blue; }
#map-container {
flex: 1 0 auto; display: flex;
position: relative; background-color: yellow;
}
#map { flex: 1 0 auto; background-color: purple; }
#controls {
background-color: orange;
position: absolute;
right: 3px; bottom: 3px;
width: 100px; height: 20px;
}
<div class="wrapper">
<div id="row1">Header</div>
<div id="row2">
<div id="col1">
<div id="map-container">
<div id="map">
Map
</div>
<div id="controls">Controls</div>
</div>
</div>
<div id="col2">Sidebar</div>
</div>
</div>
the problem is that it's wrapped in #map-container
.wrapper, html, body {
height:100%;
margin:0;
}
#col1 {
display: flex;
}
#map-container {
background-color: yellow;
width: 100%;
height: 100%;
}
#map {
background-color: purple;
width: 100%;
/* height: 100%; */
display: flex;
flex-wrap: wrap-reverse;
justify-content: space-between;
}
#controls {
background-color: orange;
position: relative;
/*right: 3px;
bottom: 3px;*/
width: 100px;
height: 20px;
}
.wrapper {
display: flex;
flex-direction: column;
}
#row1 {
background-color: red;
}
#row2 {
flex:2;
display: flex;
}
#col1 {
background-color: green;
flex: 1 1;
}
#col2 {
background-color: blue;
flex :0 0 240px;
}
<div class="wrapper">
<div id="row1">Header</div>
<div id="row2">
<div id="col1">
<!-- <div id="map-container"> -->
<div id="map">
Map
<div id="controls">Controls</div> <!-- add it here -->
</div>
<!-- <div id="controls">Controls</div> -->
<!--</div> -->
</div>
<div id="col2">Sidebar</div>
</div>
</div>
adding an absolute position controls in that way is not optimal (in the snippet I commented it out) ; you can place the controlsnested in #map (and use flex properties for correcting placement)

Make flex child element occupy 100% height of parent flex [duplicate]

This question already has answers here:
HTML5 flexible box model height calculation
(2 answers)
Closed 4 years ago.
I have a container flex with content flexes. How do i make content flex occupy full width and height of container flex.
<div id="main">
<div id="main-nav">
</div>
<div class="container">
<div class="content"></div>
<div class="content"></div>
</div>
</div>
#main{
display: flex;
flex-direction: column;
height: 100vh;
width: 100vw;
}
#main-nav{
width: 100%
height: 50px;
}
.container{
display: flex;
flex-direction: row;
flex-wrap: wrap;
flex: 1;
}
.content{
display: flex;
width: 100%;
height: 100%;
}
The above code makes content to occupy 100% width of container but height is based on the text within the content. I tried the solutions mentioned from similar questions but had no luck and it was still the same.
Basically, I want each of the content to occupy the same height as occupied by the container in the viewport height. I also tried jQuery,
var rht = $("#container").height();
$(".content").height(rht);
It changes the height properly but adds a horizontal scroll bar with increase in width.
After several updates to the original question:
* {
box-sizing: borderbox;
margin: 0;
padding: 0;
}
#main {
display: flex;
flex-direction: column;
border: 1px solid red;
min-height: 100vh;
}
#main-nav {
flex: 0 0 50px;
}
.container {
display: flex;
flex-direction: column;
flex: 1;
border: 1px solid green;
}
.content {
flex: 1;
border: 1px solid orange;
}
<div id="main">
<div id="main-nav"></div>
<div class="container">
<div class="content"></div>
<div class="content"></div>
</div>
</div>
JSfiddle Demo
You cannot set width or height of flex's child is bigger (size of flex)/(number of flex's childs) but you can add position: absolute into .content and position: relative into .container then set width and height for .content. First .content is under second .content, you can use propety z-index or display: none to control.
* {
box-sizing: borderbox;
margin: 0;
padding: 0;
}
#main {
display: flex;
flex-direction: column;
background: red;
min-height: 100vh;
}
#main-nav {
flex: 0 0 50px;
}
.container {
position: relative;
display: flex;
flex: 1;
background: green;
}
.content {
position: absolute;
left: 0px;
top: 0px;
height: 100%;
width: 100%;
flex: 1;
background: orange;
}
<div id="main">
<div id="main-nav"></div>
<div class="container">
<div class="content">left</div>
<div class="content">right</div>
</div>
</div>

Resources