Flexbox 2x2 grid - input inside overflows the flex container - css

I want to have a flexbox 2x2 grid that contain a random number of elements (odd or even). I've achieved to create this flexbox without any problems.
When I added my content: input fields with width 100% I noticed that those are bigger then their flex container which seems odd. In the example this is easy to spot on the last red box.
How can I make the input fields be 100% of the flex container?
.flex-grid {
display: flex;
flex-wrap: wrap;
height: 500px;
}
.grid-item {
flex: 1 1 50%;
background: #F90;
border-top: solid 1px #000;
}
.grid-item:nth-child(odd) {
background: #F00;
flex: 0 0 50%;
}
input {
width: 100%;
}
<div class="flex-grid">
<div class="grid-item">
<input type="text" value="email">
</div>
<div class="grid-item">
<input type="text" value="email">
</div>
<div class="grid-item">
<input type="text" value="email">
</div>
</div>
Fiddle: https://jsfiddle.net/x3pyenkL/

From Documentation:
The box-sizing property is used to alter the default CSS box model used to calculate width and height of the elements.
Set box-sizing: border-box for <input> elements.
input {
box-sizing: border-box;
width: 100%;
}
Or better to add for all elements of your page for consistency.
* {
box-sizing: border-box;
}
.flex-grid {
display: flex;
flex-wrap: wrap;
height: 500px;
}
.grid-item {
flex: 1 1 50%;
background: #F90;
border-top: solid 1px #000;
}
.grid-item:nth-child(odd) {
background: #F00;
flex: 0 0 50%;
}
input {
box-sizing: border-box;
width: 100%;
}
<div class="flex-grid">
<div class="grid-item">
<input type="text" value="email">
</div>
<div class="grid-item">
<input type="text" value="email">
</div>
<div class="grid-item">
<input type="text" value="email">
</div>
</div>

Related

How to make adaptive centered div?

What I have now:
display: flex;
align-items: center;
flex-direction: column;
How it looks with error:
What's the target:
I can do it with
margin-left: *X*px, but it is not the way I want to solve it.
May I do it with some flex properties ?
It is important to do it without bootstrap and grid.
This could be a possible solution: Center the box with flexbox and display the errors with position: absolute;. You need to take care of responsive optimization if you want to use it on a wider range of devices.
* {
box-sizing: border-box;
}
.container {
display: flex;
align-items: center;
justify-content: center;
}
.box {
border: 1px solid black;
padding: 10px;
width: 400px;
}
.field {
position: relative;
}
.input {
margin-bottom: 10px;
width: 100%;
}
.error {
position: absolute;
left: 105%;
top: 0;
width: 200px;
}
<div class="container">
<div class="box">
<div class="field">
<input class="input" type="text">
<div class="error">error 1</div>
</div>
<div class="field">
<input class="input" type="text">
<div class="error">error 2</div>
</div>
<button>Send</button>
</div>
</div>

Centering form with flex rows

