Position image in four different possible places using CSS alone - html

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.

Related

How to make div elements appear inline with a flex direction of column?

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>

Using flex to achieve two rows and one column layout [duplicate]

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%
}

Aligning elements horizontally adjacent that are in different grid cells with CSS Grid and Flexbox

Currently I'm using a mixture between grid and flexbox to try and achieve a layout for a form.
I would like both input elements to horizontally lineup without setting a height on them. If I were to apply for padding on the text input, the range should continue to vertically center with the input adjacent to it.
Additionally I would like the label elements to also remain horizontally aligned too.
Please suggest solutions that DO NOT require changing the markup or using Javascript.
Currently what I have:
What I'm trying to achieve:
I know I could apply a fixed height or padding on the range to align it but I'm trying to make this as fluid as possible.
HTML:
<form class="grid">
<div class="group">
<label for="input-1">Label 1</label>
<input type="text" id="input-1" placeholder="placeholder" />
</div>
<div class="group">
<label for="input-2">Label 2</label>
<div class=range-wrapper>
<input type="range" id="input-2" placeholder="placeholder" />
<output>0</output>
</div>
</div>
</form>
SCSS:
html {
box-sizing: border-box;
}
*, *::before, *::after {
box-sizing: inherit;
}
body {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.2rem;
}
.grid {
width: 80%;
max-width: 960px;
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: 40px 10px;
padding: 50px;
background: #ccc;
}
.group {
display: flex;
flex-direction: column;
margin-top: auto;
label {
margin-bottom: 10px;
}
}
input {
font-size: inherit;
&[type="text"] {
padding: 14px;
}
&[type="range"] {
width: 100%;
}
}
.range-wrapper {
display: flex;
align-items: center;
output {
padding: 10px;
}
You can also check out the codepen here.
Many thanks!
** EDIT **
Should support multiline labels, if the label wraps multiple lines, elements should still horizontally align.
Multiline label example: Codepen
try this for your "group" class.
(or use a new class for that element with this styling)
.group {
display: flex;
flex-direction: column;
justify-content: center;
label {
margin-bottom: 10px;
}
}

Always center form and line up inputs, regardless of label length

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/

CSS Flexbox in a Form [duplicate]

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%;
}