34

Given that the HTML

<div>
   <div id="content1"> content 1</div>
   <div id="content2"> content 2</div>
   <div id="content3"> content 3</div>
</div>

render as

content 1
content 2
content 3

My question:

Is there a way to render it as below by using CSS only without changing the HTML part.

content 1
content 3
content 2
Ray Lu
  • 26,208
  • 12
  • 60
  • 59
  • 4
    Your question is very good because this is useful for SEO optimizations in order to bring the nav-divs below the content. You should expain why do you want this in your question body - so people will understand its use. – sorin Jan 24 '10 at 08:51
  • 1
    The reason I'm interested in this is merely to separate layout from backend coding. Our HTML is dynamically generated by the backend. It would be great if our backend engineer didn't need to know anything about the layout, and the frontend engineer could re-order everything as he/she sees fit. – speedplane Jul 15 '14 at 11:02

9 Answers9

29

This can be done in browsers that support the CSS3 flexbox concept, particularly the property flexbox-order.

See here

However, support for this is only in current versions of most browsers still.

Edit Time moves on and the flexbox support improves..

Luke H
  • 3,125
  • 27
  • 31
  • I did not know about this yet (pretty late to the party it seems ;)). I remember talking to some colleagues about how ideally CSS'd have some sort of hbox and vbox implementations. It seems like it does now :). Too bad it is so badly supported. – Mosselman Jan 24 '14 at 16:15
25

This works for me: http://tanalin.com/en/articles/css-block-order/

Example from this page:

HTML

<div id="example">
  <div id="block-1">First</div>
  <div id="block-2">Second</div>
  <div id="block-3">Third</div>
</div>

CSS

#example {display: table; width: 100%; }

#block-1 {display: table-footer-group; } /* Will be displayed at the bottom of the pseudo-table */
#block-2 {display: table-row-group;    } /* Will be displayed in the middle */
#block-3 {display: table-header-group; } /* Will be displayed at the top */

As stated there, this should work in most browsers. Check link for more info.

Marcin Robaszyński
  • 772
  • 1
  • 11
  • 21
5

It might not exactly match what you're after, but take a look at this question:
CSS positioning div above another div when not in that order in the HTML

Basically, you'd have to use Javascript for it to be reliable in any way.

Community
  • 1
  • 1
nickf
  • 537,072
  • 198
  • 649
  • 721
3

This is one of the classic use-cases for absolute positioning--to change rendering from source order. You need to know the dimensions of the divs to be able to do this reliably however, and if you don't javascript is your only recourse.

  • 1
    Absolute positioning is really not a good fit for this, since it makes for hard-to-maintain CSS even in the unlikely event that you *do* know the dimensions. – SamB Feb 09 '14 at 21:12
3

I was messing around in Firefox 3 with Firebug, and came up with the following:

<div>
  <div id="content_1" style="height: 40px; width: 40px; background-color: rgb(255, 0, 0); margin-bottom: 40px;">1</div>
  <div id="content_2" style="width: 40px; height: 40px; background-color: rgb(0, 255, 0); float: left;">2</div>
  <div id="content_3" style="width: 40px; height: 40px; background-color: rgb(0, 0, 255); margin-top: -40px;">3</div>
</div>

It's not perfect, since you need to know the heights of each container, and apply that height value to the negative top margin of the last element, and the bottom margin of the first element.

Hope it helps, nd

ndorfin
  • 476
  • 2
  • 13
1

I got it to work by doing this:

#content2 { position:relative;top:15px; }
#content3 { position:relative; top:-17px; }

but keep in mind that this will not work for you as soon as you have dynamic content. The reason I posted this example is that without knowing more specific things about your content I cannot give a better answer. However this approach ought to point you in the right direction as to using relative positioning.

Andrew Hare
  • 344,730
  • 71
  • 640
  • 635
0

One word answer: nope. Look into XSLT (XML Stylesheet Language Transforms), which is a language specifically geared towards manipulating XML.

Samir Talwar
  • 14,220
  • 3
  • 41
  • 65
  • 2
    XSLT would be massively over-the-top for this simple DOM manipulation task... – nickf Mar 08 '09 at 23:20
  • True, but it would also be the best solution. All others require client-side scripting, which won't work in all cases. – Samir Talwar Mar 09 '09 at 19:37
  • I don't quite understand the negative score of this comment. Yes, the question was about CSS, but Samir's answer provides the only reliable way to achieve the intended effect on every browser, even with Javascript disabled. – jcayzac Aug 04 '10 at 01:53
0

If you know the height of each element then it is a simple case of vertical relative positioning to swap around the orders. If you don't know the heights then you either have to give them heights and allow the divs to get scroll bars if there is any overflow or calculate it all with JavaScript and add the relative positioning on-the-fly.

Matthew James Taylor
  • 4,806
  • 5
  • 29
  • 33
-3

with jquery you can simply do:

$('#content2').insertAfter($('#content3'));

I don't think there's a way to do it with CSS, except to force fixed positioning of each of the divs and stack them that way.

meem
  • 1