Swap DIV position with CSS only - css

I'm trying to swap two divs' locations for responsive design (the site looks different depending on width of the browser/good for mobile).
Right now I have something like this:
<div id="first_div"></div>
<div id="second_div"></div>
But would it be possible to swap their placements to make it look like second_div is first, using CSS only? The HTML stays the same. I've tried using floats and stuff but it doesn't seem to work the way I want it to. I don't want to use absolute positioning because the heights of the divs are always changing. Are there any solutions, or is there just no way to do this?

Someone linked me this: What is the best way to move an element that's on the top to the bottom in Responsive design.
The solution in that worked perfectly. Though it doesn’t support old IE, that doesn’t matter for me, since I’m using responsive design for mobile. And it works for most mobile browsers.
Basically, I had this:
#media (max-width: 30em) {
.container {
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-box-orient: vertical;
-moz-box-orient: vertical;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
/* optional */
-webkit-box-align: start;
-moz-box-align: start;
-ms-flex-align: start;
-webkit-align-items: flex-start;
align-items: flex-start;
}
.container .first_div {
-webkit-box-ordinal-group: 2;
-moz-box-ordinal-group: 2;
-ms-flex-order: 2;
-webkit-order: 2;
order: 2;
}
.container .second_div {
-webkit-box-ordinal-group: 1;
-moz-box-ordinal-group: 1;
-ms-flex-order: 1;
-webkit-order: 1;
order: 1;
}
}
This worked better than floats for me, because I needed them stacked on top of each other and I had about five different divs that I had to swap around the position of.

The accepted answer worked for most browsers but for some reason on iOS Chrome and Safari browsers the content that should have shown second was being hidden. I tried some other steps that forced content to stack on top of each other, and eventually I tried the following solution that gave me the intended effect (switch content display order on mobile screens), without bugs of stacked or hidden content:
.container {
display:flex;
flex-direction: column-reverse;
}
.section1,
.section2 {
height: auto;
}

This question already has a great answer but in the spirit of exploring all possibilities here is another technique to reorder dom elements whilst still allowing them to take up their space, unlike the absolute positioning method.
This method works in all modern browsers and IE9+ (basically any browser that supports display:table) it has a drawback that it can only be used on a max of 3 siblings though.
//the html
<div class='container'>
<div class='div1'>1</div>
<div class='div2'>2</div>
<div class='div3'>3</div>
</div>
//the css
.container {
display:table;
}
.div1 {
display:table-footer-group;
}
.div2 {
display:table-header-group;
}
.div3 {
display:table-row-group;
}
This will reorder the elements from 1,2,3 to 2,3,1. Basically anything with the display set to table-header-group will be positioned at the top and table-footer-group at the bottom. Naturally table-row-group puts an element in the middle.
This method is quick with good support and requires much less css than the flexbox approach so if you are only looking to swap a few items around for a mobile layout for example then dont rule out this technique.
You can check out a live demo on codepen: http://codepen.io/thepixelninja/pen/eZVgLx

This solution worked for me:
Using a parent element like:
.parent-div {
display:flex;
flex-direction: column-reverse;
}
In my case I didn't have to change the css of the elements that I needed to switch.

In some cases you can just use the flex-box property order.
Very simple:
.flex-item {
order: 2;
}
See: https://css-tricks.com/almanac/properties/o/order/

Using CSS only:
#blockContainer {
display: -webkit-box;
display: -moz-box;
display: box;
-webkit-box-orient: vertical;
-moz-box-orient: vertical;
box-orient: vertical;
}
#blockA {
-webkit-box-ordinal-group: 2;
-moz-box-ordinal-group: 2;
box-ordinal-group: 2;
}
#blockB {
-webkit-box-ordinal-group: 3;
-moz-box-ordinal-group: 3;
box-ordinal-group: 3;
}
<div id="blockContainer">
<div id="blockA">Block A</div>
<div id="blockB">Block B</div>
<div id="blockC">Block C</div>
</div>

Assuming Nothing Follows Them
If these two div elements are basically your main layout elements, and nothing follows them in the html, then there is a pure HMTL/CSS solution that takes the normal order shown in this fiddle and is able to flip it vertically as shown in this fiddle using one additional wrapper div like so:
HTML
<div class="wrapper flipit">
<div id="first_div">first div</div>
<div id="second_div">second div</div>
</div>
CSS
.flipit {
position: relative;
}
.flipit #first_div {
position: absolute;
top: 100%;
width: 100%;
}
This would not work if elements follow these div's, as this fiddle illustrates the issue if the following elements are not wrapped (they get overlapped by #first_div), and this fiddle illustrates the issue if the following elements are also wrapped (the #first_div changes position with both the #second_div and the following elements). So that is why, depending on your use case, this method may or may not work.
For an overall layout scheme, where all other elements exist inside the two div's, it can work. For other scenarios, it will not.

