This question already has an answer here:
Why does minmax(0, 1fr) work for long elements while 1fr doesn't?
(1 answer)
Closed 7 months ago.
The form has a fixed width of 300px with a grid layout. I have made it two columns by
grid-template-columns: repeat(2, 1fr) , and I have also tried grid-template-columns: auto auto , but the elements are still going outside of the form.
How to make the elements auto-adjust their width to suit the form width?
form {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 30px;
background-color: green;
width: 300px;
}
textarea {
grid-column: span 2 / span 2;
}
<form>
<input placeholder="First Name" type="text" name="first_name" required>
<input placeholder="Last Name" type="text" name="last_name" required>
<textarea placeholder="Message" name="message" rows="5"></textarea>
<input type="submit" value="Submit">
</form>
1fr means minmax(auto, 1fr) which is a well-known concern here. In your context, auto is not obvious, and that causes unexpected widths for your input fields.
To fix it, you should set grid-template-columns: repeat(2, minmax(0, 1fr)); instead.
form {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 30px;
background-color: green;
width: 300px;
}
textarea {
grid-column: span 2 / span 2;
}
<form>
<input placeholder="First Name" type="text" name="first_name" required>
<input placeholder="Last Name" type="text" name="last_name" required>
<textarea placeholder="Message" name="message" rows="5"></textarea>
<input type="submit" value="Submit">
</form>
You will need to set the overflow of any child elements to a value other than the default of visible.
form input {
overflow: hidden; // New
}
form {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-auto-rows: minmax(min-content, max-content);
gap: 30px;
background-color: green;
width: 300px;
}
textarea {
grid-column: span 2 / span 2;
}
<form>
<input placeholder="First Name" type="text" name="first_name" required>
<input placeholder="Last Name" type="text" name="last_name" required>
<textarea placeholder="Message" name="message" rows="5"></textarea>
<input type="submit" value="Submit">
</form>
Related
How can I add spacing between input elements that has flex-direction: row. I'm using components from the angular-material library. Below screenshot with a highlighted inputs that must have spacing between them
HTML
<form class="form-container">
<mat-form-field class="full-width">
<mat-label>First name *</mat-label>
<input type="text" name="firstName" matInput placeholder="First name" value="">
</mat-form-field>
<mat-form-field class="full-width">
<mat-label>Last name *</mat-label>
<input type="text" name="lastName" matInput placeholder="Last name" value="">
</mat-form-field>
<div class="date-of-birth">
<mat-form-field>
<mat-label>Day</mat-label>
<input type="number" name="day" matInput placeholder="Day" value="">
</mat-form-field>
<mat-form-field>
<mat-label>Month</mat-label>
<input type="number" name="month" matInput placeholder="Month" value="">
</mat-form-field>
<mat-form-field>
<mat-label>Year</mat-label>
<input type="number" name="year" matInput placeholder="Year" value="">
</mat-form-field>
</div>
</form>
CSS
.form-container {
min-width: 150px;
max-width: 500px;
width: 100%;
margin: 0 auto;
}
.full-width {
width: 100%;
}
.date-of-birth {
display: flex;
flex-direction: row;
}
Adding gap in .date-of-birth will solve your issue:
<form class="form-container">
<mat-form-field class="full-width">
<mat-label>First name *</mat-label>
<input type="text" name="firstName" matInput placeholder="First name" value="">
</mat-form-field>
<mat-form-field class="full-width">
<mat-label>Last name *</mat-label>
<input type="text" name="lastName" matInput placeholder="Last name" value="">
</mat-form-field>
<div class="date-of-birth">
<mat-form-field>
<mat-label>Day</mat-label>
<input type="number" name="day" matInput placeholder="Day" value="">
</mat-form-field>
<mat-form-field>
<mat-label>Month</mat-label>
<input type="number" name="month" matInput placeholder="Month" value="">
</mat-form-field>
<mat-form-field>
<mat-label>Year</mat-label>
<input type="number" name="year" matInput placeholder="Year" value="">
</mat-form-field>
</div>
</form>
CSS
.form-container {
min-width: 150px;
max-width: 500px;
width: 100%;
margin: 0 auto;
}
.full-width {
width: 100%;
}
.date-of-birth {
display: flex;
flex-direction: row;
gap: 20px;
}
You can use column-gap:
.date-of-birth {
column-gap: 5px;
display: flex;
flex-direction: row;
}
Initially a part of Multi-column Layout, the definition of column-gap has been broadened to include multiple layout methods. Now specified in Box Alignment, it may be used in Multi-column, Flexible Box, and Grid layouts.
https://developer.mozilla.org/en-US/docs/Web/CSS/column-gap
There is already wide support for this, with Safari (both MacOS and iOS) being the unfortunate exception: https://caniuse.com/mdn-css_properties_column-gap_flex_context
If you need support for those exceptions and possibly even Internet Explorer, you can go like this:
.date-of-birth > *:not(:last-child) {
margin-right: 5px;
}
.date-of-birth {
display: flex;
margin: 0 -5px;
}
.date-of-birth mat-form-field {
max-width: 33.33%;
flex: 0 0 33.33%;
padding: 0 5px;
}
I'd suggested this one.
I have a grid container that has multiple labels and inputs. Is it possible to configure the grid in a way that it auto-fills the space with always two columns so that the label breaks the line with its corresponding input?
Grid before resize:
Label
Input
Label
Input
Label
Input
Grid after resize:
Label
Input
Label
Input
Label
Input
Simply wrap inputs inside their label:
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-gap:5px;
}
input{
width:50%;
float:right;
}
<div class="grid">
<label>label <input type="text"></label>
<label>label <input type="text"></label>
<label>label <input type="text"></label>
<label>label <input type="text"></label>
<label>label <input type="text"></label>
<label>label <input type="text"></label>
</div>
You can provide multiple tracks in the second argument of repeat and it will always fill to a multiple of that number of tracks.
In the case of auto-fill the tracks must be <fixed-length>. It is explained better by MDN repeat() docs including auto-fill
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(50px, max-content) minmax(50px, max-content));
grid-gap:5px;
}
<div class="grid">
<label>label</label> <input type="text">
<label>label</label> <input type="text">
<label>label</label> <input type="text">
<label>label</label> <input type="text">
<label>label</label> <input type="text">
<label>label</label> <input type="text">
</div>
I need to insert a multi-column which spans over 2 columns.
Since my final form consists of 150+ label/input -pairs and that I would fetch data from array, I need to keep the label and input separated in HTML (as-is in the code).
Question: What is the minimal adjusting in CSS that needs to be done to get existing code to span as multi-column over 2 columns? HTML should stay intact.
.form_content {
display: grid;
grid-auto-rows: auto;
grid-auto-flow: column;
}
.form_content label {
grid-column: 1;
}
.form_content input {
grid-column: 2;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="main.css">
<title>Automated creation of form</title>
</head>
<body>
</body>
</html>
<div class="form_content">
<!-- Labels -->
<label for="1">Label-1</label>
<label for="2">Label-2</label>
<label for="3">Label-3</label>
<label for="4">Label-4</label>
<label for="5">Label-5</label>
<label for="6">Label-6</label>
<!-- Input fields -->
<input id="1" type="text" name="1" value="-">
<input id="2" type="text" name="2" value="-">
<input id="3" type="text" name="3" value="-">
<input id="4" type="text" name="4" value="-">
<input id="5" type="text" name="5" value="-">
<input id="6" type="text" name="6" value="-">
</div>
Is that you want
.form_content {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-flow: column;
}
label {
grid-column: 1;
}
input {
grid-column: 2;
}
label:nth-of-type(n+4) {
grid-column: 3;
}
input:nth-of-type(n+4) {
grid-column: 4;
}
label {
text-align: right;
}
label,
input {
margin: 5px;
}
<div class="form_content">
<!-- Labels -->
<label for="1">Label-1</label>
<label for="2">Label-2</label>
<label for="3">Label-3</label>
<label for="4">Label-4</label>
<label for="5">Label-5</label>
<label for="6">Label-6</label>
<!-- Input fields -->
<input id="1" type="text" name="1" value="-">
<input id="2" type="text" name="2" value="-">
<input id="3" type="text" name="3" value="-">
<input id="4" type="text" name="4" value="-">
<input id="5" type="text" name="5" value="-">
<input id="6" type="text" name="6" value="-">
</div>
this ?
.form_content {
display: grid;
grid-template-columns: 1fr 2fr ;
grid-auto-rows: auto;
grid-auto-flow: column;
}
label {text-align: right; padding: .5em .3em 0 0; }
label::after {content:' :'}
.form_content label { grid-column: 1; }
.form_content input { grid-column: 2; }
#media screen and (max-height: 20em) {
.form_content { grid-template-columns: 1fr 2fr 1fr 2fr;}
.form_content > label:nth-of-type(n+4) { grid-column: 3; }
.form_content > input:nth-of-type(n+4) { grid-column: 4 }
}
/* first attempt ..
.form_content label:nth-child(odd) { grid-column: 1; }
.form_content input:nth-child(odd) { grid-column: 2; }
.form_content label:nth-child(even) { grid-column: 3; }
.form_content input:nth-child(even) { grid-column: 4; }
*/
<div class="form_content">
<!-- Labels -->
<label for="1">Label-1</label>
<label for="2">Label-2</label>
<label for="3">Label-3</label>
<label for="4">Label-4</label>
<label for="5">Label-5</label>
<label for="6">Label-6</label>
<!-- Input fields -->
<input id="1" type="text" name="1" value="-1">
<input id="2" type="text" name="2" value="-2">
<input id="3" type="text" name="3" value="-3">
<input id="4" type="text" name="4" value="-4">
<input id="5" type="text" name="5" value="-5">
<input id="6" type="text" name="6" value="-6">
</div>
I'm trying to set up my form so that the text input is on one side, and two buttons take up the rest of the side, one on top and the other on the bottom.
I've tried to use br, but this has not done anything. I'm also doing this on Angular 7.0 if it matters.
HTML
<form class="form" (ngSubmit)="onSubmit()">
<input type="text" name="title" [(ngModel)]="title" placeholder="Add Todo">
<input type="submit" value="Submit" class="btn">
<input type="reset" value="Reset" class="btn">
</form>
CSS
.form {
display: flex;
}
.form input[type='text'] {
flex: 10;
padding: 5px;
height: 40px;
}
.form input[type='submit'] {
flex: 2;
height: 20px;
display: block;
}
.form input[type='reset'] {
flex: 2;
height: 20px;
display: block;
}
Currently, all three are side by side, like this. I want the two buttons to be on top of each other.
If you don't want to change your markup, you can use display: grid.
form {
display: grid;
grid-template-areas: 'form topbutton' 'form bottombutton'
}
input[type="text"] {
grid-area: form;
}
input[type="submit"] {
grid-area: topbutton;
}
input[type="reset"] {
grid-area: bottombutton;
}
<form class="form" (ngSubmit)="onSubmit()">
<input type="text" name="title" [(ngModel)]="title" placeholder="Add Todo">
<input type="submit" value="Submit" class="btn">
<input type="reset" value="Reset" class="btn">
</form>
A more solid solution may use flexbox:
div.row {
display: flex;
width: 100%;
/* you may add height if you need it */
/* height: 125px; */
}
div.row > * {
flex: 1 1 80%;
}
div.row > .buttons {
flex: 1 1 20%;
display: flex;
flex-direction: column;
}
div.row > .buttons > * {
flex: 1 1 auto;
}
<form class="form" (ngSubmit)="onSubmit()">
<div class="row">
<input type="text" name="title" [(ngModel)]="title" placeholder="Add Todo">
<div class="buttons">
<input type="submit" value="Submit" class="btn">
<input type="reset" value="Reset" class="btn">
</div>
</div>
</form>
Add display: block to your input elements to have them occupy a new line.
You can also divide the elements into two columns by wrapping the desired elements in <div> classes (in this case of .left and .right), and floating them both to the left.
This can be seen in the following:
.left, .right {
width: 50%;
float: left;
}
.right input {
display: block;
}
<form class="form" (ngSubmit)="onSubmit()">
<div class="left">
<input type="text" name="title" [(ngModel)]="title" placeholder="Add Todo">
</div>
<div class="right">
<input type="submit" value="Submit" class="btn">
<input type="reset" value="Reset" class="btn">
</div>
</form>
I've never used Angular, but I usually use two br afterward with html and it works fine, alternatively you could use css to manually change the location of each element with style and margin (top,left,etc.). ie: like so:
br example:
<form class="form" (ngSubmit)="onSubmit()">
<input type="text" name="title" [(ngModel)]="title" placeholder="Add Todo"><br><br>
<input type="submit" value="Submit" class="btn"><br><br>
<input type="reset" value="Reset" class="btn"><br><br>
</form>
css example:
<form class="form" (ngSubmit)="onSubmit()">
<input style=margin-top:90px type="text" name="title" [(ngModel)]="title" placeholder="Add Todo"><br><br>
<input style=margin-top:100px type="submit" value="Submit" class="btn"><br><br>
<input style=margin-top:110px type="reset" value="Reset" class="btn"><br><br>
</form>
A picture is needed here.
I have a 9 grid defined using CSS grid like this...
.App {
height: 100vh;
width: 100vw;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
grid-template-areas: "1 2 3" "4 5 6" "7 8 9";
}
In the 2, 4, 6 and 8 grid-areas I've got a number of input elements. They stretch to fit their parent element using flexbox like this ...
.ItemsSection {
display: flex;
flex-direction: column;
}
.ItemsSection * {
flex: 1;
font-size: 100%;
}
You can see from the image that I've tried to rotate the 4 grid-area. It didn't work. I'm not surprised about that but I'm struggling to think how I would achieve that layout without a lot of pain.
What I need is for the inputs to be transformed by 90 degrees and then fitted to the parent element so that they are sideways on but sized to the mid-blue area.
Honestly, I'm not even sure what to google for that!
I'm really looking for a CSS only solution but beggars can't be choosers.
EDIT: Code snippet added as requested
.app {
height: 100vh;
width: 100vw;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
grid-template-areas: "a b c" "d e f" "g h i";
}
.ItemSection {
display: flex;
flex-direction: column;
padding:10px;
}
.ItemSection * {
flex: 1;
font-size: 100%;
text-align: center;
}
.one {
background-color: #999;
grid-area: a;
}
.two {
background-color: #666;
grid-area: b;
}
.three {
background-color: #999;
grid-area: c;
}
.four {
background-color: #666;
grid-area: d;
}
.five {
background-color: #999;
grid-area: e;
}
.six {
background-color: #666;
grid-area: f;
}
.seven {
background-color: #999;
grid-area: g;
}
.eight {
background-color: #666;
grid-area: h;
}
.nine {
background-color: #999;
grid-area: i;
}
<div class="app">
<div class="ItemSection one">
<input />
<input />
<input />
<input />
</div>
<div class="ItemSection two">
<input />
<input />
<input />
<input />
</div>
<div class="ItemSection three">
<input />
<input />
<input />
<input />
</div>
<div class="ItemSection four">
<input />
<input />
<input />
<input />
</div>
<div class="ItemSection five">
<input />
<input />
<input />
<input />
</div>
<div class="ItemSection six">
<input />
<input />
<input />
<input />
</div>
<div class="ItemSection seven">
<input />
<input />
<input />
<input />
</div>
<div class="ItemSection eight">
<input />
<input />
<input />
<input />
</div>
<div class="ItemSection nine">
<input />
<input />
<input />
<input />
</div>
</div>
Thanks in advance.
Despite my comment to your question with a working solution (albeit it'll only work in a certain layout), I believe you can solve your issue with writing-mode: sideways-lr; (and maybe prefixes?) but you might want to tweak how your inputs are sized.
.app {
height: 100vh;
width: 100vw;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
grid-template-areas: "a b c" "d e f" "g h i";
}
.ItemSection {
display: flex;
flex-direction: column;
padding: 10px;
}
.ItemSection * {
flex: 1;
font-size: 100%;
text-align: center;
}
.one {
grid-area: a;
}
.two {
grid-area: b;
}
.three {
grid-area: c;
}
.four {
grid-area: d;
}
.five {
grid-area: e;
}
.six {
grid-area: f;
}
.seven {
grid-area: g;
}
.eight {
grid-area: h;
}
.nine {
grid-area: i;
}
.one,
.three,
.five,
.seven,
.nine {
background-color: #999;
}
.two,
.four,
.six,
.eight {
background-color: #666;
-webkit-writing-mode: sideways-lr;
-ms-writing-mode: sideways-lr;
writing-mode: sideways-lr;
}
<div class="app">
<div class="ItemSection one">
<input />
<input />
<input />
<input />
</div>
<div class="ItemSection two">
<input />
<input />
<input />
<input />
</div>
<div class="ItemSection three">
<input />
<input />
<input />
<input />
</div>
<div class="ItemSection four">
<input />
<input />
<input />
<input />
</div>
<div class="ItemSection five">
<input />
<input />
<input />
<input />
</div>
<div class="ItemSection six">
<input />
<input />
<input />
<input />
</div>
<div class="ItemSection seven">
<input />
<input />
<input />
<input />
</div>
<div class="ItemSection eight">
<input />
<input />
<input />
<input />
</div>
<div class="ItemSection nine">
<input />
<input />
<input />
<input />
</div>
</div>