Centering form with flex rows - css

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.

Related

Account for gap when calculating flex-basis

I'm trying to use gap to specify gaps between flexed items within my grid system, but running in to a major drawback. It seems that when you're using flex-grow: 0;/flex-shrink: 0; in conjunction with gap and flex-basis values that fill the entire available width (i.e. three columns with flex: 0 0 33.3333%;), the columns overflow their parent container as the gap doesn't account for the fixed width as specified with flex: 0 0 33.3333%.
Similar to box-sizing: border-box;, is there some way to instruct the rendering engine that the gap should be subtracted when determining the width of these columns?
Demonstration:
.row {
display: flex;
gap: 30px;
border: 2px solid red;
}
.col {
flex: 0 0 33.3333%;
background: teal;
border: 2px solid #004D4D;
color: white;
font-weight: 700;
padding: 50px;
text-align: center;
}
:root {
font-family: sans-serif;
}
* {
box-sizing: border-box;
}
<h2>With gap:</h2>
<div class="row">
<div class="col">
1
</div>
<div class="col">
2
</div>
<div class="col">
3
</div>
</div>
<h2>Without gap:</h2>
<div class="row" style="gap:0;">
<div class="col">
1
</div>
<div class="col">
2
</div>
<div class="col">
3
</div>
</div>
Note: I could account for this with a formula like flex-basis: calc($width - ($gap / ($number-of-columns / 2));, but as this is for a reusable grid system, I can't practically account for every possible scenario.
Here is another not very elegant quick way to hack your way forward. Similar to the answer by UPinar it alters the outer flex container. Here with negative margin on the right (this might cause other layout problems!). This "solution" is using shrink 0. Also it works with a wrapping flex.
I agree that this should not be so complicated and hacky. Maybe we are missing something? I am also under the impression that this is not the really the desired box-sizing border-box behavior which I hoped to find in combination with the gap property.
flex and gap should be hack free like: Draw three containers each consuming a third of the width and have some space between em. AFAIK gap works that way with CSS grid and CSS columns.
.flex {
display: flex;
flex-grow: 0;
flex-shrink: 0;
flex-wrap: wrap;
}
.flex.gap {
gap: var(--space-s);
margin-right: calc(-1 * var(--space-s));
}
.col {
flex-basis: 33.3333%;
background: teal;
border: 2px solid #004D4D;
color: white;
font-weight: 700;
padding: 50px;
text-align: center;
}
.flex.gap .col {
flex-basis: calc(33.3333% - var(--space-s));
background: teal;
border: 2px solid #004D4D;
color: white;
font-weight: 700;
padding: 50px;
text-align: center;
}
:root {
font-family: sans-serif;
--space-s: 1rem;
}
* {
box-sizing: border-box;
}
<h2>With gap</h2>
<div class="flex gap">
<div class="col">
1
</div>
<div class="col">
2
</div>
<div class="col">
3
</div>
<div class="col">
4
</div>
<div class="col">
5
</div>
<div class="col">
6
</div>
</div>
<h2>Without gap</h2>
<div class="flex">
<div class="col">
1
</div>
<div class="col">
2
</div>
<div class="col">
3
</div>
<div class="col">
4
</div>
<div class="col">
5
</div>
<div class="col">
6
</div>
</div>
The formula you mentioned works... you can use CSS variables to make a reuseable grid system. A buddy and I came up with this:
.flex{
--columns:3;
--gap:30px;
--gap-count:calc( var(--columns) - 1 );
display:flex;
gap:var(--gap);
}
.flex-child {
flex-basis: calc( calc( 100% / var(--columns) ) - calc( var(--gap) / var(--columns) * var(--gap-count) ) );
}
#media (max-width: 992px) {
.flex{
--columns:2;
}
}
#media (max-width: 767px) {
.flex{
--columns:1;
}
}
So then all you need to change are the variables --columns and --gap
https://codepen.io/pyledigital/pen/mdWmjQb
When you add a padding-right: calc(var(--gap-space) * 2); to parent container. Parent container width will calculte before child containers use 100% which is parent container width. You need to change parent containers width before using its width inside child container.
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
min-height: 100vh;
text-rendering: optimizeSpeed;
line-height: 1.5;
margin: 0;
background-color: bisque;
display: grid;
place-content: center;
}
:root{
--gap-space:30px;
font-family: sans-serif;
}
.row-1 {
display: flex;
gap: var(--gap-space);
border: 2px solid red;
padding-right: calc(var(--gap-space) * 2);
}
.row-1 .col{
background: teal;
border: 2px solid #004D4D;
color: white;
font-weight: 700;
padding: 50px;
text-align: center;
flex: 0 0 calc(100% / 3);
}
.row-2{
display: flex;
flex-direction: row;
border: 2px solid red;
}
.row-2 .col{
background: teal;
border: 2px solid #004D4D;
color: white;
font-weight: 700;
padding: 50px;
text-align: center;
flex: 0 0 calc(100% / 3);
}
<h2>With gap:</h2>
<div class="row-1">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
<h2>Without gap:</h2>
<div class="row-2" style="gap: 0">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
What's wrong with using only width?
.col {
width: 33.3333%;
...
}
.row {
display: flex;
gap: 30px;
border: 2px solid red;
}
.col {
width: 33.3333%;
background: teal;
border: 2px solid #004D4D;
color: white;
font-weight: 700;
padding: 50px;
text-align: center;
}
:root {
font-family: sans-serif;
}
* {
box-sizing: border-box;
}
<h2>With gap:</h2>
<div class="row">
<div class="col">
1
</div>
<div class="col">
2
</div>
<div class="col">
3
</div>
</div>
<h2>Without gap:</h2>
<div class="row" style="gap:0;">
<div class="col">
1
</div>
<div class="col">
2
</div>
<div class="col">
3
</div>
</div>