I have a form where every single row has display: flex. Each row has a label box with a fixed width and a field box which fit to his content. Now it looks like this:
What I want to achive is to shrink every row to the minimum content width and centering the form horizontally. Something like this:
I tried using inline-flex for rows but seems like parent becomes smaller than the total width of children.
Is there a way to achive it keeping flexbox for each row and without using transform: translate to align form horizontally?
Here is the code of the first image:
.form-container {
background-color: black;
padding: 5px;
color: white;
}
.form {
background-color: yellow;
padding: 5px;
}
.form-row {
display: flex;
background-color: silver;
padding: 5px 0;
margin: 5px 0;
}
.form-row-label {
flex: 0 0 200px;
background-color: cornflowerblue;
}
.form-row-field {
flex: 0 1 0;
background-color: orangered;
white-space: nowrap;
}
<div class="form-container">
<div class="form">
<div class="form-row">
<div class="form-row-label">
label 1
</div>
<div class="form-row-field">
field 1 xxxxxxxxxxxxxxxxx
</div>
</div>
<div class="form-row">
<div class="form-row-label">
label 2
</div>
<div class="form-row-field">
field 2 xxxx
</div>
</div>
<div class="form-row">
<div class="form-row-label">
label 3
</div>
<div class="form-row-field">
field 3 xxxxxxxxxx
</div>
</div>
</div>
</div>
And here is the jsfiddle.
Thanks
Here is an idea:
.form-container {
background-color: black;
padding: 5px;
color: white;
text-align:center; /* Center the inline-block*/
}
.form {
background-color: yellow;
padding: 5px;
display:inline-block; /* Use this to fit content */
}
.form-row {
display: flex;
background-color: silver;
padding: 5px 0;
margin: 5px 0;
}
.form-row-label {
width: 200px;
flex-shrink:0; /* Avoid the content to shrink*/
background-color: cornflowerblue;
text-align:left;
}
.form-row-field {
flex-shrink:0;
background-color: orangered;
}
<div class="form-container">
<div class="form">
<div class="form-row">
<div class="form-row-label">
label 1
</div>
<div class="form-row-field">
field 1 xxxxxxxxxxxxxxxxx
</div>
</div>
<div class="form-row">
<div class="form-row-label">
label 2
</div>
<div class="form-row-field">
field 2 xxxx
</div>
</div>
<div class="form-row">
<div class="form-row-label">
label 333
</div>
<div class="form-row-field">
field 3 xxxxxxxxxx
</div>
</div>
</div>
</div>
Here is an idea using display:inline-flex and flex-direction:column in the .form class with text-align: center in the parent class. Also you will need to use width: 200px in label instead of flex-basis:200px
.form-container {
background-color: black;
padding: 5px;
color: white;
text-align: center;
}
.form {
background-color: yellow;
padding: 5px;
display: inline-flex;
flex-direction: column;
justify-content: center;
}
.form-row {
display: flex;
background-color: silver;
padding: 5px 0;
margin: 5px 0;
}
.form-row-label {
width: 200px;
background-color: cornflowerblue;
}
.form-row-field {
flex: 0 1 0;
background-color: orangered;
white-space: nowrap;
}
<div class="form-container">
<div class="form">
<div class="form-row">
<div class="form-row-label">
label 1
</div>
<div class="form-row-field">
field 1 xxxxxxxxxxxxxxxxx
</div>
</div>
<div class="form-row">
<div class="form-row-label">
label 2
</div>
<div class="form-row-field">
field 2 xxxx
</div>
</div>
<div class="form-row">
<div class="form-row-label">
label 3
</div>
<div class="form-row-field">
field 3 xxxxxxxxxx
</div>
</div>
</div>
</div>
If you want to center the yellow box within the black box, you should only add below code to your code:
.form {
background-color: yellow;
padding: 5px;
display: flex;
width: 650px;
max-width: 650px;
flex-direction: column;
margin: 0 auto;
}
.form-row-label {
flex: 0 0 60%;
background-color: cornflowerblue;
}
I think it will help you a little bit.

Flex items are not equal width [duplicate]

