Converting absolute layout to use floats

I’m looking for some advice on a project I am working on and would be appreciative of any assistance.

Aim:

To make a drag and drop CMS which allows a user to draw elements on a grid and move them into the desired position. The changes are recorded in JSON format and converted into HTML/CSS when the user presses a publish button. The resultant HTML should be clean and flexible (i.e. cater for content that will vary in height/length).
The system should be able to handle creating e-Commerce sites as well as simple information sites.

Problem:

The logical way to achieve a drag and drop system in HTML is to use absolute positioning with set widths and heights; this method doesn’t lend itself to the finished site as the content is likely to be of variable lengths and as absolutely positioned elements are taken out of the flow of the document they are unaware of the elements around them.

Solution:

Create a system which converts the absolutely positioned elements into floated elements.

Example:

In the CMS system the user creates the following layout by drawing boxes on a grid:

  1. Header of fixed height
  2. Navigation of variable height
  3. Image of fixed height
  4. Main content of the page of variable height
  5. List of visited items of variable height
  6. Footer of fixed height

Absolute layout:

Absolute layout

The HTML/CSS would be something like this:

body {
    background-color: #999999;
    font-family: verdana, arial, helvetica, sans-serif;
    font-size: 70%;
    margin: 15px 0;
    padding: 0;
}
#mainContainer {
    background-color: #FFFFFF;
    height: 500px;
    margin: 0 auto;
    position: relative;
    width: 916px;
}
.contentBlock {
    border: 1px solid orange;
    box-sizing: border-box;
    color: orange;
    font-size: 2em;
    text-align: center;
}
.contentBlock:after {
    content: "";
    display: inline-block;
    height: 100%;
    vertical-align: middle;
}
#contentBlock1 {
    height: 120px;
    left: 0;
    position: absolute;
    top: 0;
    width: 916px;
}
#contentBlock2 {
    height: 100px;
    left: 0;
    position: absolute;
    top: 140px;
    width: 136px;
}
#contentBlock3 {
    height: 100px;
    left: 0;
    position: absolute;
    top: 260px;
    width: 136px;
}
#contentBlock4 {
    height: 220px;
    left: 156px;
    position: absolute;
    top: 140px;
    width: 604px;
}
#contentBlock5 {
    height: 220px;
    left: 780px;
    position: absolute;
    top: 140px;
    width: 136px;
}
#contentBlock6 {
    height: 120px;
    left: 0;
    position: absolute;
    top: 380px;
    width: 916px;
}
<div id="mainContainer">
    <div class="contentBlock" id="contentBlock1">1</div>
    <div class="contentBlock" id="contentBlock2">2</div>
    <div class="contentBlock" id="contentBlock3">3</div>
    <div class="contentBlock" id="contentBlock4">4</div>
    <div class="contentBlock" id="contentBlock5">5</div>
    <div class="contentBlock" id="contentBlock6">6</div>
</div>

The user now hits the publish button and the layout will be converted to use floats instead absolute positioning. The resultant HTML cannot use absolute positioning because if the content in 2 or 4 expands they will go over/under 3 and 6. Floats keep the elements in the flow and aware of each other so the following would cater for the dynamic content in 2 and 4:

Floated layout:

Floated layout

The HTML/CSS would be something like this:

body {
    background-color: #999999;
    font-family: verdana, arial, helvetica, sans-serif;
    font-size: 70%;
    margin: 15px 0;
    padding: 0;
}
#mainContainer {
    background-color: #FFFFFF;
    margin: 0 auto;
    width: 916px;
}
.contentBlock {
    border: 1px solid orange;
    box-sizing: border-box;
    color: orange;
    font-size: 2em;
    text-align: center;
}
.contentBlock:after {
    content: "";
    display: inline-block;
    height: 100%;
    vertical-align: middle;
}
#contentBlock1 {
    margin-bottom: 20px;
    height: 120px;
}
#contentBlock2 {
    height: 100px;
    margin-bottom: 20px;
    width: 136px;
}
#contentBlock3 {
    height: 100px;
    margin-bottom: 20px;
    width: 136px;
}
#contentBlock4 {
    float: left;
    height: 220px;
    margin-bottom: 20px;
    margin-left: 20px;
    width: 604px;
}
#contentBlock5 {
    float: left;
    height: 220px;
    margin-bottom: 20px;
    margin-left: 20px;
    width: 136px;
}
#contentBlock6 {
    clear: left;
    height: 120px;
}
#contentContainer1 {
    float: left;
    width: 136px;
}
<div id="mainContainer">
    <div class="contentBlock" id="contentBlock1">1</div>
    <div id="contentContainer1">
        <div class="contentBlock" id="contentBlock2">2</div>
        <div class="contentBlock" id="contentBlock3">3</div>
    </div>
    <div class="contentBlock" id="contentBlock4">4</div>
    <div class="contentBlock" id="contentBlock5">5</div>
    <div class="contentBlock" id="contentBlock6">6</div>