Complex grid with bootstrap

I would like to make a design like this in CSS, but without the blank below blue div and with a margin between each.
I tried different things and impossible to do that, my divs always go to a new line...
Thank you very much !
Here is my code (simplified)
.row > div { border: 1px solid black;}
.A {height:420px;}
.D {height:200px;}
.E {height:200px;}
.B {height:300px;}
.C {height:300px;}
<div class="container">
<div class="row">
<div class="col-md-8 col-lg-6 A">
<div>
A
</div>
</div>
<div class="col-md-12 col-lg-6 B">
<div>
B
</div>
</div>
<div class="col-md-12 col-lg-6 C">
<div>
C
</div>
</div>
<div class="col-md-4 col-lg-3 D">
<div>
D
</div>
</div>
<div class="col-md-4 col-lg-3 E">
<div>
E
</div>
</div>
</div>
</div>
With Flexbox there, no need to use bootstrap or grid!
.topmost-wrapper {
height: 100vh;
width: 65%;
margin: 0 auto;
display: flex;
flex-direction: row;
}
.sub-wrap-1 {
display: flex;
flex-direction: column;
flex: 0.5 1 0;
height: 100%;
margin-right: 0.125rem;
}
.inner-1 {
flex: 0.7 1 0;
background: lightblue;
margin-bottom: 0.0925rem;
border-radius: 0.1825rem;
}
.inner-2 {
flex: 0.3 1 0;
display: flex;
flex-direction: row;
margin-top: 0.0925rem;
}
.in-inner-1 {
flex: 0.7 1 0;
background: lightgreen;
margin-right: 0.0825rem;
border-radius: 0.1825rem;
}
.in-inner-2 {
flex: 0.3 1 0;
background: lightsalmon;
margin-left: 0.0825rem;
border-radius: 0.1825rem;
}
.sub-wrap-2 {
display: flex;
flex-direction: column;
flex: 0.5 1 0;
height: 100%;
margin-left: 0.125rem;
}
.inner-3 {
flex: 0.5 1 0;
background: grey;
margin-bottom: 0.0925rem;
border-radius: 0.25rem;
}
.inner-4 {
flex: 0.5 1 0;
background: #3e3e3e;
margin-top: 0.0925rem;
border-radius: 0.25rem;
}
<div class='topmost-wrapper'>
<div class="sub-wrap-1">
<div class="inner-1"></div>
<div class="inner-2">
<div class="in-inner-1"></div>
<div class="in-inner-2"></div>
</div>
</div>
<div class='sub-wrap-2'>
<div class="inner-3"></div>
<div class="inner-4"></div>
</div>
</div>

Why is <ul> getting out of the box when padding is set to zero?