Simple flexbox solution utilizing the order-property:
.container {
display: flex;
flex-direction: column;
}
.first {
order: 3;
}
.second {
order: 2;
}
<div class="container">
<div class="first">First</div>
<div class="second">Second</div>
<div class="third">Third</div>
</div>

assuming both elements have 50% width, here is what i used:
css:
.parent {
width: 100%;
display: flex;
}
.child-1 {
width: 50%;
margin-right: -50%;
margin-left: 50%;
background: #ff0;
}
.child-2 {
width: 50%;
margin-right: 50%;
margin-left: -50%;
background: #0f0;
}
html:
<div class="parent">
<div class="child-1">child1</div>
<div class="child-2">child2</div>
</div>
example: https://jsfiddle.net/gzveri/o6umhj53/
btw, this approach works for any 2 nearby elements in a long list of elements. For example I have a long list of elements with 2 items per row and I want each 3-rd and 4-th element in the list to be swapped, so that it renders elements in a chess style, then I use these rules:
.parent > div:nth-child(4n+3) {
margin-right: -50%;
margin-left: 50%;
}
.parent > div:nth-child(4n+4) {
margin-right: 50%;
margin-left: -50%;
}

Yesterday ran into the same problem. Grid areas worked out great in my case:
.content-body {
display: grid;
grid-template-areas: " left right ";
grid-template-columns: 1fr 1fr;
}
.first_div {
grid-area: right;
}
.second {
grid-area: left;
}

You don't need anything fancy. Make a copy of your second div, and place it on top. Like this
<div id="second_div_copy"></div>
<div id="first_div"></div>
<div id="second_div"></div>
Give the second_div_copy display: none when you want first div to appear on top. Give the second_div_copy display: block, and the second_div display: none when you want the second div to appear on top.
It's really that simple. Or am I missing something ?

Related

How to make a v-textarea fill the screen vertically?

I'm using Vuetify and I want a page that is mostly one big v-textarea. There is some stuff on top, and maybe on the bottom, but besides that I want the page filled with v-textarea, with no scrolling (except scrolling inside the v-textarea). I feel adding a style like "height:calc(100vh - 100px)" is a bit hack.
Is there some way I can do this the real way?
Thanks.
Not sure what you call "the real way", but in one (more or less real) way or another you have to tell the <textarea> or one of its ancestors to fill up the free space of your viewport.
The typical solution is to have a parent wrapper which fills up the viewport, with display: flex; flex-direction: column and give your element flex-grow: 1
body {margin: 0; padding: 0; }
* { box-sizing: border-box; }
.wrapper {
min-height: 100vh;
display: flex;
flex-direction: column;
padding: 1rem;
}
.wrapper > * {
flex-grow: 0;
}
.wrapper > textarea {
flex-grow: 1;
margin-top: 1rem;
}
<div class="wrapper">
<div>
Some variable height stuff...
<hr>
<div contenteditable="true">Click to edit and make this element taller.<br> The textarea will adjust accordingly.</div>
</div>
<textarea>Your text area...</textarea>
</div>
The advantage is you don't have to hardcode the difference into <textarea>'s height. Instead, you tell it: fill up the available free space.

Flexbox conundrum - how to nest flex box in layers of custom elements and get the desired result with media queries

