My wife works on a web project in Norway. As it is typical these days, functionality gets more weight than design when displaying web pages on mobile devices. Especially after Google’s decisions to explicitly require responsiveness. [Which was in my opinion mostly driven by their own interests to promote Android driven devices and their own development tools. And then maybe by general market and selling requirements. But this is a different story… ]
IT and communication in Norway is all about smart phones and tablets. So, of course, our Norwegian customer wanted to get some “responsive design”. OK … Although not really interested, I do take some challenges when my wife asks me for assistance …
As I am getting pretty IT-conservative with growing age my starting point with “responsiveness” was a fluid layout combined with “@media screen” CSS decisions – and a reluctance to use Javascript [JS] and jQuery. (This reluctance, of course, reflects the nagging question: What do we do when a customer has deactivated JS?)
My opinion was: In a certain range of browser window width – or more generally viewport width – the fluidity of the web design should predominantly govern the responsive reaction to a width change or a small target screen. I regard such a careful JS-free approach to responsive web design as reasonable – it helps already with different browser sizes on standard desktop screens – completely independent of mobile devices.
More extreme measures as removing visible parts of the layout or rearranging the positions, sizes and vertical order of whole HTML DIV container blocks would in this approach only be involved below certain viewport width thresholds via “@media” decisions. All in all, no big deal, I thought …. (In the first articles of this series we do not look at more detailed things as image resizing or font size adaptions).
What I underestimated is the fact that “old fashioned” fluid layouts may require a certain HTML tag order when we define its multiple columns”. However, in a responsive design approach you may eventually stumble across situations where the natural DIV element order you are used to is NOT suitable below some viewport width limits – i.e. when you want to rearrange the position and size of these DIV containers in a certain way. It took me some time to realize that there was a kind of contradiction between fluidity and responsiveness.
At this point I felt tempted again to use jQuery to freely rearrange the order of nodes of container DIVs in the HTML node tree or to use CSS flex boxes. However, flexboxes are not really standardized yet – and once you start with jQuery and responsiveness you must take care to align your Javascript conditions with the CSS @media decisions in a precise and non contradictory way. In addition I thought it better to understand JS free options and possibilities first before implementing some parametrizable JS machinery.
Whilst experimenting I all the time had the feeling that with some dirty CSS trick one should be able to gain control over the DIV element order – without destroying the optical appearance – and become able to adapt it to any predefined responsive reordering requirements for small viewport widths. I needed some hours to figure out how I could overcome at least some of the problems. I had some fun with this and maybe others find tweaking CSS interesting, too.
In this first article of a series I like to describe a standard flexible 3 column fluid layout and the CSS directives behind it. In a second article I shall add some elementary responsiveness and deduct the problem of the DIV order. Then I shall describe some CSS “trick” which will enable us to (manually) change or adapt the required DIV order in the HTML code without loosing fluidity and without loosing the optical appearance of the inital horizontal sequence of our columns. This will help us to achieve the pursued responsive and
vertical container rearrangement with a few very simple CSS changes below some width threshold of the viewport.
In other words: Our first objective is find CSS manipulations which enable us to code any required DIV order for the column grid in HTML such
- that we optically do not change the column order or layout,
- that we do not disturb the ability of our 3 column layout to adapt optically to the height of its largest (= highest) column,
- that we can produce any predefined vertical content order of the column contents during a responsive reaction to view port width changes
- and that we at the same time can realize responsiveness easily by basically changing some float or position statements in @media screen based decisions in our CSS file.
Note that the second point may impose additional difficulties!
Note further that even if we fulfilled our list of objectives we still would have to plan ahead our HTML code and its DIV order for the specific responsive layout we want to achieve. But being able to choose the required DIV order for our HTML code would already gives us the chance to create templates for different responsive reactions required by customers. In combination e.g. with PHP such templates would give us the freedom to switch any horizontal column order into any desired vertical order during responsive reactions – without involving JS.
Nevertheless, later in this series I want to show how we can use Javascript/jQuery to enforce a predefined responsive vertical order of the column contents from a basic 3-column layout we develop in the next two articles. But, at least I myself need some learning curve to get there.
We shall concentrate our efforts on a fluid 3-column layout.
Study example: A fluid/fixed layout with 3 columns
Below, we construct a simple example of a 3 column layout, where you arrange
- a kind of navigation column on the left web page side,
- a main contents area in the middle
- and some column like area, e.g. for teaser elements, on the right page side.
Your fluidity objectives for a certain range of viewport widths would e.g. be
- that the left column keeps up a fixed width,
- whereas the middle main column changes its width adaptively with the viewport width
- and that the right column adapts its width to a defined percentage of the viewport width.
Thus we have defined a combination of fixed/fluid elements which provides a good insight into the basic CSS techniques. Generalizations will be obvious. You require of course that the width adaption happens automatically whilst resizing the viewport width in the given range. All this should be governed by CSS statements, only. Imagine now, that you want to tweak things a bit further in the form that the longest of the three defined “columns” determines the height of the whole page and the apparent “visible” height of the other (not so high) columns, too. Above a responsiveness width threshold at least.
Typically, the main content column may become largest in size (height), whereas e.g. the left column may contain only some few menu points. Nevertheless, you want to create an appearance as if all 3 columns got the same height as the largest one with respect to height – and this should work automatically even if you changed the text and image contents of the content column significantly (e.g. via an CMS). This means that in case you add many lines of new text to the middle column the whole page and its right and left areas should somehow
optically adapt in height.
And: Everything should work analogously in case either the left or right column becomes the largest in height on some pages.
There is of course a simple, “conservative” CSS solution for this problem which I shall discuss a bit below. However, the requirement of fluidity in width in combination with the requirement of extending the web pages height automatically will unavoidably lead to a certain order of the HTML DIV containers.
Some details of our conventional fluid approach
The HTML file is pretty simple:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>fluid standard</title> <link href="css/fluid_standard.css" rel="stylesheet"> </head> <body> <!-- 3 spalten layout --> <div id="all"> <div id="head"> <div id="hmen_knapp_cont" class="hmen_knapp_cont"> <a id="hmen_knapp"></a> </div> <div id="hmen_cont" class="hmen_cont"> <ul> <li><div class="hmen_pkt">h-menu 1</div></li> <li><div class="hmen_pkt">h-menu 2</div></li> <li><div class="hmen_pkt">h-menu 3</div></li> <li><div class="hmen_pkt">h-menu 4</div></li> <li><div class="hmen_pkt">h-menu 5</div></li> <li><div class="hmen_pkt"><a id="but2" href="#"></a></div></li> <li class="floatstop"></li> </ul> </div> </div> <div id="outer_cont"> <div id="nav_left_bg"></div> <div id="right_bg"></div> <div id="info_bg"></div> <div id="float_cont"> <div id="left_nav"> <p><a href="#">sub menu point 1</a></p> <p><a href="#">sub menu point 2</a></p> <p><a href="#">sub menu point 3</a></p> </div> <div id="right"> <div id="right_inner"> <p>Some stupid text - just to show something</p> <p> </p> <p>Some stupid text - just to show something</p> </div> </div> <div id="main_cont"> <div id="info"> <p>Lorem ipsum .... </p> <p> </p> <p>Lorem ipsum ....</p> <p> </p> <p>This is the end, my friend<br> </p> </div> </div> <p class="floatstop"> </p> </div> </div> </div> </body> </html>
The central DIV that shall contain most of the information of our web page is “div#info”. Why we have placed it inside an extra container “div#main_cont” may become clear in the next article. In the pure fluid approach it would not really have been necessary. You clearly detect the “left” sided DIV for e.g. a column with navigation points and the “right” sided DIV, which may contain something else. Note that there are “background” DIVs (with an ID like “…_bg”) that provide the impression of colored columns with exactly the length of the “outer_cont” DIV.
To understand the fluid behavior let us have a look at the CSS :
@CHARSET "UTF-8"; html { font-size:10px; } body { margin-left:0; margin-right:0; } p { font-size: 1.6rem; line-height: 1.4; margin: 0; } div#all { position:relative; width:100%; background-color: #000; } /* The header region */ div#head { position:relative; width:100%; background-color: #FF0; min-height: 3.0rem; } /* The main contents container */ div#outer_cont { position:relative; width:100%; background-color: #FF0; min-height: 10.0rem; } /* background elements for all columns */ div#left_nav, div#nav_left_bg { width: 14.2rem; } div#right, div#right_bg { width: 26%; } div#nav_left_bg, div#right_bg, div#info_bg { top:0; bottom:0; } div#nav_left_bg { position: absolute; left:0; background-color: #DDD; z-index:1; border: 1px solid #F00; } div#right_bg { position: absolute; right: 0; background-color: #FEEEBB; z-index:1; border: 0px solid #F00; } /* The float container and its basic elements */ div#float_cont { position:relative; width: 100%; /*background-color: #99e;*/ border: 0px solid #FF0000; z-index:5; } /* left column */ div#left_nav { position:relative; float:left; border: 0px solid #009900; padding-left:8px; /*margin-left: -320px;*/ z-index:2; } /* middle column */ div#main_cont { position: relative; margin: 0 27% 0 15rem; /*width:74%;*/ /*min-width: 462px;*/ /*background-color: #fff;*/ border: 0px solid #009900; z-index:2; } div#info { position: relative; /*margin: 0 2px 0 160px;*/ width:auto; background-color: #0f0; padding-left:8px; /*height:200px;*/ } /* right column */ div#right { position:relative; float:right; /*min-width: 15.2rem;*/ width: 26%; /*background-color: #00f;*/ border: 0px solid #009900; } div#right_inner { width:auto; padding: 0 0.8rem 0 0.8rem; } /* Other elements */ p.floatstop { clear:both; height:0; margin:0; line-height:0; padding: 0; font-size: 0; } /* contents of the upper horozontal menu */ div.hmen_cont { display: block; position: relative; min-height: 3.0rem; width: 100%; background-color: #ccc; } div.hmen_cont ul { position: relative; list-style-type: none; width: 100%; margin: 0; padding: 0; background-color: #00EE00; } div.hmen_cont ul li { float: left; padding: 2px 40px 2px 40px; border-left: #ffffff 1px solid; border-right: #a90000 1px solid; min-height: 2.0rem; font-size: 1.6rem; } div.hmen_cont ul li.floatstop { float:none; clear:both; min-height:0; margin:0; line-height:0; padding: 0; font-size: 0; } div#hmen_knapp_cont { display: none; position: absolute; right:0; top:10px; width: 50%; height: 2.4rem; border: 1px #A90000 solid; } a#hmen_knapp { display: block; width: 100%; height: 100%; background-color: #009999; } a#but2 { display: block; width:20px; height: 20px; background-color: #eee; }
Note that all of the DIVs
- div#all,
- div#outer_cont,
- div#float_cont,
- div#main_cont,
- div#info
got a “position: relative;”, but none got any defined height. Actually, as we stop the floating at the end of “div#float_cont” via an artificial p-element, the “div#float_cont” container responds dynamically to the maximum height of one of its inner floated elements or relatively positioned elements and imposes its own height on the surrounding DIV container “div#outer_cont”. The resulting height of this container can be used to indirectly define the height of absolutely positioned background
DIV elements which “simulate” a colored virtual height of all columns – at least as long as we do not rearrange DIV containers due to responsiveness.
Whereas the width adaptivity of the right column is understandable from its CSS width statement, the adaptivity of the “div#main_cont” results from its relative positioning with left and right margins on top of the vertical level which is automatically defined by the floated elements inside the “div#float_cont”. The margins guarantee that we leave enough space on the left and right side not to cover the floated columns contents there.
This fluid design is quite adaptive already – see the following images taken with Firefox.
and
But, of course, the column adaptivity will not be of much use on small smart phone displays: First there comes an end to shrinking as soon as some words get too large to fit into their column width. And on a smart phone we would appreciate very much to use all of the available width for the text in the main column. We shall look at related measures in the next article.
For now, I want you to realize that the above fluid design relies totally on the order of the DIVs inside the “div#float_cont”. See, what happens, if we changed the order of the DIVs to
<div id="float_cont"> <div id="main_cont"> ... </div> <div id="left_nav">..</div> <div id="right"> ... </div> <p class="floatstop"> </p> </div>
Then the first DIV spans a region with height that defines the position of the layer for the floated elements – namely below the “div#main_cont”. So our nice fluid design would be doomed to fail in case we needed some other DIV order.
Outlook on forthcoming posts
In the next post
Responsive fluid multi-column layouts – the DIV order problem – II
we introduce some elementary responsiveness and discuss, why the defined DIV order in the HTML code may conflict with a responsive rearrangement. We shall present a responsive solution where some few CSS tricks allow us to (manually) change the DIV order in the HTML code in whatever required way to maintain an easy realization of responsiveness. See also
Responsive fluid multi-column layouts – the DIV order problem – III
for a full discussion.
In the articles
Responsive fluid multi-column layouts – with a responsive horizontal menu – IV
and
Responsive fluid multi-column layouts – with a responsive horizontal menu – V
we discuss menu adaptions without and with Javascript.
Our final objective is to use JS to switch the DIV tag order in the HTML node tree for
a basic 3 column layout in accordance with the required DIV order for a defined responsiveness – in a parametrized way.