In the previous articles of this series
Responsive fluid multi-column layouts – the DIV order problem – I
Responsive fluid multi-column layouts – the DIV order problem – II
we discussed a problem that may arise when you want to make a fluid design responsive.
In order
- to both use a fluid design with multiple content columns in horizontal direction and
- and to control the vertical heights of optical background elements for the different columns
you need to encapsulate floated page elements in a container.
Such floated content elements could be a vertical navigation column, a main information block with text and a right column with teaser text elements. In your HTML code you would define and describe the tags of the floated container elements in just this natural sequence. The CSS properties of the containers require no special attention – everything is straightforward. However, the natural tag order may lead to conflicts when you want to reposition the column like page elements in a fluid and additionally responsive approach to our multi-column layout.
Typically, in a responsive approach you rearrange the content columns into a vertical order instead of the original horizontal sequence, because you want to make use of a maximum of the view port width for each of the information and navigation containers. For reasons of coding efficiency the vertical rearrangement of previously horizontally distributed containers should be achieved just by changing some CSS properties like “position”, “margin” or “float” when the view port gets smaller than some predefined values. Under normal circumstances you do NOT want to create major HTML block elements twice and switch them alternately on and off just to become responsive.
For getting the right vertical ordering effect you would e.g. make use of the automatic handling of floated elements by the browser for situations when the horizontal viewport space gets too small for displaying all floated elements in just one row. In such a situation, however, the last tag (of the sequence of floated elements) in the code represents the element which is moved downwards in the browser’s viewport first.
In the second article of this series we therefore discussed a special situation for which we required a specific vertical reordering of existing elements. We showed how we could re-nest and rearrange the DIV-container tags into the required code order – without changing the original optical and fluid layout. Of course we had to compensate by more complicated CSS definitions.
Among other things we used negative margin definitions to optically place floated elements where we needed them to be on the screen – despite an unusual tag position in the HTML code. With a bit of abstraction the discussed recipe will in general allow for any required tag order for the DIV-containers in the code. What we have achieved is that by using some compensating CSS tricks we can now choose a certain – unusual, but in a responsive context required – tag order in the HTML code without destroying the optical features and the fluidity of our multi-column page layout.
We have demonstrated how to handle a first responsive transition in viewport width by moving one of the columns downward and adapt our content areas in width – without loosing fluidity. In the last article we also discussed some additional, conventional measures to make the different content column blocks appear as separate optical elements floating above a common background (picture).
We have, however, not yet shown how to manage a second – and more
important – transition to a range of significant smaller view port widths. For small view port widths we would like to move our left sided vertical menu directly below the text area – an objective we had already defined in the first article and which will be met by the measures discussed in the present article.
We shall see in this article that our achievements now allow for almost trivial measures to gain the correct aspired responsiveness: You just need to change a few “float” and “margin” properties.
To make everything a bit more challenging we shall also show how one can add transparent background layers to each column of the original fluid layout and how we manage such transparency layers together with responsive width adaptions of the web page.
Extending the HTML code by tags for transparency layers
We firstly define DIV containers which serve us as transparent background stripes of all column elements of our fluid design. To be able to keep up the transparency during a later responsive element reordering we need to insert such background layer (DIV) elements
- into the defined outmost container “div#outer_cont” and the additionally introduced internally nested container “div#main_cont”,
- and as well as into each of the floated DIV-elements representing the text column blocks.
Due to some simple CSS rules already presented in the previous articles the absolutely positioned background layers will adapt automatically to the height of their encapsulating DIV containers (via “position: absolute; top:0; bottom:0;” settings).
The height of the encapsulating containers is in turn dynamically defined by the maximum height of their enclosed relatively positioned, but floated text containers – i.e. according to the available horizontal space, the text content length and the height of other enclosed inner elements.
The modified HTML code is here:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>fluid standard 2</title> <link href="css/fluid_standard2.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="bg_left0"></div> <div id="bg_right0"> <!-- do not remove ! --> <div id="bg_right_inner0"></div> </div> <div id="bg_info0"></div> <div id="float_cont"> <div id="main_cont"> <div id="bg_left1"></div> <div id="bg_info1"></div> <div id="info_cont"> <div id="float_info"> <div id="bg_info2"></div> <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> <div id="left_nav"> <div id="bg_left2"></div> <div id="left_inner"> <ul> <li><p><a href="#">sub menu point 1</a></p></li> <li><p><a href="#">sub menu point 2</a></p></li> <li><p><a href="#">sub menu point 3</a></p></li> </ul> </div> </div> <p class="floatstop"> </p> </div> </div> <div id="right"> <div id="bg_right2"></div> <div id="right_inner"> <p>Some stupid text - just to show something</p> <p> </p> <p>Some stupid text - just to show something</p> <p>Some stupid text - just to show something</p> </div> </div> <p class="floatstop"> </p> </div> </div> </div> </body> </html>
Note: If you want to test our example in some smartphone do not forget a reasonable meta-tag like
<meta name=”viewport” content=”width=device-width, initial-scale=1″>
to the header of the HTML file. You may adapt the metatag given in the above code to your needs. For more information see e.g.:
https://css-tricks.com/snippets/html/responsive-meta-tag/
The reader may have noticed that we have changed some element names in comparison to the HTML code discussed in the last article – but this not be a big obstacle as we kept up the basic tag nesting structure.
The multiple defined internal background layers (bg_left0, bg_left1, bg_left2, bg_info0, bg_info1, bg_info2, bg_right0, bg_right2) MUST be switched/on off at certain width values for the viewport. See below.
Extending the CSS definitions to cover a second transition of the view port width – and transparency effects
We need to adapt the CSS definitions to handle the transparency layers properly – for all view port width transitions. In the 1st article we had defined 3 ranges of view port widths – therefore we have to cover 2 transitions. In the last article we have shown the definitions for the first transition from Range III to Range II.
In addition, we now need to take care of a second width transition from Range II to Range I. At this second transition we want to move the left sided menu area downwards – right below the main text area and on top of the originally right column area (see the 2nd article). All 3 text areas ( i.e. our original columns) shall use all the width of the view port – we only leave small border areas transparent.
You find the necessary, adapted CSS definitions here:
@CHARSET "UTF-8"; html { font-size:10px; } body { margin-left:0; margin-right:0; margin-top: 0; background-image: url(../image/hg_straa_mp.jpg); background-repeat:no-repeat; background-position:top center; } p { font-size: 1.6rem; line-height: 1.4; margin: 0; } div#all { position:relative; width:100%; padding-bottom: 1.0rem; padding-top: 1.0rem; } /* The header region */ div#head { position:relative; width:100%; min- height: 3.0rem; } /* The main contents container */ /* *************************** */ div#outer_cont { position:relative; width:100%; min-height: 10.0rem; margin-top:1.0rem; } /* some elementary width definitions */ /* -------------------------------- */ div#left_nav, div#bg_left0, div#bg_left1 { width: 14rem; } div#left_nav { margin-left: 1.0rem; } div#right, div#bg_right0 { width: 27%; } /* background elements for all columns in range I */ div#bg_left0, div#bg_left1, div#bg_left2, div#bg_right0, div#bg_right_inner0, div#bg_right2, div#bg_info0, div#bg_info1, div#bg_info2 { position: absolute; top:0; bottom:0; border-radius: 0.8rem; } div#bg_left0 { left:1.0rem; background-color: #FFF; opacity: 0.5; border: 0px solid #F00; z-index:1; } div#bg_info0 { position: absolute; left:16.0rem; right:27%; background-color: #FFF; opacity: 0.85; border: 0px solid #00F; z-index:1; } div#bg_right0 { right: 0; border: 0px solid #F00; z-index:1; } div#bg_right_inner0 { left: 1.0rem; right: 1.0rem; background-color: #FEEEBB; opacity:0.80; } /* The float container and its basic elements */ /* ****************************************** */ div#float_cont { position:relative; width: 100%; border: 0px solid #FF0000; z-index:5; } /* floated left main container and * its background elements for range II*/ div#main_cont { position: relative; float: left; width:100%; min-height: 2.0rem; border: 0px solid #009900; z-index:1; } div#bg_left1 { display: none; left:1.0rem; background-color: #FFF; opacity: 0.75; border: 0px solid #F00; z-index:1; } div#bg_info1 { display: none; left:16.0rem; right:1.0rem; background-color: #FFF; opacity: 0.9; border: 0px solid #00F; z-index:1; } /* The main column */ /* --------------- */ div#info_cont { position: relative; width:100%; border:0px #F00 solid; } div#float_info { position:relative; float:left; width: 100%; /*background-color: #99e;*/ border: 0px solid #FF0000; z-index:2; } div#info { position: relative; margin: 0 27% 0 16rem; width:auto; /*background-color: #0f0;*/ padding:0.8rem; /*height:200px;*/ z-index: 1; } div#bg_info2 { display: none; left:1.0rem; right:1.0rem; background-color: #FFB; background-color: #FFF; opacity: 0.95; border: 0px solid #00F; z-index:1; } /* left column */ /* ----------- */ div#left_nav { position:relative; float:left; border: 0px solid #009900; margin-left: -100%; padding-left: 1.0rem; z-index:5; } div#left_inner { position: relative; width:auto; padding: 0.8rem; z-index: 2; } div#bg_left2 { display: none; left:1.0rem; right:1.0rem; border: 0px solid #F00; background-color: #FFF; opacity: 0.9; z-index:1; } /* right column */ /* ------------ */ div#right { float:left; position:relative; margin-left: -27%; min-height: 2.0rem; /*min-width: 15.2rem;*/ /*background-color: #eee;*/ border: 0px solid #009900; z-index:2; } div#right_inner { position:relative; width:auto; margin-left: 1.0rem; margin-right: 1.0rem; padding: 0.8rem; z-index: 2; } div#bg_right2 { display: none; left:1.0rem; right:1.0rem; border: 0px solid #F00; background-color: #FEEEBB; opacity: 0.85; z-index:1; } /* Support elements */ p.floatstop { clear:both; height:0; margin: 0; line-height:0; padding: 0; font-size: 0; } /* contents of the upper horizontal menu */ div.hmen_cont { display: block; position: relative; min-height: 3.0rem; width: auto; margin-right:0.8rem; margin-left:0.8rem; background-color: #EEE; border-radius: 1.0rem; } div.hmen_cont ul { position: relative; list-style-type: none; width: 100%; margin: 0; padding: 0; } div.hmen_cont ul li { float: left; padding: 0.2rem 4.0rem 0.2rem 4.0rem; /*border-left: #ffffff 1px solid;*/ border-right: #a90000 0.2rem 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: 1.8rem; height: 1.8rem; background-color: #A90000; border-top: 0.2rem #CCC solid; border-right: 0.2rem #CCC solid; border-left: 0.2rem #AAA solid; border-bottom: 0.2rem #AAA solid; } /* contents of the left vertical menu */ #left_inner ul { width:100%; min-height: 2.2rem; list-style-type: none; padding: 0; margin: 0; } #left_inner ul li { width:100%; } #left_inner ul li a, #left_inner ul li a:visited { color: #990000; } #left_inner ul li a:hover { color: #FFF; } /* ---------------------------------------------- */ /* @media screen decision and settings for range II */ @media screen and (min-width : 540px) and (max-width :828px) { div#info { margin: 0 2.0rem 0 16rem; background-color:transparent; } div#right { float:left; margin-top:1.0rem; margin-left: 0; margin-right: 0; width:100%; } div#right_inner { margin-left: 1.0rem; margin-right: 1.0rem; width: auto; /* background-color: #FEEEBB; */ border-radius: 0.8rem; } /* * Switch OFF backgrounds after 1st viewport width transition */ div#bg_left0 { display: none; } div#bg_info0 { display:none; } div#bg_right0 { display: none; } /* * Switch ON backgrounds after first viewport width transition */ div#bg_left1 { display: block; } div#bg_info1 { display: block; } div#bg_right2 { display: block; opacity: 0.9; } } /* ---------------------------------------------- */ /* @media screen decision and settings for range I */ @media screen and (max-width : 539px) { div#info { margin: 0 1.0rem 0 1.0rem; /* background-color: #FFB; */ border-radius: 0.8rem; } div#left_nav { margin-top:1.0rem; margin-left: 0; width:100%; padding:0; } div#left_inner { width:auto; padding: 0.8rem; margin: 0 1.0rem 0 1.0rem; /* background-color: #DDDDDD; */ border-radius: 0.8rem; z-index: 2; } div#right { float:left; margin-top:1.0rem; margin-left: 0; margin-right: 0; width:100%; } div#right_inner { margin-left: 1.0rem; margin-right: 1.0rem; width: auto; /* background-color: #FEEEBB;*/ border-radius: 0.8rem; } /* * Switch OFF backgrounds after 2nd viewport width transition */ div#bg_info0 { display: none; } div#bg_info1 { display: none; } div#bg_right0 { display: none; } div#bg_left0 { display: none; } div#bg_left1 { display: none; } /* * Switch ON backgrounds after 2nd viewport width transition */ div#bg_info2 { display: block; opacity: 0.95; } div#bg_left2 { display: block; opacity: 0.95; } div#bg_right2 { display: block; opacity:0.9; } }
Before we discuss some details let us look at the visual results:
Range III: Fluidity when reducing viewport width
Range II: Move the rightmost column to the bottom
Range I: Move the leftmost column right below the text box and over the initially right column
A closer look may reveal that we changed the transparency a bit during the transitions between the viewport width ranges.
Some CSS hints
We switch some of the transparency layers off and on during the range transitions by using the “display” property. This is somewhat saver than just changing the visibility.
As soon as a major content element is moved downwards during a responsive action we switch off the corresponding background element in its encapsulating container. Instead, we switch on the respective background layer in that container which becomes relevant for the correct height of the background layer after the vertical repositioning.
Thus, in Range III bg_left0, bg_info0, bg_right0 are the active background layers. In Range II, however, we use
bg_left1, bg_info1 and bg_right2. In Range I we activate the innermost layers bg_left2, bg_info2, bg_right2.
The height of these absolutely positioned background containers layers is defined by the height of their outer encapsulating container. The height of the latter is defined by the highest of its inner relatively positioned content containers. This type of indirect height control of absolutely positioned layers via relatively positioned boxes on the same code level inside one and the same encapsulating container is basic CSS2.
The transition between Range II and Range I is done by mainly 2 adaptions in the section
@media screen and (max-width : 539px) {}
of the CSS code:
- We adapt the margins of “div#info” to a full extension over the viewport width -i.e by setting both “margin-left” and “margin-right” to small values. ( Small values to keep some optical distance of the contents to the viewport edges …). This change of margins is already enough to vertically reposition “div#left_nav” if we at the same time change the property “left-margin” of “div#left_nav” (from -100%) to zero.
- We set the width of “div#left_nav” to 100%.
n
Pretty simple, isn’t it?
All the rest is cosmetics. Note, that the opacity values are adapted during the transitions, too. Such an adaption may be helpful if elements of the background image started to disturb the readability of your text during the repositioning of the web page’s text containers.
What if we had wanted to move the left sided navigation column above the main text box in Range I?
This is a relevant question. But after what we have learned so far the answer is extremely trivial. So, I leave this up to the reader.
Addendum 25.08.2015:
As I got a question regarding this point I give a hint. The most simple solution builds on the following steps: Change the tag order of the floated “div#left_nav” and “div#float_info” in the HTML code. Adapt the margins of div#left_nav (no loner a negative margin-left, but a negative margin-right!). Change widths and margins – also margin-top – at the responsive transition as required.
Note that turning “div#float_info” a right floated div would not help much. The tag that is the last one in the code for floated elements of a container represents the first element which is moved downwards by the browser as soon as the widths of the floated elements collide. By performing such an experiment we would again see that the div-order in the code is of major importance. However, we are now able to adapt such an order quickly to our requirements regarding the final responsive outcome.
What about “inline-block” instead of floated elements?
Also a good point. With inline block elements [CSS property “display:inline-block;”] we can indeed replace floated elements in their containers. However, the tag order plays the same role for the behavior of inline-block elements as for floated elements when the space for a horizontal presentation becomes insufficient. The last tags are moved downwards. So we would have to work with the same type of tricks as discussed in this and the last article.
What is still missing?
Although we have harvested
- control over the DIV order in the code required for an easily manageable responsiveness,
- control over responsive adaptions of the position and width of content containers and their transparent background layers
there are of course still things to improve. E.g.:
- The upper horizontal main menu could be collapsed to a button with a switch ON/OFF functionality on the upmost area of the web page.
- The vertical navigation sub-menu could also be collapsed to a kind of button available on the left side of the viewport.
A full “Switch ON/OFF” functionality for such menu button requires Javascript. However, there is a well defined – though limited – solution also for users which have Javascript deactivated. These new objectives will be topics of forthcoming articles.
In the next article of this series
Responsive fluid multi-column layouts – with a responsive horizontal menu – IV
we shall describe a handling of the horizontal main menu line at small viewport widths – without involving Javascript.