I'm trying to build out a form module so that regardless of the various inputs a form may have, the following conditions are always met:
The form is centered within its containing element. (I think this is just inline-block combined with text-align: center.)
The inputs are all the same width and line up along their left edge.
The labels can be any length (within reason), and their right edges all line up.
The form is only as wide as its longest label/input combination (in other words, the width of the form is dynamic and determined by its longest label). (The red lines in the image below represent the bounding edges of the form as per the given labels and inputs.)
Basically, I want something like the following:
This type of layout is really easy to do with tables, but I have read that tables are not advisable to use for forms, so my question is, how can I do all of this without using a table?
Thank you.
Edit: The layout must work in IE8.
You can accomplish the required behavior using flex.
HTML structure (it's just an approach):
<div id="container">
<div class="form-container">
<form>
<div class="column">
<label for="text1">This is a label</label>
<label for="text2">Label</label>
<label for="text3" style="flex-grow:2;">Another larger label :D</label>
<label for="text4">A short one!</label>
</div>
<div class="column">
<input type="text" name="text1" />
<input type="text" name="text2" />
<textarea name="text4" style="flex-grow:2;"></textarea>
<input type="text" name="text3" />
</div>
</form>
</div>
</div>
CSS:
#container {
text-align: center;
}
#container .form-container {
display: inline-block;
}
#container form {
background: #eee;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
padding: 20px;
}
#container form .column {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
}
#container form .column label {
padding: 2px;
text-align: right;
}
#container form .column input,
#container form .column textarea {
align-self: flex-start;
width: 200px;
}
Here is a working demo: http://jsfiddle.net/gopafm4g/2/
Related
I am trying to get the text input on the same line as the h1 tag inline then display it as a flex-direction of column. But it only seems to want to set all the inputs in a line and with the h1 on top which is not what I want.
Here is what I mean.
here is the desired output:
.contactuscontent{
border: 1px solid pink;
display: flex;
}
.contactusinput {
display: inline-flex;
flex-direction: column;
border: 1px solid purple;
}
<div class="contactuscontent">
<div class="contactusinput">
<div class="name"><h1>Name</h1> <input type="text"> </div>
<div class="email"><h1>Email</h1> <input type="text"> </div>
<div class="refer"><h1>How did you find us</h1> <input type="text"> </div>
</div>
</div>
You should look into semantics of HTML, <h1> is used for headlines.
If you want to add labels for input fields you should use <label for="...">. You can style the any tag in any way you want so default styling should not be a reason to use a tag at all.
.contactuscontent {
border: 1px solid pink;
display: flex;
justify-content: center;
}
.contactusinput {
width: 400px;
border: 1px solid purple;
}
.contactusinput>div {
display: flex;
justify-content: space-between;
margin-top: 10px;
}
.contactusinput label {
width: 200px;
}
.contactusinput input,
.contactusinput textarea {
width: 200px;
padding: 3px;
}
<div class="contactuscontent">
<div class="contactusinput">
<div class="name"><label for="name">Name</label> <input type="text" id="name" name="name"> </div>
<div class="email"><label for="email">Email</label> <input type="text" id="email"> </div>
<div class="refer"><label for="howtofind">How did you find us</label> <textarea id="howtofind"> </textarea> </div>
</div>
</div>
That's because h1 is a block element, and since it's inside an un-styled div, it will push the input in a new line.
If you make the div that wraps the h1 and the input as flexbox, it will look similar to the image:
.contactusinput div {
display: flex;
}
You don't need flexbox on any of the parents for this to work.
To push inputs in the same line you can add min-width to the h1:
h1 {
min-width: 200px;
}
You will need to apply different styling to smaller screens, likely removing the min-width and showing the h1 in a column instead of row.
Here is a jsFiddle
By the way, heading elements h1-h6 aren't meant for this. You generally want to have only one h1 in the entire site. The better option to use here would be label.
To make the design you want, it is needed to set flexbox on the div which contains input and h1.
So in this case, there will be 3 divs to have the flexbox design and all of them are the direct childs of .contactusinput selector.
So on style, you can set the .contactusinput > div (direct div child of .contactusselector) style to flexbox as follows.
.contactuscontent {
border: 1px solid pink;
display: flex;
}
.contactusinput {
display: inline-flex;
flex-direction: column;
border: 1px solid purple;
}
.contactusinput > div {
display: flex;
justify-content: space-between;
align-items: center;
}
<div class="contactuscontent">
<div class="contactusinput">
<div class="name"><h1>Name</h1> <input type="text"> </div>
<div class="email"><h1>Email</h1> <input type="text"> </div>
<div class="refer"><h1>How did you find us</h1> <input type="text"> </div>
</div>
</div>
This question already has answers here:
Make a div span two rows in a grid
(2 answers)
Closed 3 years ago.
I'm trying to use flexbox to achieve a column layout with an element "floated" to the right.
Something like this:
Thing is, I cannot alter the HTML since it's an embedded form so trying to achieve this via pure CSS.
So far, I have this:
.form {
display: flex;
flex-direction: column;
text-align: center;
}
.form-container {
display: flex;
flex-direction: column;
text-align: center;
justify-content: space-between;
}
.form-form {
width: 100%;
}
form {
display: flex;
justify-content: center;
}
fieldset {
border: 0;
}
textarea {
resize: none;
}
.form-columns-2 {
display: flex;
}
.form-columns-2 input:first-child {
margin-bottom: .5em
}
.form-columns-1 textarea {
height: 100%
}
.submit-wrapper{
flex-direction:column;
}
<div class="form">
<div class="form-container">
<div class="form-form">
<form>
<fieldset class="form-columns-2">
<input type="text" placeholder="test">
<input type="text" placeholder="test">
</fieldset>
<fieldset class="form-columns-2">
<input type="text" placeholder="test">
<input type="text" placeholder="test">
</fieldset>
<fieldset class="form-columns-1">
<textarea placeholder="test">Text</textarea>
</fieldset>
<div class="submit-wrapper">
<div class="actions">
<input type="submit" value="Submit">
</div>
</div>
</form>
</div>
</div>
</div>
Edit:
I also need the submit button to sit under the textarea, but since the .submit-wrapper is a direct child of form, the only way I can see addressing this is by adding flex-direction: column; to form. However, this turns the whole layout into a column, which I do not want.
You are apllying display: flex to the wrong elements and to more elements than you need to.
Check this: https://codepen.io/anon/pen/dwPoEP
* {
box-sizing: border-box;
}
fieldset{
border:0;
}
textarea{
resize:none;
}
form { // you want the form to be a flex box, not everything!
display: flex;
justify-content: center;
}
.form-columns-2 {
display: flex; //you can use other options here, this works but you can use display: block on the inputs for example
}
// this 2 are just to make it look like the image
.form-columns-2 input:first-child {
margin-bottom: .5em
}
.form-columns-1 textarea {
height: 100%
}
I'm going to really struggle to put this into words, but I will try. I have a div with some text in it, this text is dynamic so it can be different lengths depending on user input.
Now I want the option to be able to place an image in one of the following positions, depending on the value of a select dropdown, which will place the image either:
Above the text
Below the text
Left of text
Right of text
I'm wondering if there is an easy way to keep the markup the same, i.e
<img src="">
<span>Text</span>
But use CSS to vary the position of the image to any one of the above positions. It's important to note that the text width and height is dynamic, so it isn't possible to use exact pixels.
I would rather avoid using javascript if possible.
This is all you need:
.container {
display: flex;
}
#p-below:checked ~ .container {
flex-direction: column-reverse;
}
#p-right:checked ~ .container {
flex-direction: row-reverse;
}
#p-above:checked ~ .container {
flex-direction: column;
}
.container {
display: flex;
}
#p-below:checked ~ .container {
flex-direction: column-reverse;
}
#p-right:checked ~ .container {
flex-direction: row-reverse;
}
#p-above:checked ~ .container {
flex-direction: column;
}
/* everything below is totally optional */
.container {
justify-content: center;
align-items: center;
}
.container > .text {
border: 1px solid #424242;
padding: 1rem;
}
.container .image > img {
display: block;
}
<input name="position" type="radio" checked id="p-above" />
<label for="p-above">Above</label>
<input name="position" type="radio" id="p-below" />
<label for="p-below">Below</label>
<input name="position" type="radio" id="p-left" />
<label for="p-left">Left</label>
<input name="position" type="radio" id="p-right" />
<label for="p-right">Right</label>
<div class="container">
<div class="image"><img src="http://lorempixel.com/g/400/300" /></div>
<div class="text">Lorem ipsum dolor sit amet. Have as much text here as you like.</div>
</div>
Use float: left, right or none on the image (using a stylesheet). You cannot place the image below the text with CSS.
So, I understand that tables are the spawn of satan. How should I align this without a table?
I have a bunch of input fields, each with a label to the left of it, and I would like the left side of the input fields to be aligned. Bad ascii art follows:
name ________________
date of birth ________________
Shakespeare villain I would like to be ________________
favo(u)rite do(gh)nut ________________
pet's blood group ________________
mother's maiden name ________________
favo(u)rite Led Zeppelin track ________________
I don't need exact code, just to be told how to do it.
This page looks incredibly helpful, but how do I do it with the text & input fileds?
Maybe a <div> with the text floating right and the input field vertically aligned at 50% ?
Try display: table-cell;
.wrapper {
display: table;
}
.inner {
display: table-cell;
}
#wrapper div.td1 {
text-align: right;
padding: 0;
margin: 0;
vertical-align: middle;
/* added incase of too long label text */
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
#wrapper div {
width: 50%;
display: inline-block;
text-align: left;
padding-left: 5px;
margin-right: -5px;
}
#wrapper {
width: 100%;
line-height: 1.5em;
}
<div id="wrapper">
<div class="td1">name</div><div><input type="text"></div>
<div class="td1">date of birth</div><div><input type="text"></div>
<div class="td1">Shakespeare villain I would like to be</div><div><input type="text"></div>
<div class="td1">favo(u)rite do(gh)nut</div><div><input type="text"></div>
<div class="td1">pet's blood grou </div><div><input type="text"></div>
<div class="td1">mother's maiden name</div><div><input type="text"></div>
<div class="td1">favo(u)rite Led Zeppelin track</div><div><input type="text"></div>
</div>
The best thing you can get here is to recreate table layout with different DOM elements plus some display:table-*** declarations :
div.parent { display:table; }
div.parent > row { display:table-row; }
div.parent > row > * { display:table-cell; }
div.parent > row > label { text-align:right; padding: 0 0.25em; }
div.parent > row > label::after { content:":"; }
<div class="parent">
<row>
<label>name</label>
<p>_____________</p>
</row><row>
<label>date of birth</label>
<p>_____________</p>
</row><row>
<label>Shakespeare villain I would like to be</label>
<p>_____________</p>
</row><row>
<label>favo(u)rite do(gh)nut</label>
<p>_____________</p>
</row><row>
<label>pet's blood group</label>
<p>_____________</p>
</row><row>
<label>mother's maiden name</label>
<p>_____________</p>
</row><row>
<label>favo(u)rite Led Zeppelin track</label>
<p>_____________</p>
</row>
</div>
A touch of flex
This may have some limitations depending on the rest of your layout; treat it as an experiment.
To reduce the amount of HTML used along with a tiny amount of CSS, we can play around with a flexbox layout.
Compatibility: IE 11+ and all modern browsers
The <form> container is given display: flex and, to align each label in the center of its input, align-items: center. flex-wrap: wrap is used to form rows.
The inputs and labels are given flex: 1 1 50%. This gives them an initial width of 50% which will then grow and shrink with the container. The initial value of 50% can be changed to make the inputs wider or smaller, as long as the label and inputs initial values add up to 100%.
The rows are spaced out with margin: 5px 0 5px on the inputs to provide a top and bottom margin. The top and bottom margin value should remain the same so the labels are centered.
box-sizing: border-box incorporates border and padding into the elements width and height
A guide to Flexbox is very useful.
Full Example
The form can be nicely controlled with min-width and max-width to maintain some flexibility.
* {
box-sizing: border-box;
}
form {
display: flex;
flex-wrap: wrap;
align-items: center;
max-width: 600px;
min-width: 300px;
}
label {
text-align: right;
flex: 1 1 50%;
padding-right: 10px;
}
input {
flex: 1 1 50%;
margin: 5px 0 5px;
}
<form>
<label for="label1">This is a really long label</label>
<input id="label1" type="text">
<label for="label2">Smaller label</label>
<input id="label2" type="text">
<label for="label3">Tiny</label>
<input id="label3" type="text">
</form>
This question already has an answer here:
Why are not all flexbox elements behaving like flexbox divs?
(1 answer)
Closed 8 years ago.
I want to use the flex display property on my web form in order to have two text fields side-by side and automatically growing to fill the space. I chose to use flex over a table layout because I want them to move to their own line when the window shrinks.
I believe I am misunderstanding how to use flexbox.
Below is my work so far (simplified for posting here). I am using a fieldset as a flex parent, and each form element which should "grow" side-by-side is encased in a div (set to display: inline so they can be on the same line). I also have a legend for the fieldset, set to display:block and width:100% so that it will be on its own line.
jsFiddle link
fieldset {
display: flex;
flex-direction: row;
justify-content: space-between;
border: none;
}
label {
display: none;
}
legend {
display: block;
width: 100%;
}
fieldset > div {
display: inline;
flex: 1 1 auto;
}
input {
width: 100%;
}
<form>
<fieldset>
<legend>These are Text Fields</legend>
<div>
<input type="text" id="text1">
<label for="text1">Text Field</label>
</div>
<div>
<input type="text" id="text2">
<label for="text2">More Text</label>
</div>
</fieldset>
</form>
As you can see, the divs are each on their own line (despite the display: inline and flexbox stuff). If you add a border to the div elements, you'll see that they are 100% width right now; but even if you manually define a width (like 30%), they remain on their own lines.
How can I use flex to display the divs side-by-side and allow them to scale to fill the parent's width?
EDIT: This bug has been fixed in Firefox and Chrome. The example as originally posted in the question now works as intended.
https://bugzilla.mozilla.org/show_bug.cgi?id=1230207
https://bugs.chromium.org/p/chromium/issues/detail?id=375693
Two things here:
When you do display: flex on an element, every single direct child is affected. So in your example (if it were working) the legend will also be displayed on the same line.
For whatever reason, fieldset doesn't like to play nicely with flexbox. since you don't want the legend to be on the same line anyway, I would suggest specifically wrapping the elements you want to be on the same line.
<form>
<fieldset>
<legend>These are Text Fields</legend>
<div class="flex-wrapper">
<div>
<input type="text" id="text1">
<label for="text1">Text Field</label>
</div>
<div>
<input type="text" id="text2">
<label for="text2">More Text</label>
</div>
</div>
</fieldset>
</form>
fieldset {
border: none;
}
.flex-wrapper {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: stretch;
}
.flex-wrapper > div {
flex: 1 1 auto;
}
label {
display: none;
}
legend {
display: block;
width: 100%;
}
input {
width: 100%;
}