This problem can be solved in a couple of ways, one way – with caveats – using CSS (with either CSS flex-box or Grid layouts) and another with JavaScript/jQuery.
First, with CSS flexbox:
/* we use flexbox layout on the element which
contains the elements you wish to rearrange,
which causes them to become flex-items, and
this allows us to use the 'order' property
to visually arrange them: */
#main {
display: flex;
flex-direction: column;
}
/* here we select the elements and use the
'order' property with a numerical value
to place them in the correct order within
their parent element: */
#header {
order: 1;
}
#main-top {
order: 2;
}
#main-bottom {
order: 3;
}
#footer {
order: 4;
}
<div id='main'>
<div id='main-top'>Main Top</div>
<div id='main-bottom'>Main Bottom</div>
<div id='header'>Header</div>
<div id='footer'>Footer</div>
</div>
and, with CSS Grid:
/* we use grid layout on the element which
contains the elements you wish to rearrange,
which causes them to become grid-items, and
this allows us to use the 'order' property
to visually arrange them: */
#main {
display: grid;
grid-auto-flow: row;
}
/* here we select the elements and use the
'order' property with a numerical value
to place them in the correct order within
their parent element: */
#header {
order: 1;
}
#main-top {
order: 2;
}
#main-bottom {
order: 3;
}
#footer {
order: 4;
}
<div id='main'>
<div id='main-top'>Main Top</div>
<div id='main-bottom'>Main Bottom</div>
<div id='header'>Header</div>
<div id='footer'>Footer</div>
</div>
There's a third CSS approach, again using CSS Grid layout, but taking advantage of the grid-template-areas
and grid-area
properties:
/* we use flexbox layout on the element which
contains the elements you wish to rearrange,
which causes them to become flex-items, and
this allows us to use the 'order' property
to visually arrange them: */
#main {
display: grid;
/* here we name several grid areas; each quoted string
names the areas in that row, here we have four named
rows and each row has only one column: */
grid-template-areas:
"header"
"main-top"
"main-bottom"
"footer";
}
/* here we select the elements and use the
'grid-area' property to place them each
in the correct grid-area: */
#header {
grid-area: header;
}
#main-top {
grid-area: main-top;
}
#main-bottom {
grid-area: main-bottom;
}
#footer {
grid-area: footer;
}
<div id='main'>
<div id='main-top'>Main Top</div>
<div id='main-bottom'>Main Bottom</div>
<div id='header'>Header</div>
<div id='footer'>Footer</div>
</div>
The caveat of these approaches is that they affect only the visual presentation; the DOM is untouched and the positioned elements – whether using order
or grid-area
– remain in their original order for those users using alternative means of consumption (such as screen-readers).
Using native JavaScript, which does modify the DOM order:
// we retrieve, and cache, the <div id="header"> element,
// and then its parentNode:
const header = document.getElementById('header'),
parent = header.parentNode;
// here we use the parentNode.insertBefore() method to
// place the 'header' before the 'parent' Node's
// first-child:
parent.insertBefore(header, parent.firstChild);
#main-top,
#main-bottom {
display: none;
}
#header+#main-top,
#header+#main-top+#main-bottom {
display: block;
}
<div id='main'>
<div id='main-top'>Main Top</div>
<div id='main-bottom'>Main Bottom</div>
<div id='header'>Header</div>
<div id='footer'>Footer</div>
</div>
This is functionally equivalent to your request, however your question specifically asks about:
- moving the
#main-top
element after the #header
element, and
- moving the
#main-bottom
element before the #footer
element.
With this in mind, if you really wish to move two elements instead of just the one, then the following should address your need in relation to the elements you wish to position alongside:
// retrieving and caching all elements using destructuring assigment:
const [parent, mainTop, mainBottom, header, footer] = document.querySelectorAll('div');
parent.insertBefore(mainTop, header.nextSibling);
parent.insertBefore(mainBottom, footer);
#main-top,
#main-bottom {
display: none;
}
#header+#main-top,
#header+#main-top+#main-bottom {
display: block;
}
<div id='main'>
<div id='main-top'>Main Top</div>
<div id='main-bottom'>Main Bottom</div>
<div id='header'>Header</div>
<div id='footer'>Footer</div>
</div>
Finally, of course, using jQuery if you wish to do so:
$('#header').after($('#main-top'));
$('#footer').before($('#footer'));
#main-top,
#main-bottom {
display: none;
}
#header+#main-top,
#header+#main-top+#main-bottom {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='main'>
<div id='main-top'>Main Top</div>
<div id='main-bottom'>Main Bottom</div>
<div id='header'>Header</div>
<div id='footer'>Footer</div>
</div>