This is a question about alignment with flexbox when used in a column direction. The trouble I'm finding is that all the documentation uses examples in rows, and certain things don't seem to translate when changing the axis.
I'm building a web single page web app which is structured in multiple lays of custom elements. I exclude selection between pages for simplicity sake, so this view is a summary of the contents of one page, the others being essentially swapped out (using litHtml and the cache directive controlled by a dynamic object selection). My hierarchy is like this (apart from the <app-page> element, all the other elements have their content solely in the shadowroot, so not as children as shown here. <app-page> is more of a utility item and so it has slots defined in the shadow root and its real children are hoisted in to them. I use some lines to indicate the difference between its shadow root and its real children. <app-error> will have no content most of the time - it gains content when there is an error, and at that point <app-session> displays no content.
<main-app>
<header>My App Header Bar with menu button and App-logo etc</header>
<section>
<app-error></app-error>
<app-session>
<app-verify-email>
<app-page>
<--
<header>Different sort of Logo </header>
<slot></slot>
<div id="wedge"></div>
<slot name="action></slot>
-->
<h1>Verify Email Header</h1>
<p>Some text about Verifying Email</p>
<input type="email" value="${this.email}"/.
<button slot="action">Send</button>
<button slot="action>Cancel</button>
</app-page>
</app-verify-email>`,
</app-session>
</section>
</main-app>`
My objective is as follows the normal case I assume we have a mobile phone, where the main-app's header bar will be at the bottom of the screen, to make the menu button on it close the the users thumb. I achieve this by giving main-app a style of
:host {
height: 100vh;
display: flex;
flex-direction: column-reverse;
}
#media (min-width: 500px) {
:host {
flex-direction: column;
}
}
To support the other elements in the chain, so they are all fully stretched, I have decided to try them with
:host {
display: flex;
flex-direction: row;
align-items: stretch;
}
this allows them to fill out to full content, but (I hope) allows <app-session> to collapse down when <app-error> has something to display (and it doesn't because the error stage will be selected.
The other consideration is, I want the rest of the content to nestle at the top EXCEPT the buttons inside the "action" slot. Firstly in the normal case the buttons should be at the bottom just above the header bar, but in the wider screen situation they should be at the top immediately under the content. I am trying to achieve by host styles as so:-
:host {
display: flex;
flex-direction: column;
}
#wedge {
display: block;
flex:1;
}
#media-query (min-width: 500px) {
#wedge {
display: none;
flex:0;
}
}
but its not working and I don't know why?
I've tried other options, like not using the wedge and instead putting align-item: flex end; on the button slot but that doesn't work either.
As I said above I am struggling to find flex box examples that are based on column layouts, so I could do with help working how how to achieve my objectives.
I made a test case and have been working away at it to try and solve this. The trick, I think is to be sparing with when something is a flex-box, but also to make use of height=100% to force not flexbox items to fill the space, so that its internal flexbox items can do their thing over the entire space.
The real clincher was the use of margin:auto as a way of pushing the button block to the bottom, even though the contents is justified to flex-start. This appears to be the "standard" way of pushing items in a flex container apart;
<!DOCTYPE html>
<html lang="en">
<head>
<style>
html {
background: #ffffff;
}
body {
margin: 0;
min-height: 100vh;
font-family: sans-serif;
line-height: 1.5;
letter-spacing: 0.1em;
background-color: #fafafa;
color: #333;
}
.main-app {
height: 100vh;
display: flex;
flex-direction: column-reverse;
justify-content:flex-start;
}
.main-app>header {
height: 64px;
color: white;
background-color: #adcabd;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items:center;
}
.main-app>section {
height: calc(100vh - 64px);
display: flex;
flex-direction: column;
}
.app-session {
display:block;
flex:1;
}
.app-verify-email {
height: 100%;
display:flex;
flex-direction:column;
align-items: center;
}
.app-page{
height:100%;
display: flex;
flex-direction:column;
max-width: 600px;
justify-content: start;
padding:10px;
}
.app-page header {
height: 64px;
margin: 0 auto;
padding: 0;
}
.action {
display: flex;
width:100%;
flex-direction:row;
flex-wrap: wrap;
justify-content: space-evenly;
margin-top:auto;
}
#media (min-width: 500px) {
.main-app {
flex-direction: column;
}
.action {
margin-top: 10px;
}
.app-page {
min-width:600px;
height: auto;
}
}
#media (min-width: 501px) {
.app-page {
border-radius: 10px;
box-shadow: 0px 0px 38px -2px rgba(0, 0, 0, 0.5);
}
}
</style>
</head>
<body>
<div class="main-app">
<header><img src="/appimages/site_logo.png"/><div>v1.0.0</div></header>
<section>
<div class="app-error"><!--Error in progress--></div>
<div class="app-session">
<div class="app-verify-email">
<div class="app-page">
<header>Different sort of Logo </header>
<section class="container">
<h1>Verify Email Header</h1>
<p>Some text about Verifying Email</p>
<input type="email" value="alan#chandlerfamily.org.uk"/>
</section>
<div class="action">
<button>Send</button>
<button cancel>Cancel</button>
</div>
</app-page>
</div>
</div>
</section>
</div>
</body>
</html>

Is it possible to round values in css? Or, how to solve half/sub-pixels on % translated layouts?