</div>

It cannot be expected for the user to understand how floating elements work, so this process would need to be automatic when the changes are published.

This particular example is quite simple, although more advanced layouts would need to be handled as well.

What other CMS systems do:

As far as I can tell, most CMS systems either fix the user into a set template or build the page using JavaScript to set the heights/position of absolutely positioned elements (which I would like to avoid).

Read More:   Why does a while loop block the event loop?

My questions:

  • Is it possible to devise a set of rules to convert an absolute layout to a floated one?
  • If so are there any existing CMS that do it?
  • Any suggestions on other ways to tackle this issue?

Thanks.

First : I don’t think “converting” an absolute layout to float is the best approach. You should think floats from the beginning and hint/teach the user to build the layout accordingly.

Second : I believe the tool you want to build will need the users to learn how to use it. This said you want to make it simple enough for people not familiar with HTML/CSS concepts to be able to use it. So you need to base the use of this tool on simple and understandable concepts that users can use to build the “look” and you to generate the code behind it.

Ones I can think of are :

  • blocks/container
  • columns
  • height/width
  • margin/padding

Now using these concepts you could enable the user to create blocks with properties : number of columns for the content width/height margin/padding. The user can then nest blocks indefinitly with these properties and drag-drop content inside them.

Here is how it could work for your example :

Header :

The user creates a block and gives it these properties :

  • width:100%
  • height:80px (this can be done by draging the elements border)
  • number of columns 2 (one for the logo and one for the menu)

Main :

The user creates a new block under the header with these properties :

  • width:100%
  • height: adaptive
  • number of columns : 3 (col 1 and 3 : 15% width, col 2 70% width)

Footer

New block with same properties as the header.

The use can then start again inside each block/column and can nest new ones with the same properties

Generating the code :

You know the number of columns of each block and their widths so you can easily create a div for each and use floats/width to position them side by side. For the heights : the user can set a fixed height and it won’t be difficult for him to understand that the content can overflow. So if he doesn’t want that he must select the “adaptive” height (height : auto; in css).

Conclusion :

This is a very general idea and simple concept. The main work will be on the UI design and the way you will hint/teach the user to build layouts with your tool. Keep in mind who you are disigning for and how they would react in different situations. Use your best UI skills to hint/teach the use in the right direction.

There’s a website creator tool called Weebly that has the same functionality you’re looking for. It’s free of charge, so you can have a look to learn more about its features.

What you’re asking for is really vague, so I divided the answers into several parts:

1- For the Drag-and-Drop feature:

This is exactly what you’re looking for: Gridster

You can let the user resize the boxes while keeping constraints.

2- If you’re looking for a clean CSS Framework:

3- If you’re looking for a fluid layout which covers the whole page (vertically and horizontally):

html,
body {height:100%; margin:0px; padding:0px;}
.wrapper {position:relative; height:100%; width:100%; display:block;}
.header {position:relative; height:22%; width:100%; display:inline-block; margin-bottom:3%; background:red;}
.footer {position:relative; height:22%; width:100%; display:inline-block; margin-top:3%; background:green;}
.content {position:relative; height:50%; width:100%; display:inline-block;}
.content .left_sidebar {float:left; width:17%; height:100%; position:relative; margin-right:3%; background:yellow;}
.content .right_sidebar {float:right; width:17%; height:100%; position:relative; margin-left:3%; background:purple;}
.content .middle {float:left; width:60%; height:100%; position:relative; background:cyan;}

/**
 * @info Clearfix: clear all the floated elements
 */
.clearfix:after {visibility:hidden; display:block; font-size:0; content:" "; clear:both; height:0;}
.clearfix {display:inline-table;}
	