It seems that the content inside a flex div affects its calculated size concerning the flex-grow property. Am I doing something wrong?
In the fiddle provided below, you'll see a number pad. All the rows contain 3 numbers except the bottom row. That row should have the '0' be the width of 2 numbers, hence flex-grow: 2 and the ':' (colon) be the size of 1 number, hence flex-grow: 1.
Am I missing something here?
The right side of the '0' should be aligned with the 8, 5, and 2 above it. It's a bit off.
.numbers {
display: flex;
flex-direction: column;
}
.row {
display: flex;
flex-direction: row;
flex-grow: 1;
justify-content: space-between;
}
.button {
display: flex;
flex-grow: 1;
justify-content: center;
align-items: center;
margin: 5px;
border-radius: 5px;
border: 1px solid gray;
background: rgba(255, 255, 255, 0.2);
cursor: pointer;
}
.button#number0 {
flex-grow: 2;
}
.button#colon {
flex-grow: 1;
}
<div class="numbers">
<div class="row">
<div class="button number" id="number1">1</div>
<div class="button number" id="number2">2</div>
<div class="button number" id="number3">3</div>
</div>
<div class="row">
<div class="button number" id="number4">4</div>
<div class="button number" id="number5">5</div>
<div class="button number" id="number6">6</div>
</div>
<div class="row">
<div class="button number" id="number7">7</div>
<div class="button number" id="number8">8</div>
<div class="button number" id="number9">9</div>
</div>
<div class="row">
<div class="button number" id="number0">0</div>
<div class="button" id="colon">:</div>
</div>
</div>
https://jsfiddle.net/0r4hemdu/
Short Analysis
The problem is that rows 1-3 have two horizontal margins and row 4 only has one.
With horizontal margins at 10px each, row 4 has 10px more free space than the other rows. This throws off the alignment of the columns.
Because flex-grow applies only to free space, and is heavily influenced by content and margins, it's not the most secure way to size flex items.
Try flex-basis instead. Add this to your code:
.button { flex-basis: 33.33%; }
#number0 { flex-basis: calc(66.67% + 10px); }
* { box-sizing: border-box; }
.numbers {
display: flex;
flex-direction: column;
}
.row {
display: flex;
flex-direction: row;
flex-grow: 1;
justify-content: space-between;
}
.button {
display: flex;
flex-basis: 33.33%;
justify-content: center;
align-items: center;
margin: 5px;
border-radius: 5px;
border: 1px solid gray;
background: rgba(255, 255, 255, 0.2);
cursor: pointer;
}
#number0 { flex-basis: calc(66.67% + 10px); }
* { box-sizing: border-box; }
<div class="numbers">
<div class="row">
<div class="button number" id="number1">1</div>
<div class="button number" id="number2">2</div>
<div class="button number" id="number3">3</div>
</div>
<div class="row">
<div class="button number" id="number4">4</div>
<div class="button number" id="number5">5</div>
<div class="button number" id="number6">6</div>
</div>
<div class="row">
<div class="button number" id="number7">7</div>
<div class="button number" id="number8">8</div>
<div class="button number" id="number9">9</div>
</div>
<div class="row">
<div class="button number" id="number0">0</div>
<div class="button" id="colon">:</div>
</div>
</div>
Extended Analysis
You wrote:
It seems that the content inside a flex div affects its calculated size concerning the flex-grow property. Am I doing something wrong?
The source of your problem is not the content inside the flex item.
You wrote:
In the fiddle provided below, you'll see a number pad. All the rows contain 3 numbers except the bottom row. That row should have the '0' be the width of 2 numbers, hence flex-grow: 2 and the ':' be the size of 1 number, hence flex-grow: 1. Am I missing something here?
Yes. Your interpretation of the flex-grow property is incorrect. flex-grow is not intended for defining the size of a flex item. Its job is to distribute free space in the flex container among items.
By applying flex-grow: 1 to a group of flex items, you are telling them to distribute free space evenly among themselves. This is why, in your demo, rows 1, 2 and 3 have equally sized flex items.
When you apply flex-grow: 2, you are telling the flex item to consume twice as much free space as items with flex-grow: 1.
But where does the second 10px margin from the rows above factor into the layout of row 4?
The reason the alignment is off on row 4 is that row 4 has one less margin than the other rows, meaning that row 4 has 10px more free space than the other rows.
You'll notice that if you remove the margin rule you get your desired alignment.
.numbers {
display: flex;
flex-direction: column;
}
.row {
display: flex;
flex-direction: row;
flex-grow: 1;
justify-content: space-between;
}
.button {
display: flex;
flex-grow: 1;
justify-content: center;
align-items: center;
/* margin: 5px; */
border-radius: 5px;
border: 1px solid gray;
background: rgba(255, 255, 255, 0.2);
cursor: pointer;
}
.button#number0 {
flex-grow: 2;
}
.button#colon {
flex-grow: 1;
}
<div class="numbers">
<div class="row">
<div class="button number" id="number1">1</div>
<div class="button number" id="number2">2</div>
<div class="button number" id="number3">3</div>
</div>
<div class="row">
<div class="button number" id="number4">4</div>
<div class="button number" id="number5">5</div>
<div class="button number" id="number6">6</div>
</div>
<div class="row">
<div class="button number" id="number7">7</div>
<div class="button number" id="number8">8</div>
<div class="button number" id="number9">9</div>
</div>
<div class="row">
<div class="button number" id="number0">0</div>
<div class="button" id="colon">:</div>
</div>
</div>
So what happens on row four to that second 10px margin?
It gets absorbed by the two flex items.
Here's how flex-grow distributes the extra space on row four:
Flex item left (with content "0") has flex-grow: 2. (.button#number0 in your code.)
Flex item right (with content ":") has flex-grow: 1. (.button#colon in your code.)
The second inter-item margin, which appears only on rows with three flex items, is 10px wide. (The code says 5px around each item, but in
CSS horizontal margins never
collapse.
Moreover, in flexbox, no margins
collapse.)
The sum total of the flex-grow values is three. So let's divide 10px by 3. Now we know that the proportion of 1 is 3.33px.
Hence, flex item left gets 6.66px of the extra space, and flex item right gets 3.33px.
Let's say that flex item left had flex-grow: 3 instead. Then flex item left would get 7.5px, and flex item right would get 2.5px.
The last part of your question says:
The right side of the '0' should be aligned with the 8, 5, and 2 above it. It's a bit off.
Because flex-grow applies only to free space, and is heavily influenced by content and margins, it's not the most secure way to size flex items.
Try flex-basis instead. Add this to your code:
.button { flex-basis: 33.33%; }
#number0 { flex-basis: calc(66.67% + 10px); }
* { box-sizing: border-box; }
.numbers {
display: flex;
flex-direction: column;
}
.row {
display: flex;
flex-direction: row;
flex-grow: 1;
justify-content: space-between;
}
.button {
display: flex;
flex-basis: 33.33%;
justify-content: center;
align-items: center;
margin: 5px;
border-radius: 5px;
border: 1px solid gray;
background: rgba(255, 255, 255, 0.2);
cursor: pointer;
}
#number0 { flex-basis: calc(66.67% + 10px); }
* { box-sizing: border-box; }
<div class="numbers">
<div class="row">
<div class="button number" id="number1">1</div>
<div class="button number" id="number2">2</div>
<div class="button number" id="number3">3</div>
</div>
<div class="row">
<div class="button number" id="number4">4</div>
<div class="button number" id="number5">5</div>
<div class="button number" id="number6">6</div>
</div>
<div class="row">
<div class="button number" id="number7">7</div>
<div class="button number" id="number8">8</div>
<div class="button number" id="number9">9</div>
</div>
<div class="row">
<div class="button number" id="number0">0</div>
<div class="button" id="colon">:</div>
</div>
</div>
jsFiddle demo
References:
flex-grow definition ~ MDN
flex-basis definition ~ MDN
7.2 Components of Flexibility ~ W3C
EXTRA: CSS GRID SOLUTION
With the advent of CSS Grid, the code for this entire layout can be greatly simplified.
.numbers {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(26%, 1fr));
grid-gap: 10px;
}
#number0 {
grid-column: span 2;
}
/* non-essential decorative styles */
.button {
display: flex;
justify-content: center;
align-items: center;
border-radius: 5px;
border: 1px solid gray;
}
<div class="numbers">
<div class="button number" id="number1">1</div>
<div class="button number" id="number2">2</div>
<div class="button number" id="number3">3</div>
<div class="button number" id="number4">4</div>
<div class="button number" id="number5">5</div>
<div class="button number" id="number6">6</div>
<div class="button number" id="number7">7</div>
<div class="button number" id="number8">8</div>
<div class="button number" id="number9">9</div>
<div class="button number" id="number0">0</div>
<div class="button" id="colon">:</div>
</div>
Update 3:
I figured out yet another way to get rid of the misalignment.
This version, together with the 2:nd update, works with the original html untouched, and is using pseudo elements to create the buttons, button hover/click effects included.
flex only version
.row {
width: 60%;
margin: auto;
display: flex;
}
.button {
flex: 0 0 33.3%;
text-align: center;
position: relative;
padding: 10px 5px;
box-sizing: border-box;
pointer-events: none;
}
.button#number0 {
flex: 0 0 66.6%;
}
.button:before,
.button:after {
content: " ";
border-radius: 5px;
border: 1px solid gray;
cursor: pointer;
position: absolute;
left: 5px;
top: 5px;
right: 5px;
bottom: 5px;
pointer-events: auto;
}
.button:before {
background: rgba(255, 255, 255, 0.9);
z-index: -1
}
.button:hover:before {
background: rgba(0, 0, 0, 0.1);
}
.button:hover:after {
border: 2px solid red;
}
.button:active:before {
background: rgba(255, 0, 0, 0.5);
}
<div class="numbers">
<div class="row">
<div class="button number" id="number1">1</div>
<div class="button number" id="number2">2</div>
<div class="button number" id="number3">3</div>
</div>
<div class="row">
<div class="button number" id="number4">4</div>
<div class="button number" id="number5">5</div>
<div class="button number" id="number6">6</div>
</div>
<div class="row">
<div class="button number" id="number7">7</div>
<div class="button number" id="number8">8</div>
<div class="button number" id="number9">9</div>
</div>
<div class="row">
<div class="button number" id="number0">0</div>
<div class="button" id="colon">:</div>
</div>
</div>
flex version with a display: table fallback for browsers that does not support the new flexbox model.
.row {
display: table; /* remove for flex only */
width: 60%;
margin: auto;
display: flex;
}
.button {
display:table-cell; /* remove for flex only */
width: 33.3%; /* remove for flex only */
flex: 0 0 33.3%;
text-align: center;
position: relative;
padding: 10px 5px;
box-sizing: border-box;
pointer-events: none;
}
.button#number0 {
width: 66.6%; /* remove for flex only */
flex: 0 0 66.6%;
}
.button:before,
.button:after {
content: " ";
border-radius: 5px;
border: 1px solid gray;
cursor: pointer;
position: absolute;
left: 5px;
top: 5px;
right: 5px;
bottom: 5px;
pointer-events: auto;
}
.button:before {
background: rgba(255, 255, 255, 0.9);
z-index: -1
}
.button:hover:before {
background: rgba(0, 0, 0, 0.1);
}
.button:hover:after {
border: 2px solid red;
}
.button:active:before {
background: rgba(255, 0, 0, 0.5);
}
<div class="numbers">
<div class="row">
<div class="button number" id="number1">1</div>
<div class="button number" id="number2">2</div>
<div class="button number" id="number3">3</div>
</div>
<div class="row">
<div class="button number" id="number4">4</div>
<div class="button number" id="number5">5</div>
<div class="button number" id="number6">6</div>
</div>
<div class="row">
<div class="button number" id="number7">7</div>
<div class="button number" id="number8">8</div>
<div class="button number" id="number9">9</div>
</div>
<div class="row">
<div class="button number" id="number0">0</div>
<div class="button" id="colon">:</div>
</div>
</div>
Update 2:
In addition to Michael_B's answer, which by the way has a very good explanation, is here an updated version, that actually does give the desired alignment without the, in this case, 1-2 px off.
Here is a fiddle sample, and an image, of both mine and Michael_B versions, where the border has been increased a little to make it easier to see the misalignment.
It all comes down to how flexbox calculates sizes when border/padding is present, which you can read more about in this post, where box-sizing: border-box needs to be set along with a few more adjustments, which is commented in the code.
Here is my fiddle and snippet
.row {
display: flex;
width: calc(100% - 30px); /* 30px = the sum of the buttons margin: 5px
to avoid horizontal scroll */
}
.button {
display: flex;
flex-basis: 33.33%;
flex-shrink: 0; /* we need flex-grow/shrink to be 1/0 to make
it calculate the size properly */
box-sizing: border-box; /* to take out the borders when calculate the
flex shrink/grow factor */
justify-content: center;
align-items: center;
margin: 5px;
border-radius: 5px;
border: 1px solid gray;
background: rgba(0, 0, 0, 0.1);
cursor: pointer;
}
#number0 {
flex-basis: calc(66.66% + 10px);
}
<div class="numbers">
<div class="row">
<div class="button number" id="number1">1</div>
<div class="button number" id="number2">2</div>
<div class="button number" id="number3">3</div>
</div>
<div class="row">
<div class="button number" id="number4">4</div>
<div class="button number" id="number5">5</div>
<div class="button number" id="number6">6</div>
</div>
<div class="row">
<div class="button number" id="number7">7</div>
<div class="button number" id="number8">8</div>
<div class="button number" id="number9">9</div>
</div>
<div class="row">
<div class="button number" id="number0">0</div>
<div class="button" id="colon">:</div>
</div>
</div>
Update:
flex only version, with a minor change of the existing html structure, using pseudo elements.
.row {
display: flex;
}
.button {
flex: 0 0 33.3%;
}
.button:after {
content: attr(data-nr);
display: block;
border-radius: 5px;
border: 1px solid gray;
background: rgba(255, 255, 255, 0.9);
text-align: center;
padding: 3px;
margin: 5px;
cursor: pointer;
}
.button#number0 {
flex: 0 0 66.6%;
}
<div class="numbers">
<div class="row">
<div class="button number" id="number1" data-nr="1"></div>
<div class="button number" id="number2" data-nr="2"></div>
<div class="button number" id="number3" data-nr="3"></div>
</div>
<div class="row">
<div class="button number" id="number4" data-nr="4"></div>
<div class="button number" id="number5" data-nr="5"></div>
<div class="button number" id="number6" data-nr="6"></div>
</div>
<div class="row">
<div class="button number" id="number7" data-nr="7"></div>
<div class="button number" id="number8" data-nr="8"></div>
<div class="button number" id="number9" data-nr="9"></div>
</div>
<div class="row">
<div class="button number" id="number0" data-nr="0"></div>
<div class="button" id="colon" data-nr=":"></div>
</div>
</div>
flex version, with a minor change of the existing html structure, using pseudo elements, and has a display: table fallback for browsers that does not support the new flexbox model (like IE8/9).
.row {
display: table;
width: 100%;
}
.button {
display: table-cell;
width: 33.3%;
padding: 5px;
}
.button:after {
content: attr(data-nr);
display: block;
border-radius: 5px;
border: 1px solid gray;
background: rgba(255, 255, 255, 0.9);
text-align: center;
padding: 3px;
cursor: pointer;
}
.button#number0 {
width: 66.6%;
}
#supports (display: flex) {
.row {
display: flex;
}
.button {
display: block;
width: auto;
flex: 0 0 33.3%;
padding: 0;
}
.button#number0 {
flex: 0 0 66.6%;
}
.button:after {
margin: 5px;
}
}
<div class="numbers">
<div class="row">
<div class="button number" id="number1" data-nr="1"></div>
<div class="button number" id="number2" data-nr="2"></div>
<div class="button number" id="number3" data-nr="3"></div>
</div>
<div class="row">
<div class="button number" id="number4" data-nr="4"></div>
<div class="button number" id="number5" data-nr="5"></div>
<div class="button number" id="number6" data-nr="6"></div>
</div>
<div class="row">
<div class="button number" id="number7" data-nr="7"></div>
<div class="button number" id="number8" data-nr="8"></div>
<div class="button number" id="number9" data-nr="9"></div>
</div>
<div class="row">
<div class="button number" id="number0" data-nr="0"></div>
<div class="button" id="colon" data-nr=":"></div>
</div>
</div>
I think everything that Michael_B said is correct. Only the solutions is a bit awkward. I personsally don't like calc. It just doesn't feel right.
The problem you have is a more general one. You put too many responsibilities onto one element. In this case it the .button class. Flex and Margin with flex-grow is too much responsibility. Try to break that apart. It means more DOM elements, but it saves you a lot of pain.
.numbers {
display: flex;
flex-direction: column;
max-width: 200px;
margin: 0 auto;
}
.row {
display: flex;
flex-direction: row;
flex-grow: 1;
justify-content: space-between;
}
.row > .box {
display: flex;
flex-basis: 33.3333%;
justify-content: center;
align-items: center;
}
.row > .box.box-2 {
flex-basis: 66.6667%;
}
.button {
border-radius: 5px;
border: 1px solid gray;
background: rgba(255, 255, 255, 0.2);
cursor: pointer;
width: auto;
text-align: center;
margin: 5px;
width: 100%;
}
<div class="numbers">
<div class="row">
<div class="box"><div class="button number" id="number1">1</div></div>
<div class="box"><div class="button number" id="number2">2</div></div>
<div class="box"><div class="button number" id="number3">3</div></div>
</div>
<div class="row">
<div class="box"><div class="button number" id="number4">4</div></div>
<div class="box"><div class="button number" id="number5">5</div></div>
<div class="box"><div class="button number" id="number6">6</div></div>
</div>
<div class="row">
<div class="box"><div class="button number" id="number7">7</div></div>
<div class="box"><div class="button number" id="number8">8</div></div>
<div class="box"><div class="button number" id="number9">9</div></div>
</div>
<div class="row">
<div class="box box-2"><div class="button number" id="number0">0</div></div>
<div class="box"><div class="button" id="colon">:</div></div>
</div>
</div>
flexbox doesn't respond well to margins, in my opinion.
The better approach / workaround I prefer is to make sure all flex children have 0 margins, set the flex container to justify-content: space-between;, and then give the children a total width less than 100%. The remainder will be your margin.
In other words, if you want two elements per row, set each to 49% wide and you'll have 2% space between them. Three elements, each at 32% wide and you'll have 2% between them. In the calculator example, the 0 cell should be 66% wide and the rest 32%.
Edit: Note that because reasons (namely that content-box is terrible), if any of your children have borders you'll need to use box-sizing: border-box for my suggestion to work properly.
https://jsfiddle.net/r3L1mtbe/2/
It is important to use the shorthand to accommodate cross browser support:
.row {
display: flex;
flex-direction: row; /* <-- this is the default so unnecessary to state */
flex-grow: 1;
justify-content: space-between;
}
.button {
display: flex;
/* flex-grow: 1; replace with shorthand */
flex:1 0 100%; /* probably making the "width: 100%;" unnecessary */
justify-content: center;
}
.button#number0 {
/* flex-grow: 2; replace with shorthand */
flex:2 0 100%;
}
.button#colon {
/* flex-grow: 1; replace with shorthand */
flex:1 0 100%;
}