I have a curious problem. I built a flex/grid fullscreen responsive interface. I used % values. It works fine, but sometimes, randomly, by resizing the window a 1 px line appears between item (horizontal, vertical, or both). I think maybe that's because, using % values and being the elements liquid, the items size is not always perfect-pixel. Look:
How could I avoid that, still maintaining a responsive layout?
I managed to somewhat good by very little scaling the inner elements (images and rollover layers) like scale(1.005), but still it was not always perfect. The problem is that browsers can't round element sizes on fullscreen layouts, or something like that, don't know.
Just a little abstraction of my original code, just to add context. It's a 3 cols flex layout where 1 col is 50% width (the third one is off screen > the overall behaves like a 3 panels 'slideshow'). The second column, itself contains the grid on the picture:
/* HTML */
<div class="sections-list">
<div class="section column-1"></div>
<div class="section column-2">
<div class="grid">
<button type="button">a</button>
<button type="button">b</button>
<button type="button">c</button>
<button type="button">d</button>
</div>
</div>
<div class="section column-3"></div>
</div>
/* SCSS */
.sections-list{
display: flex;
justify-content: flex-start;
min-height: 100vh;
translateX(-50%);
}
.section{
flex-grow:1;
min-width: 50%;
box-sizing:border-box;
min-height: 100vh;
}
.grid{
display: grid;
height: 100%;
grid-template:
"a b" 50%
"c d" 50%
/ 50% 50%;
button{
display: block;
position: relative;
overflow: hidden;
padding: 0;
min-width: none;
max-width: none;
height: auto;
&:nth-child(1){ grid-area: a; }
&:nth-child(2){ grid-area: b; }
&:nth-child(3){ grid-area: c; }
&:nth-child(4){ grid-area: d; }
}
}
So, it turns out the problem was caused by the 50% translation on the main element. That caused half pixels when window.width was odd.
The solution to me was to recalculate and round the translation using a little javascript, css --properties and a fallback for legacy browsers. Here's some simplified code (and please look to the original's code too):
:root{
--half-window: -50%;
}
.sections-list{
display: flex;
justify-content: flex-start;
min-height: 100vh;
transform: translatex(-50%); // legacy
transform: translatex(var(--half-window));
}
then:
function round_half_window(){
document.documentElement.style.setProperty('--half-window', -Math.round($(window).width()/2) + 'px');
}
$window.resize(_.debounce(function(){ round_half_window(); },500));
round_half_window();

Masonry with Flexbox, dynamic height [duplicate]

I have 3 divs inside a container. There are no nested divs.
I am using flex and order property.
On mobile, it is ok with order property.
But on larger screens it fails.
I did not use a container div for divs 2 and 3 in order to order them as 2,1,3 on mobile.
HTML FILE
<div class="container">
<div class="orange">1</div>
<div class="blue">2</div>
<div class="green">3</div>
</div>
CSS FILE
/*************** MOBILE *************/
.container
{
display: flex;
flex-wrap: wrap;
}
div.blue
{
order:1;
width: 100%;
}
div.orange
{
order:2;
width: 100%;
}
div.green
{
order:3;
width: 100%;
}
/***************************/
#media screen and (min-width:1200px)
{
.container
{
justify-content: space-between;
}
div.blue
{
order:2;
width: 36%;
}
div.orange
{
order:1;
width: 60%;
}
div.green
{
order:3;
width: 36%;
}
}
In your layout, using row wrap for the desktop view will be difficult, if not impossible, to implement with CSS. At a minimum, things would get overly complex. Why?
Because flexbox is not a grid system. It's a layout system designed to align content by distribution of space in the container.
In flexbox, items in a row wrap container must wrap to new rows. This means that div3 cannot wrap beneath div2. It must wrap beneath div1.
Here's how items wrap in a flex container with row wrap:
If div3 were to wrap under div2, that wouldn't be a row, that would be a grid, and flex items are confined to a straight, unbending row.
Put another way, you can't make a flex item wrap under another item in the same row.
As a result, white space created by items that aren't the tallest in the row is preserved in each column, creating unsightly gaps.
For your desired layout to work in row wrap, flex items would have to exit their row in order to close the gap – maybe with absolute positioning – which flexbox cannot do.
One way to align the items would be to wrap div2 and div3 in their own container. This new container would be a sibling to div1. It can then become a nested flex container with flex-direction: column. Now the gaps are gone and layout looks right.
Except, in this particular case, you need the order property to work (meaning all items must have the same parent), so a nested flex container is out of the question.
What may work is column wrap instead of row wrap:
/*************** MOBILE *************/
.container {
display: flex;
flex-direction: column;
height: 200px; /* necessary so items know where to wrap */
}
div.orange {
background-color: orange;
}
div.blue {
order: -1;
background-color: aqua;
}
div.green {
background-color: lightgreen;
}
.container > div {
width: 100%;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
/***************************/
#media screen and (min-width: 800px) {
.container {
flex-wrap: wrap;
}
div.orange {
flex-basis: 100%;
width: 50%;
}
div.blue {
flex-basis: 50%;
width: 50%;
order: 0;
}
div.green {
flex-basis: 50%;
width: 50%;
}
}
<div class="container">
<div class="orange">1</div>
<div class="blue">2</div>
<div class="green">3</div>
</div>
jsFiddle
Here are two other options:
Desandro Masonry
Masonry is a JavaScript grid layout library. It
works by placing elements in optimal position based on available
vertical space, sort of like a mason fitting stones in a wall.
source: http://masonry.desandro.com/
CSS Grid Layout Module Level 1
This CSS module defines a two-dimensional grid-based layout system, optimized for user interface design. In the grid layout model, the children of a grid container can be positioned into arbitrary slots in a predefined flexible or fixed-size layout grid.
source: https://drafts.csswg.org/css-grid/
Related post: Is it possible for flex items to align tightly to the items above them?

