Chaning the order of appearance of elements in a responsive webdesign layout

Sometimes you wish to change the ordering of elements when an website get's resized, but alas native css doesn't support "moving" elements from one position to another.

That is why I've written my own library to help with that so that even if elements have to appear at an totally different order that is totally managable.

With this library it's not even important in which order your html div's are placed within the document, because they get recalculated at every screen resize to their approriate positions.

Now, because what I'm trying to explain is pretty abstract below the visualisation of what I mean:

Say that this is your website. The natural flow is that the red and blue block are aligned left and the gray blok right.
What happens if you have a responsive layout, the gray block has to appear or as whole above the red or below the red. You cannot extract one block and place that where you wish to place it from the gray block.

This is an example of the desired result with a responsive view on mobile. You can see that the first block fromt the gray set has been placed under the red and the rest at the bottom.
Doing this in pure css is tricky if not impossible.

That is why I've written my own library to help with the sorting. Below my library(which is dependant on jQuery. If you need a library that is not dependant on library that is not jQuery in dependant contact me:
To minify this code feel free to use: http://www.minifyjavascript.com/, but do please keep the comment with the copyright notice in place.


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/* Copyright 2014 Michael Dibbets, all rights reserved. 
    This library is free to use for non commercial use, 
    if you leave a comment below the blog post at 
    http://all-purpose-programming.blogspot.nl/2014/02/chaning-order-of-appearance-of-elements.html
    where you are implementing this libary.
    For commercial use contact me to come to an licensing agreement.
    mdibbets [at] outlook [dot] com
    My prices are fair and reasonable.
    ususage of this script without notification of the author 
    in the before mentioned ways is not permitted.
*/
function JX_responsive_sort(precursor)
    {
    if(typeof precursor == 'undefined')
        {
        precursor = 'conditional';
        }
    // our sorting array
    var orderofthings = new Array();
    // window width 
    var windowwidth = $(window).innerWidth();
    // get all classes named conditional
    jQuery('.'+precursor).each(function()
       {
       // get all classes of the conditional element
       var classList = jQuery(this).attr('class').split(/\s+/);
       // loop through all classes of the current element
       // backwards compatible... of course
       for(c=0;c<classList.length;c++)
          {
          item=classList[c];
          // no need for this one bub
          if(item != precursor)
              {
              if(item.substring(0,11) == precursor)
                  {
                  // sanitise the item
                  item = item.substring(12,item.length);
                  // from which screenwidth is this rule active?
                  var startwidth = parseInt(item.substring(0,item.indexOf('_'))); 
                  // to which screenwidth is this rule active?
                  var endwidth = parseInt(item.substring(item.indexOf('_')+1,item.indexOf('_',item.indexOf('_')+1)));
                  if(windowwidth >= startwidth && windowwidth <= endwidth)
                      {
                      // remove the widths so all that remains are commands
                      item = item.substring(item.indexOf('_',item.indexOf('_')+1)+1,item.length);    
                      // split on hypens, since they are the commands separators
                      var commands = item.split(/-/);
                      for(i=0;i<commands.length;i++)
                          {
                          // get the instructions
                          var instructions = commands[i].split('_');
                          // to know the command remove the first element
                          var command = instructions.shift();
                          // command order - Instruction to display the elements in the desired order.
                          // This is a top level ordering of parent elements in the conditional_mainwrap 
                          // In order to change the ordering of child elements you'll have to "pop" them
                          // a level higher.
                          // allowed variables:
                          // 0 : order number priority. Try not to cause conflicts
                          if(command == 'order')
                              {
                              // add the this element at the desired position into the order of things.
                              orderofthings.push({order: instructions[0] , theobj : this });
                              }
                          // command pop - Instruction to remove the current element from its parent,
                          // and attach it to the parents parent.
                          if(command == 'pop')
                              {
                              // an item that switches positions needs an "returning" wrapper.
                              // that is the first parent.
                              // Then we have the normal container that needs to be escaped.
                              // Then we have parent where we wish to attach it to.
                              if(jQuery(this).parent().attr('id') == precursor + '_wrap_' + jQuery(this).attr('id'))
                                  {
                                  jQuery(this).appendTo($(this).parent().parent().parent());
                                  }
                              }
                          // command repop - Instruction to return the current element to it's designated position
                          // This is why a poppable element needs a wrapper, so we know where to return it.
                          if(command == 'repop')
                               {
                               jQuery(this).appendTo('#conditional_wrap_'+jQuery(this).attr('id'));
                               }
                          }
                      }
                  }
              }              
          }
       });
    // set a simple variable to get the jQuery object of the parent wrap
    parentkeeper = jQuery('.'+precursor+'_mainwrap');
    // sort the arrays so the orderofthings get's it's sorting from the ORDER command.
    orderofthings = orderofthings.sort(keysrt('order',false));
    for(c=0;c<orderofthings.length;c++)
        {
        if(typeof orderofthings[c] != 'undefined')
            {
            jQuery(orderofthings[c]['theobj']).appendTo(parentkeeper);
            }
        }
    }
jQuery(document).ready(function(){
JX_responsive_sort();
});
jQuery( window ).resize(function() 
    {
    JX_responsive_sort();
    });
function keysrt(key,desc) {
  return function(a,b){
   return desc ? ~~(a[key] < b[key]) : ~~(a[key] > b[key]);
  }
}

The string 'conditional' is optional, but if it's not defined it will revert to 'conditional'.

This css selector has to be used in all elements you wish to manipulate. Otherwise the library won't recognise your elements you wish to sort.