Column flexbox fitting within another column flexbox

I'm trying to get a UI that looks somewhat like this:
In the image pretend the top bar with "New York..." and the "Book it" button are fixed and the stuff between is scrollable.
The HTML I have so far is this (note that the .button and .form are just divs to try to keep the example as simple as possible)
<div class="wrapper">
<div class="sidebar"> <!-- Hidden from UI unless you swipe left to right --> </div>
<div class="inner-wrapper">
<div class="header">Title here</div>
<div class="balance-bar">$0</div>
<div class="app-content">
<div class="body-content">
<div class="form">
<input type="text"><br><br>
<input type="text"><br><br>
<input type="text"><br><br>
<input type="text"><br><br>
<input type="text"><br><br>
<input type="text"><br><br>
<input type="text"><br><br>
<input type="text"><br><br>
<input type="text"><br><br>
</div>
<div class="button">Submit</div>
</div>
</div>
</div>
</div>
The CSS is:
.button, input {
width:100%;
box-sizing: border-box;
}
.wrapper {
border: 2px solid blue;
height:200px;
overflow: auto;
}
.header {
background: lightblue;
flex-shrink: 0;
}
.balance-bar {
background: lightgreen;
flex-shrink: 0;
}
.inner-wrapper {
border: 2px solid red;
display: flex;
flex-direction: column;
}
.app-content {
border: 2px solid green;
overflow:auto;
}
.body-content {
border: 2px solid orange;
display: flex;
flex-direction:column;
}
.form {
}
.button {
background: pink;
flex-shrink: 0;
}
If I move the button outside the form and as a child of the first flexbox (so .button would be a sibling of .app-content) this all works great and you don't even need a flexbox within a flexbox. One flexbox works perfect. The issue tho is that the semantics are all wrong, you don't get built in browser features like enter to submit, and the flow for the JS to get it to work is super janky.
I was hoping with flexbox I can set the wrapper to the height of the window and flexbox would just calculate all children to fit within the window (which it does, but not for children set to flex)
http://jsbin.com/gumozexihi/1/edit?html,css,output
I hope this helps. I kept the button inside the form and gave it a position: fixed and a bottom: 0.
HTML:
<div class="wrapper">
<div class="inner-wrapper">
<div class="header">Header</div>
<div class="balance-bar">$0</div>
<div class="app-content">
<div class="body-content">
<div class="form">
<input type="text" />
<input type="text" />
<input type="text" />
<input type="text" />
<input type="text" />
<input type="text" />
<input type="text" />
<input type="text" />
<div class="button">Submit</div>
</div>
</div>
</div>
</div>
</div>
And the CSS:
html, body {
height: 100%;
margin: 0;
}
.wrapper {
height: 100%;
}
.inner-wrapper {
height: 100%;
display: flex;
flex-direction: column;
}
.app-content {
flex: 1;
overflow: auto;
}
.body-content {
height: 1000px;
display: flex;
flex-direction: column;
}
.button {
position: fixed;
bottom: 0;
width: 100%;
}
I added height: 1000px to .body-content to mimic having more content than the available screen height. And I fixed the button to the bottom using position: fixed and bottom: 0, which may not be ideal solutions but it seems to work while keeping the button inside the form element.
Update
Just saw you specifically didn't want to use a fixed position on the button. If I can find another solution I'll edit this response, but for a single button this should do the trick.

