I am trying to keep a seo friendly and semantic structure for my DOM, without repeating whole elements to display them in various positions.
My layout is based on
In general, you can't do this with Flexbox alone, though there might be a compromise based on each given case.
With Flexbox alone, using fixed height, you can accomplish this
* {
box-sizing: border-box;
}
body, html {
margin: 0;
}
.flex {
width: 90%;
margin: 5vh auto;
height: 90vh;
background: rgba(0, 0, 0, 0.05);
display: flex;
flex-flow: column wrap;
}
.flex div {
flex: 1;
width: 50%;
}
.flex div:nth-child(2) {
order: -1;
}
.flex::before {
content: '';
height: 100%;
}
@media (max-width:768px) {
.flex div {
width: auto;
}
.flex::before {
display: none;
}
.flex div:nth-child(2) {
order: 0;
}
}
/* styling */
.flex-child {
color: white;
font-size: 2em;
font-weight: bold;
}
.flex-child:nth-child(1) {
background: #e6007e;
}
.flex-child:nth-child(2) {
background: #f4997c;
}
.flex-child:nth-child(3) {
background: #86c06b;
}
Top/Right
Center/Left
Bottom/Right
In this case, where no fixed height is allowed, you can combine Flexbox and float.
By set up it for mobile using Flexbox where you add the center item first in the markup and then, with order, move it between the top and bottom.
With a media query you then simply make the flex container a block element and use float to position the left to the left and the right to the right.
* {
box-sizing: border-box;
}
body, html {
margin: 0;
}
.flex {
max-width: 1024px;
width: 90%;
margin: 5vh auto;
height: 90vh;
background: rgba(0, 0, 0, 0.05);
display: flex;
flex-direction: column;
}
.flex-child {
color: white;
font-size: 2em;
font-weight: bold;
padding: 5%;
flex-basis: 33.333%;
display: flex;
align-items: center;
}
.flex-child:nth-child(1) {
background: #e6007e;
order: 1;
}
.flex-child:nth-child(2) {
background: #f4997c;
}
.flex-child:nth-child(3) {
background: #86c06b;
order: 2;
}
@media (min-width: 768px) {
.flex {
display: block;
}
.flex-child {
width: 50%;
}
.flex-child:nth-child(1) {
float: left;
height: 100%;
}
.flex-child:nth-child(2),
.flex-child:nth-child(3) {
float: right;
height: 50%;
}
}
Center/Left
Top/Right
Bottom/Right
Update
Here is another version combining Flexbox with position: absolute, which also vertically center the items in desktop mode
Updated, added a script to control so the absolute positioned element won't get bigger than the right items, and if so, adjust the flex containers height.
Note, the script is by no means optimized, it is only there to show how a fix in certain situations
(function() {
window.addEventListener("resize", resizeThrottler, false);
var fp = document.querySelector('.flex');
var fi = fp.querySelector('.flex-child:nth-child(1)');
var resizeTimeout;
function resizeThrottler() {
// ignore resize events as long as an actualResizeHandler execution is in the queue
if ( !resizeTimeout ) {
resizeTimeout = setTimeout(function() {
resizeTimeout = null;
actualResizeHandler();
// The actualResizeHandler will execute at a rate of 15fps
}, 66);
}
}
function actualResizeHandler() {
// handle the resize event
if (fp.offsetHeight <= fi.offsetHeight) {
fp.style.cssText = 'height: '+fi.offsetHeight+'px';
} else {
fp.style.cssText = 'height: auto';
}
}
window.addEventListener('load', function() {
actualResizeHandler();
})
}());
* {
box-sizing: border-box;
}
body, html {
margin: 0;
}
.flex {
position: relative;
max-width: 1024px;
width: 90%;
margin: 5vh auto;
height: 90vh;
background: rgba(0, 0, 0, 0.05);
display: flex;
flex-direction: column;
}
.flex-child {
color: white;
font-size: 2em;
font-weight: bold;
padding: 5%;
}
.flex-child:nth-child(1) {
order: 1;
}
.flex-child:nth-child(3) {
order: 2;
}
.flex-child:nth-child(1) div {
background: #e6007e;
}
.flex-child:nth-child(2) div {
background: #f4997c;
}
.flex-child:nth-child(3) div {
background: #86c06b;
}
@media (min-width: 768px) {
.flex {
justify-content: center;
}
.flex-child {
width: 50%;
}
.flex-child:nth-child(1) {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.flex-child:nth-child(n+2) {
margin-left: 50%;
}
}
Center/Left
with more
content
than any
of the
other items
other items
other items
other items
other items
Top/Right
with more
content
Bottom/Right
with more
With script one can also reorder/move items between elements.
Stack snippet
You can also combine this with a media query, and use it to do the actual re-order of the elements
$( document ).ready(function() {
$(window).resize(function() {
if ($( window ).width() < 600 ) {
$(".one").insertBefore("#b");
} else {
$(".one").insertBefore(".two");
}
});
});
.outer, #flex, #flex2 {
display: flex;
flex-direction: column;
}
#a {
order: 4;
background: #ccc;
}
#b {
order: 1;
background: #aaa;
}
#c {
order: 3;
background: #d33;
}
.one {
order: 2;
background: #aaa;
}
.two {
order: 5;
background: #aaa;
}
A
B
C
Show me 2nd
Show me 5th
Update 2 (answered at another question but later moved here)
If we talk about smaller items, like a header or smaller menus, one can do what many website platform providers like "squarespace", "weebly", "wordpress", etc does. Their templates holds different markup structures, where an item sometimes exist twice, one visible for desktop, another for mobile.
Also, being so small, there will be less to nothing when it comes to performance (and personally I don't see anymore issue with this than having duplicate CSS rules, one for each screen size, and happily do this instead of introducing script).
Fiddle demo
Stack snippet
.container {
display: flex;
}
.container > div {
width: 50%;
}
.container div:nth-child(-n+2) {
border: dashed;
padding: 10px;
}
.container > div:nth-child(1) {
display: none; /* hide outer "Flower" */
}
@media (max-width:768px) {
.container {
flex-direction: column;
}
.container div {
width: auto;
}
.container div:nth-child(1) {
display: block; /* show outer "Flower" */
}
.container div:nth-child(3) div:nth-child(1) {
display: none; /* hide inner "Flower" */
}
}
Flower
Tree
Flower
Bee