Some example HTML code:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
<HTML>
<HEAD>
<STYLE type="text/css">
#consol {
    font-family:courier;
    color:lime;
    font-weight:400;
    background-color:black;
    border:1px inset gray;
    padding-left:10px;

}
span
    {
        display:inline-block;
        margin: 50px 50px;
        font-size:4em;
        font-weight:800;
        text-shadow: 3px 3px 10px gray;
        font-family:sans-serif;
    }

#red {
    background-color:red;
    border: 1px solid brown;
    display:inline-block;
}
#yellow1, #yellow2
    {
    background-color:yellow;
    border: 1px solid lightbrown;
    }
#black
    {
    display:inline-block;
    border:1px solid black;
    background-color:gray;
    }
#green1, #green2, #green3
    {
    display:inline-block;
    background-color:lime;
    border:1px solid darkgreen;
    }
#blue
    {
    display:inline-block;
    border:1px solid darkblue;
    background-color:lightblue;
    }
#purple1, #purple2, #purple3
    {
    display:block;
    border: 1px solid darkpurple;
    background-color:purple;
    }
/* desktops and big resolution screens that can handle the normal layout */
@media only screen and (min-width: 875px) {
#red {
    width:600px;
}

#yellow1, #yellow2
    {
    width:250px;
    height:300px;
    margin:20px;
    float:left;
    }
#black
    {
    float:right;
    }
#green1, #green2, #green3
    {
    clear:both;
    float:right;
    width:200px;
    height:150px;
    margin:20px;
    }
#blue
    {
    width:600px;
    }
#purple1, #purple2, #purple3
    {
    width:150px;
    margin:25px;
    float:left;
    height:200px;
    }
}
/* small screens */
@media only screen and (max-width: 875px) {
#red {
    width:100%;
}
#yellow1, #yellow2
    {
    width:90%;
    margin:5%;
    float:left;
    }
#black
    {
    width:100%;
    }
#green1, #green2, #green3
    {
    width:90%;
    margin:5%;
    }
#blue
    {
    width:100%;
    }
#purple1, #purple2, #purple3
    {
   width:90%;
    margin:5%;
    }
}
</STYLE>
</HEAD>
<BODY>
<div class="conditional conditional_mainwrap">
  <div id="black" class="conditional conditional_0_875_order_4 conditional_875_3000_order_1">
    <div id="conditional_wrap_green1" class="conditional">
        <div id="green1" class="conditional conditional_0_875_pop-order_2 conditional_875_3000_repop whoa">
            <span>1</span>
        </div>
    </div>
    <div id="green2">
        <span>2</span>
    </div>
    <div id="green3">
        <span>3</span>
    </div>
</div>
<div id="red" class="conditional conditional_0_875_order_1 conditional_875_3000_order_2">
    <div id="yellow1">
        <span>1</span>
    </div>
    <div id="yellow2">
        <span>2</span>
    </div>
</div>

<div id="blue" class="conditional conditional_0_875_order_3 conditional_875_3000_order_3">
    <div id="purple1">
        <span>1</span>
    </div>
    <div id="purple2">
        <span>2</span>
    </div>
    <div id="purple3">
        <span>3</span>
    </div>
</div>
</div>

Now to explain how it works if you can't puzzle it from the example code ;-)

Every class that is affected or has a command for the library needs to have the CSS class that you defined in the precursor.
Then, any commnd for the library to be processed needs to be preceded by the precursor and then an underscore '_'
Then you define the minimal screen width that this command has to be executed.
Then another underscore. Then the maximal screen width where this rule applies to.

Usually these will follow the same max and min widths you have defined in your responsive css selectors.

The library will skip rules that do not fit within the current screen dimensions.

The following commands can be used with this library:

order _ [INT]

The order commands takes one parameter and that is the sorting order that applies to this element.
Does it need to appear as first, as second or as third, etc..
This is defined as an integer value(1,2,3,4,5,6).

pop

You can "pop" an element out of it's container(in the graphic example the gray box) with this command.
To use this command you need to give the element you're popping an unique ID.
Also the element needs to be wrapped with a div with the following ID: precursor_wrap_[ID of the element you wish to pop].
This is to make sure that the element can be returned if it needs to be.
NOTE: do not execute this at top level elements ;-) just saying...

repop

This command is used to "undo" the above command pop


String commands together
Sometimes you wish to use multiple commands in order to get your object at the desired position.
To make a queue of commands concatenate them with a hypen '-' so that you do not need to use multiple classes to do multiple commands.

To first pop and then sort an element use the following string:

conditional_0_875_pop-order_2

What does this do?
conditional : precursor, this tells that this in an instructing css class
0: Is the current screen width bigger or equal then 0 pixels?
875: Is the current screen width smaller or equal then 875 pixels?

if above statements are both true then:

look for commands, command found:
pop: First pop the element out of the current container
First command executed, check if there is a next command:
order: Tell the sorter to sort the current element at integer provided
2: Priority of sorting. Will be shown as second element if there is an element with priority 1
no further commands, continue loop

Another note, and is possibly the most important one... there needs to be a 'mainwrap' where all manipulations happen.

css class: precursor_mainwrap

This is where all the sorted elements will be put into.

Now, to see it in action:

http://jsfiddle.net/mdibbets/5r5A5/

Full screen:

http://jsfiddle.net/mdibbets/5r5A5/embedded/result/

If you have any (intelligent) questions, please don't hesistate to ask me, but kinda same rules as on stackoverflow apply on asking me questions...

If you cannot understand this code from provided code and jsfiddle, this is not for you, go learn stuff then return.;-)

Comments