/**
 * @hack Display the Clearfix as a block element
 * @hackfor Every browser except IE for Macintosh
 */
   /* Hides from IE-mac \*/
   * html .clearfix {height:1%;}
   .clearfix {display:block;}
   /* End hide from IE-mac */
<div class="wrapper">
    <div class="header">Header</div>
    <div class="content">
        <div class="left_sidebar">Left Sidebar</div>
        <div class="middle">Middle</div>
        <div class="right_sidebar">Right Sidebar</div>
        <div class="clearfix"></div>
    </div>
    <div class="footer">Footer</div>
</div>

Keep in mind that doing so will destroy the user experience on mobile devices.

Read More:   Google Chrome extension - how to turn JavaScript on/off?

Is it possible to devise a set of rules to convert an absolute layout to a floated one?

Not impossible but extremely difficult to implement.

If so are there any existing CMS that do it?

Not that I am aware of.

Any suggestions on other ways to tackle this issue?

I find it easier to think of layouts as a bunch of rows and columns, floated appropriately. So, for this layout:

Absolute layout

I would generate HTML markup similar to this (simplified for understanding):

<div class="box">Content 1</div>
<div class="row">
    <div class="col">
        <div class="box">Content 2</div>
        <div class="box">Content 3</div>
    </div>
    <div class="col">
        <div class="box">Content 4</div>
    </div>
    <div class="col">
        <div class="box">Content 5</div>
    </div>
</div>
<div class="box">Content 6</div>

You will need to provide a UI where a user can:

  1. Add content
  2. Add column wrappers
  3. Add columns inside column wrappers

You can then name the rows, columns and/or content elements and use CSS to adjust their widths. Here is a proof-of-concept:

$(function() {
    $(".insertable").draggable({ revert: "invalid" });
    $(".insertzone").droppable({ activeClass: "acceptable", drop: handleInsert, accept: ".insertable-box, .insertable-row" });
    $(".removezone").droppable({ activeClass: "acceptable", drop: handleRemove, accept: ".removable" });
    function handleInsert(event, ui) {
        ui.draggable.css({ left: 0, top: 0 });
        var $div = $("<div class="removable"></div>").appendTo(this).draggable({ revert: "invalid" });
        if (ui.draggable.hasClass("insertable-box")) {
            $div.addClass("box").text("Lorem ipsum dolor sit amet.");
        }
        if (ui.draggable.hasClass("insertable-row")) {
            $div.addClass("row").droppable({ activeClass: "acceptable", drop: handleInsert, greedy: true, accept: ".insertable-col" }); ;
        }
        if (ui.draggable.hasClass("insertable-col")) {
            $div.addClass("col").addClass(ui.draggable.find("select").val()).droppable({ activeClass: "acceptable", drop: handleInsert, greedy: true, accept: ".insertable-box, .insertable-row" });
        }
    }
    function handleRemove(event, ui) {
        ui.draggable.remove();
    }
});
/* INTERFACE */
body { font: medium/1 monospace; }
select { font: inherit; margin: -1em 0; border: 0; padding: 0; }
.insertzone { margin: 1em 0; box-shadow: 0 0 .25em #CCC; }
.removezone { margin: 1em 0; box-shadow: 0 0 .25em #CCC; }
.insertable { cursor: move; display: inline-block; padding: 1em 4em; background-color: #CCC; }
.removable { cursor: move; }
.acceptable { background-color: #FEA !important; }
.insertzone .box { background-color: #EFD; }
.insertzone .row { background-color: #FEE; }
.insertzone .col { background-color: #FFD; }
.insertzone .box:after { display: block; padding: 1em; text-align: center; content: "box"; color: #CCC; margin-bottom: -1em; }
.insertzone .row:after { display: block; padding: 1em; text-align: center; content: "row"; color: #CCC; }
.insertzone .col:after { display: block; padding: 1em; text-align: center; content: "col"; color: #CCC; min-width: 8em; }
.insertzone:after { display: block; padding: 1em; text-align: center; content: "Drag here to insert"; }
.removezone:after { display: block; padding: 1em; text-align: center; content: "Drag here to remove"; }
/* LAYOUT */
.box { margin: 1em 0; padding: 1em; }
.row { margin: 1em 0; }
.row:after { display: block; clear: both; content: ""; }
.col { float: left; }
.col > * { margin-left: .5em; margin-right: .5em; }
.col:first-child > * { margin-left: 0; }
.col:last-child > * { margin-right: 0; }
.col > *:first-child { margin-top: 0; }
.col > *:last-child { margin-bottom: 0; }
.col-10 { width: 10%; }
.col-20 { width: 20%; }
.col-30 { width: 30%; }
.col-40 { width: 40%; }
.col-50 { width: 50%; }
.col-60 { width: 60%; }
.col-70 { width: 70%; }
.col-80 { width: 80%; }
.col-90 { width: 90%; }
<link rel="stylesheet" href="https://code.jquery.com/ui/1.9.2/themes/smoothness/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.9.2/jquery-ui.min.js"></script>

<div class="insertzone"></div>
<div class="removezone"></div>
<div>
    <div class="insertable insertable-box">box</div>
    <div class="insertable insertable-row">row</div>
    <div class="insertable insertable-col">col
        <select>
            <option value="col-10">10%</option>
            <option value="col-20">20%</option>
            <option value="col-30">30%</option>
            <option value="col-40">40%</option>
            <option value="col-50" selected>50%</option>
            <option value="col-60">60%</option>
            <option value="col-70">70%</option>
            <option value="col-80">80%</option>
            <option value="col-90">90%</option>
        </select>
    </div>
</div>

And here is your layout, designed using this tool:

This is what I would to devise a system that automagically does that:
(pseudo code, mostly)

  1. get window.width and window.height of what user is visualizing on his screen
  2. calculate a percentage for every element with a simple formula:

    var elWidth = (element.width / window.width) * 100
    var elHeight = (element.height / window.height) * 100

  3. get every element that is not 100% width to behave like an inline element with
    display:inline-block;

This should be a good base to start with, provided that you designed a good UI to derive every nested DIV and a sort of “magnetic” grid to align the items.

Read More:   Copy to clipboard in Node.js?

What do you think?

The issue with converting from absolute positioning to floated is that you’ll expend a lot of effort on something that probably won’t translate well. Wouldn’t it be better to have the elements use floating from the start?

I know you don’t want users to have to understand floating, but think about the way images work in Microsoft Word – the user drags the image to where they want it, and can then set how text wraps around it. This is not so different from floating elements, and will more accurately present the end result than something that has yet to go through a translation process that may or may not work 100%.

Example:

Drag an element onto the page, it takes up 100% width. Drag another element onto the page, it sits under the first and takes up the same. You then change the “wrap” style of both elements so they float left, and the page updates to show exactly what the user will get at the end. What you sacrifice in super flexible positioning, you make up for in a better user experience.

Conclusion

It sounds like you’re anticipating your users needs by deciding that absolute positioning is the only solution flexible enough – my advice is: don’t build features your users haven’t asked for. Give them a drag and drop UI that you CAN build, and then if they ask for more features, figure it out then. They might never ask, and you’ll save yourself a headache.

  1. Take a look at the grid (not data grid) frameworks, there are lot of good ideas, perhaps you can use some of them without any customization.
  2. Think once more about the absolute positioned user’s input, but i think it is not suitable for a CMS.

I think you should be careful: from what it sounds like you are trying to build a WYSIWYG interface using absolute positioning and size that turns into something that is not WYSIWYG in the end; variable widths and positioning depending on screen size.

You have come across one of the fundamental problems of modern responsive design; websites aren’t WYSIWYG anymore. Its virtually impossible to convey all the different ways a well designed mobile site will look in a single image.

Your users will have to conform to the same constraints that designers have with mobile design, in that elements have to flow gracefully between screen sizes. This usually means constraining content to a grid or a single plane (ie columns or rows), or designing twice; once for mobile, once for desktop.

That being said, one of the few grid systems i have seen that works with absolutely positioned and sized elements is the Masonry Grid. It takes elements of any size and tries to fit them together as best it can without breaking the flow of the page. It’s often seen used in magazine or portfolio sites where long form written content is rare.

With a decent rules system and special elements that create negative space (ie. full width dividers, ’empty’ blocks, full height sidebars) you could give your users the tools to create a site that rearranges itself pretty well using Masonry Grid for everything.


The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Similar Posts