Flexbox wrapping issues [duplicate]

I have 3 divs inside a container. There are no nested divs.
I am using flex and order property.
On mobile, it is ok with order property.
But on larger screens it fails.
I did not use a container div for divs 2 and 3 in order to order them as 2,1,3 on mobile.
HTML FILE
<div class="container">
<div class="orange">1</div>
<div class="blue">2</div>
<div class="green">3</div>
</div>
CSS FILE
/*************** MOBILE *************/
.container
{
display: flex;
flex-wrap: wrap;
}
div.blue
{
order:1;
width: 100%;
}
div.orange
{
order:2;
width: 100%;
}
div.green
{
order:3;
width: 100%;
}
/***************************/
#media screen and (min-width:1200px)
{
.container
{
justify-content: space-between;
}
div.blue
{
order:2;
width: 36%;
}
div.orange
{
order:1;
width: 60%;
}
div.green
{
order:3;
width: 36%;
}
}
In your layout, using row wrap for the desktop view will be difficult, if not impossible, to implement with CSS. At a minimum, things would get overly complex. Why?
Because flexbox is not a grid system. It's a layout system designed to align content by distribution of space in the container.
In flexbox, items in a row wrap container must wrap to new rows. This means that div3 cannot wrap beneath div2. It must wrap beneath div1.
Here's how items wrap in a flex container with row wrap:
If div3 were to wrap under div2, that wouldn't be a row, that would be a grid, and flex items are confined to a straight, unbending row.
Put another way, you can't make a flex item wrap under another item in the same row.
As a result, white space created by items that aren't the tallest in the row is preserved in each column, creating unsightly gaps.
For your desired layout to work in row wrap, flex items would have to exit their row in order to close the gap – maybe with absolute positioning – which flexbox cannot do.
One way to align the items would be to wrap div2 and div3 in their own container. This new container would be a sibling to div1. It can then become a nested flex container with flex-direction: column. Now the gaps are gone and layout looks right.
Except, in this particular case, you need the order property to work (meaning all items must have the same parent), so a nested flex container is out of the question.
What may work is column wrap instead of row wrap:
/*************** MOBILE *************/
.container {
display: flex;
flex-direction: column;
height: 200px; /* necessary so items know where to wrap */
}
div.orange {
background-color: orange;
}
div.blue {
order: -1;
background-color: aqua;
}
div.green {
background-color: lightgreen;
}
.container > div {
width: 100%;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
/***************************/
#media screen and (min-width: 800px) {
.container {
flex-wrap: wrap;
}
div.orange {
flex-basis: 100%;
width: 50%;
}
div.blue {
flex-basis: 50%;
width: 50%;
order: 0;
}
div.green {
flex-basis: 50%;
width: 50%;
}
}
<div class="container">
<div class="orange">1</div>
<div class="blue">2</div>
<div class="green">3</div>
</div>
jsFiddle
Here are two other options:
Desandro Masonry
Masonry is a JavaScript grid layout library. It
works by placing elements in optimal position based on available
vertical space, sort of like a mason fitting stones in a wall.
source: http://masonry.desandro.com/
CSS Grid Layout Module Level 1
This CSS module defines a two-dimensional grid-based layout system, optimized for user interface design. In the grid layout model, the children of a grid container can be positioned into arbitrary slots in a predefined flexible or fixed-size layout grid.
source: https://drafts.csswg.org/css-grid/
Related post: Is it possible for flex items to align tightly to the items above them?

Resources