This containers are arranged using nested flexbox. When I added an unordered list with zero padding, it got outside the child container. Not only that it also goes outside the parent container.
:root {
--main-bg-color: #3D3E5D;
--bg-color-red: #F06D4F;
--bg-color-aqua: #2DA6A4;
--bg-color-orange: #EFB85E;
--txt-color-primary: black;
--txt-color-secondary: white;
--heading: 3rem;
--sub-heading: 2rem;
--normal: 1rem;
--small: 0.5rem;
--main-padding: 10px;
}
* {
margin: none;
padding: 0;
box-sizing: border-box;
}
.container__main {
width: 90%;
margin: auto;
}
.container__flex {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.flex__box {
font-weight: 900;
font-size: var(--normal);
background-color: aqua;
flex: 0 0 calc(50% - 10px);
}
.red {
background-color: red;
}
.gray {
background-color: gray;
}
.container__main>.container__flex {
margin-bottom: 10px;
}
.container__flex>.flex__box {
padding: var(--main-padding);
}
.p-0 {
padding: 0 !important;
}
<div class="container__main">
<div class="container__flex">
<div class="flex__box">
<b></b>
<span class="heading">W</span>eb <span class="heading">A</span>pplication <span class="heading">T</span>echnologies
</div>
<div class="flex__box gray">
<div class="container__flex">
<div class="flex__box p-0 red">
<span class="sub-heading">Links</span>
<ul>
<li>Chubkins</li>
<li>W3 Schools</li>
<li>Learn Web Dev</li>
<li>Colour Reference</li>
</ul>
</div>
<div class="flex__box p-0 red">
</div>
</div>
</div>
</div>
<div class="container__flex">
<div class='flex__box'>
box1
</div>
<div class='flex__box'>
box2
</div>
</div>
</div>
Picture of the mentioned problem: https://prnt.sc/plgv0y
If you want to help me debug this view this codepen link:
https://codepen.io/bishant-bhattarai/pen/qBBqqYE
Since this was a small project I didn't add any comments, sorry for inconvineince.
This is probably due to the default value of the CSS property list-style-position.
You can try and change that like this:
:root {
--main-bg-color: #3D3E5D;
--bg-color-red: #F06D4F;
--bg-color-aqua: #2DA6A4;
--bg-color-orange: #EFB85E;
--txt-color-primary: black;
--txt-color-secondary: white;
--heading: 3rem;
--sub-heading: 2rem;
--normal: 1rem;
--small: 0.5rem;
--main-padding: 10px;
}
* {
margin: none;
padding: 0;
box-sizing: border-box;
}
.container__main {
width: 90%;
margin: auto;
}
.container__flex {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.flex__box {
font-weight: 900;
font-size: var(--normal);
background-color: aqua;
flex: 0 0 calc(50% - 10px);
}
.red {
background-color: red;
}
.gray {
background-color: gray;
}
.container__main>.container__flex {
margin-bottom: 10px;
}
.container__flex>.flex__box {
padding: var(--main-padding);
}
.p-0 {
padding: 0 !important;
}
ul {
list-style-position: inside;
}
<div class="container__main">
<div class="container__flex">
<div class="flex__box">
<b></b>
<span class="heading">W</span>eb <span class="heading">A</span>pplication <span class="heading">T</span>echnologies
</div>
<div class="flex__box gray">
<div class="container__flex">
<div class="flex__box p-0 red">
<span class="sub-heading">Links</span>
<ul>
<li>Chubkins</li>
<li>W3 Schools</li>
<li>Learn Web Dev</li>
<li>Colour Reference</li>
</ul>
</div>
<div class="flex__box p-0 red">
</div>
</div>
</div>
</div>
<div class="container__flex">
<div class='flex__box'>
box1
</div>
<div class='flex__box'>
box2
</div>
</div>
</div>
cf. https://developer.mozilla.org/en-US/docs/Web/CSS/list-style-position

Resize the header and content div dimensions respond when the window size changes but maintain right sidebar dimensions

I am trying to use a flexbox approach to create a layout that will resize the header width and content dimensions when a window is resized, but maintain the sidebar dimensions.
I found the following example from this Flexbox Approach to get me started, and it works as desired for the content div itself. But after looking it over, I'm unsure how to make it work as described with a fixed width, 100% height sidebar.
CSS from example:
<style>
html, body {
height: 100%;
margin: 0
}
.box {
display: flex;
flex-flow: column;
height: 100%;
}
.box .row {
border: 1px dotted grey;
}
.box .row.header {
flex: 0 1 auto; /* The above is shorthand for: flex-grow: 0, flex-shrink: 1, flex-basis: auto */ }
.box .row.content {
flex: 1 1 auto;
}
.box .row.footer {
flex: 0 1 40px;
}
</style>
HTML from example:
<div class="row header">
<p><b>header</b> <br /> <br />(sized to content)</p>
</div> <div class="row content">
<p> <b>content</b> (fills remaining space) </p>
</div>
<div class="row footer">
<p><b>footer</b> (fixed height)</p>
</div>
</div>
The following codepen example gave me the information I needed to get my layout working:
http://codepen.io/JosephSilber/pen/HqgAz
CSS:
.header {
height: 50px;
}
.body {
position: absolute;
top: 50px;
right: 0;
bottom: 0;
left: 0;
display: flex;
}
.sidebar {
width: 140px;
}
.main {
flex: 1;
display: flex;
flex-direction: column;
}
.content {
flex: 1;
display: flex;
overflow: auto;
}
.box {
min-height: -webkit-min-content;
display: flex;
}
.column {
padding: 20px;
border-right: 1px solid #999;
}
.column > div {
height: 2000px;
background: red;
}
.column:nth-child(2) > div {
height: auto;
}
/* All of these are just for this demo's design. */
body {
font-family: sans-serif;
font-size: 20px;
line-height: 50px;
text-transform: uppercase;
font-weight: bold;
}
.header {
text-align: center;
color: #fff;
background: #444;
}
.sidebar {
background: #666;
padding: 4px 20px;
color: #fff;
}
.page-header {
padding: 6px 20px;
background: #004141;
color: #fff;
font-size: .8em;
}
.content {
background: #ddd;
}
HTML:
<div class="header">Main header</div>
<div class="body">
Move this: <div class="sidebar">Sidebar</div>
<div class="main">
<div class="page-header">Page Header. Content columns are below.</div>
<div class="content">
<div class="box">
<div class="column">
<div>Column 1</div>
</div>
<div class="column">
<div>Column 1</div>
</div>
<div class="column">
<div>Column 1</div>
</div>
</div>
</div>
</div>
To here: <div class="sidebar">Sidebar</div>
</div>
To get the sidebar on the right side, I simply moved <div class="sidebar">Sidebar</div>to just above the closing div tag for the .body class.

Display Table-Cell: Remove Right and Left Border Space?

I'd like to display four elements side by side. I'm using display: table and display: table-cell to accomplish this:
#container {
width: 960px;
background-color: orange;
height: 400px;
}
#table {
display: table;
table-layout: fixed;
border-spacing: 10px;
width: 100%;
}
div.item {
display: table-cell;
height: 150px;
background-color: blue;
}
<div id="container">
<div id="table">
<div class="item">
Text 1
</div>
<div class="item">
Text 2
</div>
<div class="item">
Text 3
</div>
<div class="item">
Text 4
</div>
</div>
</div>
How can I make the rightmost and leftmost cells flush with the container div's edge and maintain equal spacing between the inner cells?
Thank you!
An easy way would be to use border on cells instead of border-spacing. Then you could cancel out border on the first of last cell. Also, keep the colour same as that of your container.
div.item {
display: table-cell;
border: 10px solid orange; /* Same colour as of the container */
border-left: none; /* reset left border to keep uniform */
}
div.item:last-child { border-right: none; } /* remove from last one */
Example Snippet:
#container {
width: 960px;
background-color: orange;
height: 400px;
}
#table {
display: table;
table-layout: fixed;
width: 100%;
}
div.item {
display: table-cell;
height: 150px;
background-color: blue;
border: 10px solid orange;
border-left: none;
}
div.item:last-child { border-right: none; }
<div id="container">
<div id="table">
<div class="item">
Text 1
</div>
<div class="item">
Text 2
</div>
<div class="item">
Text 3
</div>
<div class="item">
Text 4
</div>
</div>
</div>
You can remove the table div and make container display: flex with space-between justification.
<div id="container">
<div class="item">
Text 1
</div>
<div class="item">
Text 2
</div>
<div class="item">
Text 3
</div>
<div class="item">
Text 4
</div>
</div>
#container {
display: flex;
justify-content: space-between;
}
.item {
background-color: red;
width: 24%;
}
https://jsfiddle.net/kyy7qgLz/2/

Resources