CSS: Getting 2 children DIVs on same line

Am using Ninja Forms on a WP website. There are 2 different fields (textbox & submit button) that are separate DIVs, both children of single DIV.
They appear on consecutive lines and I cannot seem to get the on same line. Help?
Can see current code of the DIVs on the site: http://theroadmap.co/generation/
<div id="ninja_forms_form_2_all_fields_wrap" class="ninja-forms-all-fields-wrap">
<div class="field-wrap text-wrap label-above ninjacomment-wrap" id="ninja_forms_field_9_div_wrap" data-visible="1">
<input type="hidden" id="ninja_forms_field_9_type" value="text">
<label for="ninja_forms_field_9" id="ninja_forms_field_9_label" class=""> </label>
<input id="ninja_forms_field_9" data-mask="" name="ninja_forms_field_9" type="text" class="ninja-forms-field ninjacomment " value="" rel="9">
<div id="ninja_forms_field_9_error" style="display:none;" class="ninja-forms-field-error">
</div>
</div>
<div class="field-wrap submit-wrap label-left ninjasubmit-wrap" id="ninja_forms_field_10_div_wrap" data-visible="1">
<input type="hidden" id="ninja_forms_field_10_type" value="submit">
<input type="submit" name="_ninja_forms_field_10" class="ninja-forms-field ninjasubmit" id="ninja_forms_field_10" value="Suggest a link!" rel="10">
<div id="ninja_forms_field_10_error" style="display:none;" class="ninja-forms-field-error">
</div>
</div>
</div>
Modifications I've added so far:
/* Ninja Form mods */
.ninjacomment {
background: #ffbf00 !important;
border: 3px;
color: black !important;
width: 50%;
}
#ninja_forms_field_9 {
margin-left: 0;
width: 30%;
float: left;
position: inline-block;
}
#ninja_forms_field_10 {
margin-left: 0;
float: right;
position: inline-block;
}
.ninja-forms-all-fields-wrap {
overflow: hidden;
}
Thanks!
You can get elements on the same line several ways.
Sample markup:
<div class="parent">
<div class="child"></div>
<div class="child"></div>
</div>
inline-block
.child {
display: inline-block;
width: 40%; /* adjust */
}
Floats
.child {
float: left; /* or right */
width: 40%; /*adjust */
}
display: table
.parent {
display: table;
width: 100%;
}
.child {
display: table-cell;
width: 40%; /* adjust */
}
white-space: nowrap
.parent {
white-space: nowrap /* children will stay on the same line no matter how wide */
}
<div id="wrapper">
<div id="left">
<input id="ninja_forms_field_9" data-mask="" name="ninja_forms_field_9" type="text" class="ninja-forms-field ninjacomment " value="" rel="9"></input>
</div>
<div id="right">
<input type="submit" name="_ninja_forms_field_10" class="ninja-forms-field ninjasubmit" id="ninja_forms_field_10" value="Suggest a link!" rel="10"></input>
</div>
CSS
#wrapper {
width:300px;
}
#left {
float:left;
width:146px;
}
#right {
float:right;
width:148px;
}
Working Fiddle

Resources