eFORCE
Blogs Home | Corporate Website

Tuesday, May 04, 2010

How Can CSS Scripting Layout Help the Web Development Community?

Background
 
CSS Scripting Layout was designed as a general-purpose solution for defining the layout and resize behavior of HTML elements on a web page. It can be used to describe any variety of layouts succinctly and efficiently. It may be used to encapsulate layouts in reusable constructs that are applied implicitly with minimal developer imposition. Alternatively, layouts may be input explicitly, allowing developers to control precisely the layout and resize behavior of each element among a set of elements. 
 
See the CSS Scripting Layout Model blog entry for a more detailed description and example usage in blog entries Table Layout and Mixing Layout Policies.
 
CSS Scripting Layout addresses most of the frustrations Web Developers have expressed in various articles referenced in my comments on layout in the current CSS Standard. In the remainder of the blog I’ll post a sampling of some of the commentary of authors and commentators from articles referenced there and briefly comment on how Scripting Layout addresses each concern.
 
Eric Meyers – Wanted: Layout System
 
From the author...
 
“So how do we get really powerful source-order-independent layout? I wish I knew. … We just need it, and have needed it for a good decade or so. Without it, CSS is a styling language but not a layout language. We’ve bent it into being something close to a layout language, which is nice but not really ideal.
 
Maybe CSS isn’t the place for this. Maybe there needs to be a new layout language that can be defined and implemented without regard to the constraints of the existing CSS syntax rules, without worrying about backwards compatibility...”
 
The Three-Column Presentation example exhibits source order independence. Scripting Layout defines interfaces and a set of objects in a composition that results in a powerful source-order-independent layout solution. Furthermore, Scripting Layout is fully backward compatible with the current CSS standard.
 
More from the author...
 
“CSS will be extended by JS.”
 
Extending CSS with Scripting Layout and JavaScript is a natural progression from the present state.
 
From Commentators…
 
 
“Give me math, variables, and constants. Give me positioning relative to a specified element. With those things I can make my OWN layout solution. Implement a grid system, and all independent of mark-up order.”
 
And again Matt Wilcox:
 
“The problem is this: It’s not possible to provide a generic solution to layout problems. Our layout problems are not generic. They are specific to our designs. So we need the tools in the core of CSS to make our own layout solution.”
 
Scripting Layout enables the specification any kind of mathematical expression. Positioning relative to specific elements is exhibited in the Three-Column Presentation example. Scripting Layout enables anyone to implement their own layout solution. Moreover, Scripting Layout enables anyone to share and reuse solutions in the same manner that HTML JavaScript solutions are shared and reused such as JQuery.
 
 
“I think the best bet would be to create a separate layout module, independent of semantic markup in HTML and independent of the style rules in CSS as well.”
 
Scripting Layout provides layout independence from the both the HTML source and CSS style rules enabling a level of abstraction that makes layout easier to achieve.
 
 
“What CSS needs to make a good layout system is not so hard, really. It really boils down to satisfy the two main criteria about layout: being able to control the POSITION and SIZE, in the TWO dimensions, and being able to control the RELATIONSHIP of those caracteritics with other elements.”
 
Actually, a good layout system is hard, mathematically speaking, layout is often np-hard or np-complete such as a table layout. Scripting Layout provides a set of heuristics that enables the efficient resolution of difficult np-hard layout problems.
 
 
“…it seems quite clear that the problem is the lack of the ability to define relationships between elements: position and size.”
 
Scripting Layout enables the specification of relationships (constraints) among and between elements.
 
 
“Find out the fundamental axioms that work together to form the basis of a layout complete grammar… there must be a way to achieve any derived two-dimensional layout including the ability to define how it reshapes under different window sizes and zoom levels… Find a syntax and implement it.”
 
Scripting Layout provides a grammar and syntax, JavaScript, and fundamental axioms, new interfaces and constraint resolution techniques that enable a way to achieve any derived two-dimensional layout including the ability to define how it reshapes under different window sizes and zoom levels.
 
 
“…any container can be constrained (from any side, or the center) to be a certain distance (% or px) from it’s parent, including height. It’s basically absolute positioning done right. This opens up vast possibilities with layouts, far more than we have today, and equaling or bettering what can be done with tables.”
 
 
“Has anybody proposed something like Xt’s Form widget? All of the Form’s children size themselves, and they specify attachments to other widgets, or to the edges of the Form. So a 3-column layout, with a header and a footer, would be something like…
 
It’s simple to understand, it’s resolution-independent, and it’s really powerful.”
 
 
“We need the ability to “attach” one element to another in relation to each other. Possibly including the ability to “attach” an element in relation to a parent element…”
 
The Three-Column Presentation Scripting Layout example exhibits this “attachment” ability as specified by the Motif Form Widget.
 
 
 
“…the perl saying “Simple things should be simple, difficult things should be possible”…”
 
Through encapsulation and reuse Scripting Layout makes many difficult things much simpler.
 
 
From the author...
 
"No Expressions - There is currently no ability to specify property values as simple expressions (such as margin-left: 10% - 3em + 4px;). This is useful in a variety of cases, such as calculating the size of columns subject to a constraint on the sum of all columns.
Vertical Control Limitation - While horizontal placement of elements is generally easy to control, vertical placement is frequently unintuitive, convoluted, or impossible. Simple tasks, such as centering an element vertically or getting a footer to be placed no higher than bottom of viewport, either require complicated and unintuitive style rules, or simple but widely unsupported rules.
Poor Layout Controls for Flexible Layouts - While new additions to CSS3 provide a stronger, more robust layout feature-set, CSS is still very much rooted as a styling language, not a layout language."
 
Scripting Layout addresses each of these CSS weaknesses:
  • JavaScript provides syntax for expressions.
  • Vertical control is precise and intuitive.
  • Flexible layouts become much easier to achieve.
  • Scripting Layout is a layout language.
 
 
From the author...
 
“…CSS just can’t do many of the things we should expect of it. Real-world CSS is likely to get longer, not shorter, as CSS evolves toward its manifest destiny and allows us to declare… all manner of complex layouts for which we currently turn to table elements and layout systems like the Dojo BorderContainer and ExpandoPane widgets…”
 
All manner of complex layouts are achievable with Scripting Layout. Layouts are as reusable as the Dojo BorderContainer and ExpandoPane widgets only easier to use and more efficient computationally.
 
From Commentators…
 
Rob:
 
“…until CSS lets me format my layout in a simple grid, just like a table, without resorting to strange non-semantic markup and obscure large negative margins and other hacks, I will continue to use HTML tables to perform this function.”
 
HTML-like tables are achieved in the Scripting Table Layout example.
 
More from Alex Russell – The W3C Cannot Save Us
From the author...
 
“There’s also no indication that the WG has taken stabs exposing the expressive power that Microsoft exposed with CSS expressions.”
 
Microsoft’s CSS expressions had severe performance issues that have lead many people to dismiss JavaScript as a viable layout language. Scripting layout as implemented here is fast and efficient at realizing even the most complex kinds of layout.
 
From the author...
 
“The fact that we have to resort to such contortions to produce layouts that please the eye (in such a simple, basic way) makes me wonder if css – as we know it today – is up to the job at all.”
 
This is a common sentiment. Scripting Layout enables the production of layouts in simple and basic ways that are efficient. Scripting Layout is up to the task.
 
From the author...
 
“CSS tables have only one notable weakness: CSS does not allow for table cells to span rows or columns the way they can in HTML tables (with the “rowspan” and “colspan” attributes).”
 
HTML-like tables that include cell spanning are found in the Scripting Table Layout example. Furthermore, the cell spanning in this example requires no special nonsemantic HTML mark-up.
 
Paul Hammond – Eric Meyer
From the author...
 
“CSS is still incomplete - Alex Robinson's one true layout had stuff in it that nobody had thought of. Scripters are shoring up the weak points, presentation libraries (YUI), work on CSS is slow but is happening. CSS and web standards keep popping up where they’re least expected.”
 
The integration of JavaScript and CSS for layout as seen in Scripting Layout is a natural progression from what is happening now. The CSS Working Group should consider formalizing it.
 
Nicholas C. Zakas – CSS sucks
From the author...
 
“Why is it that creating multi-column layouts [in CSS] still requires trickery and some magic even after all this time? And why can I still not achieve the same type of layouts that I could easily do with tables?”
 
HTML-like tables are achieved in CSS in the Scripting Table Layout example without trickery or magic.
 
From Commentators…
 
Lonnie Lee Best:
 
“You can use absolute positioning to get any layout you want. However, when a page is loaded or resized, that layout remains static. For a layout to accommodate sizing, it requires *behavior* of that layout. I wouldn’t call it un-pure to use javascript to control layout behavior. I would simply call it an inconvenient reality for those who *purely* wanting to keep their layout out of their markup.
 
The question is: do we want that layout behavior to be inherent, or do we want to explicitly control it with javascript.
 
… some type of layout encapsulation needs to be specified somewhere in the markup or css or javascript… you need a way of grouping elements outside of the markup.”
 
Scripting Layout provides the kind of layout encapsulation and grouping required to achieve explicit and implicit layout and resize behavior. Scripting Layout bridges the gap currently existing between CSS and JavaScript.
 
From the author...
 
“We do not need the Working Group to study individual problem cases and propose a pre-packaged “solution” that either misses the point, is fundamentally wrong, or is inflexible... The crux of the issue is that W3C seem to try providing high-level “solutions” instead of low-level tools.“
 
“There are NO tools to allow flexible layout on the web. Building better tools drive better end results.“
 
“When I say CSS needs to manipulate the DOM I'm really talking about some sort of pseudo-DOM, a Visual Object Model… This is entirely about getting CSS able to provide flexible styling WITHOUT manipulating the semantics of a document.“
 
and finally…
 
“CSS 2&3…still suffers from the basic issue of having too few and too inflexible tools for layout.“
 
Scripting Layout is a low-level tool that allows designers to build their own layout solutions that are efficient, reusable, and independent of the semantics of a document. The language incorporates a type of Visual Object Model with the container, its ordered list of subelements, and Visual Object interfaces.
 
From Commentators…
 
Juergen Schreck:
 
“we just need a standardized way for CSS and Javascript to interact better.”
 
Scripting Layout describes a CSS/JavaScript interaction that can be standardized.
 
devsmt:
 
“my concern with css is that is not practical to write reusable components, the language itself laks tools to do it, basic math and variables but class like inheritance too, can alleviate this problem.”
 
Scripting Layout is a tool that provides basic math and variables as well as reusability and inheritance.
 
From the author...
 
“CSS gives imperfect options for layout. Take the example of equidistant objects, have a look at what’s required to achieve this simple visual effect. Something as fundamental as this should not be so hard to achieve. And it wouldn’t be if CSS had basic math calculations combined with an awareness of the dimensions of boxes other than parents.“
 
Equidistant objects are achieved in the Scripting Line Wrapping example. Justifying objects in this manner and mixing this effect with other layout effects is easily achieved in this example.
 
“If I want a grid layout, I want the display to adapt not pixel by pixel, but grid-unit by grid-unit.“
 
A reusable grid layout of this type could be achieved with Scripting Layout.
 
And finally from a member of the W3C CSS Working Group Elika Etemad – Layout Is Expensive
From the author...
 
“A lot of people complain about limitations in the layout capabilities in CSS. Layout in CSS is a pain, and it's a pain because CSS originally wasn't designed for coarse layout, only for linear documents. The CSS Working Group totally understands that CSS today is totally incompetent at doing layout… It is very, very obvious to us that CSS needs better, easier, more powerful layout capabilities.
 
At the same time, defining a CSS layout system is hard. It's expensive, and I don't mean money but skill×time, which is rarer… So for everyone out there who wants CSS layout to improve… please, don't come to the CSS Working Group with a loosely-defined layout proposal…Chances are your proposal is really hard to define and incorporate into existing CSS layout systems at the level of precision we need.“
 
The Scripting Layout Model proposed here is well-developed and fully incorporates into the existing layout system. Moreover, Scripting Layout enables the CSS Working Group to get out of the business of defining ever more expensive, yet limited, CSS layout systems.
 
Conclusion
 
I’ve shown how CSS Scripting Layout brings together many of the independent ideas that the Web community has expressed regarding layout within CSS. Scripting Layout is an open system whereby new layouts heretofore not achievable in CSS can be realized efficiently and shared among the developers putting to an end the frustrations nearly every developer has experienced with the current standard.
 

posted @ Tuesday, May 04, 2010 10:09 AM | Feedback (1)

Friday, April 09, 2010

CSS Scripting Layout – Mixing Layout Policies

 
CSS Scripting Layout – Mixing Layout Policies
 
 
CSS Script – Line Wrapping
 
In this example we present a CSS Scripting Layout policy that arranges rectangles left to right and line-wraps rectangles as required depending on the available width.  With this line wrapping layout we also present a set of policies that can be included with it to alter fine points of the layout to achieve different effects. These set of policies largely emulate inline layout and associated properties.
 
See the CSS Scripting Layout Model blog entry for a detailed description of layout model used in this example.
 
The HTML in Example 1 produces the screen shots in Figures 1 and 2.
 
Example 1 – Line-Wrapping Container
 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
 <title>Line Wrap</title>
<style type="text/css">
 
@layout-policy line_wrap {
initial-script: "\
var lineSpacing=2;\
function containerHeight() {\
var line = lines[lines.length-1];\
return line.top+line.rects.preferred_height.max;\
}\
function containerWidth() {\
var width=0;\
for(var i=lines.length; --i>=0;) {\
var w = lines[i].preferred_width;\
if (width<w) width=w;\
}\
return width;\
}\
function getLine(position) {\
var i=-1;\
var p=0;\
do {\
p+=lines[++i].rects.length;\
} while (position >= p);\
return lines[i];\
}\
function deriveLines(width) {\
var lines = new Array;\
var list = rectangles;\
do {\
var line = lines[lines.length] = new Object;\
var rects = line.rects = list.preferred_width.cumulate.gt(width);\
if (rects.length==0) rects = line.rects = list(0,1);\
var lineNo = line.number = lines.length;\
line.height=rects.preferred_height.max;\
line.preferred_width=rects.preferred_width.sum;\
if (lineNo>1) {\
line.top=lineSpacing+lines[lineNo-2].bottom;\
line.bottom=line.height+line.top;\
} else {\
line.bottom=line.height;\
line.top=0;\
}\
list = list(rects.length, list.length);\
} while (list.length > 0);\
return lines;\
}\
var defaultHeight;\
var lines = deriveLines(rectangles.preferred_width.sum);\
";
container-script: "\
if (sizing)\
 defaultHeight=containerHeight();\
else\
 lines = deriveLines(container.width);\
";
rectangle-attributes: '{\
"line":"getLine(rectangle.position)",\
"isFirst":"rectangle.line.rects[0]==rectangle"\
}';
top:"rectangle.line.top";
height:"rectangle.preferred_height";
left:"rectangle.isFirst ? 0 : predecessor.right";
container-height:"defaultHeight";
container-width:"containerWidth()";
}
 
@layout-policy vcenter {
container-script: "\
if (!sizing)for(var i=lines.length; --i>=0;) {\
var line = lines[i];\
line.center = line.top+line.height/2;\
}\
";
top:none;
vertical-center:"rectangle.line.center";
}
 
@layout-policy justify {
container-script: "\
if (!sizing) {\
var w=container.width;\
for(var i=lines.length; --i>=0;) {\
var line = lines[i];\
var rects = line.rects;\
var len=rects.length;\
if (len>1) line.spread = (w-rects.width.sum)/(len-1);\
}\
}\
";
left:"rectangle.isFirst ? 0 : predecessor.right+rectangle.line.spread";
}
 
@layout-policy fill_line {
container-script: "\
if (!sizing) {\
var w=container.width;\
for(var i=lines.length; --i>=0;) {\
var line = lines[i];\
var rects = line.rects;\
var sum = rects.preferred_width.sum;\
line.space = (w-sum)/sum;\
}\
}\
";
width:"rectangle.preferred_width+(rectangle.line.space*rectangle.preferred_width)";
}
 
@layout-policy fixed_height {
height:"rectangle.line.rects.preferred_height.max";
}
 
@layout-policy pack_column {
initial-script: "\
var margin=8;\
var space=(rectangles.length+1)*margin;\
";
width:"container.width";
height:"rectangle.preferred_height";
top:"margin+(predecessor ? predecessor.bottom : 0)";
container-height:"space+rectangles.preferred_height.sum";
container-width:"rectangles.preferred_width.max";
}
 
#body {
layout-policy:"pack_column";
container-width:100%;
    border:0px black solid;
    padding:0px;
    margin:0px;
    position:relative;
}
div {
    background:gray;
    margin:0px;
    border:0px black dotted;
    padding:0px;
    position:absolute;
}
 
div button {
    margin:0px;
    padding:0px;
    position:absolute;
}
span {
    margin:0px;
    border:1px black dashed;
    padding:0px;
    position:absolute;
}
 
#line_wrap1 {
layout-policy:"line_wrap";
}
 
#line_wrap2 {
layout-policy:"line_wrap vcenter";
}
 
#line_wrap3 {
layout-policy:"line_wrap justify";
}
 
#line_wrap4 {
layout-policy:"line_wrap vcenter justify";
}
 
#line_wrap5 {
layout-policy:"line_wrap fill_line";
}
 
#line_wrap6 {
layout-policy:"line_wrap fill_line fixed_height";
}
 
 </style>
</head>
 
<body id="body">
 
<span>
The line wrapping displayed in the following containers illustrates how a mixin set of layout policies can
work together to achieve different effects.
</span>
 
<div id="line_wrap1">
<span>line_wrap</span>
<button>button&nbsp;1</button>
<button>button&nbsp;2</button>
<button>button&nbsp;3</button>
<button>button&nbsp;4</button>
<button>button&nbsp;5</button>
<button>button&nbsp;6</button>
<button>button&nbsp;7</button>
<button>button&nbsp;8</button>
<button>button&nbsp;9</button>
<button>button&nbsp;10</button>
<button>button&nbsp;11</button>
<button>button&nbsp;12</button>
</div>
 
<div id="line_wrap2">
<span>line_wrap vcenter</span>
<button>button&nbsp;1</button>
<button>button&nbsp;2</button>
<button>button&nbsp;3</button>
<button>button&nbsp;4</button>
<button>button&nbsp;5</button>
<button>button&nbsp;6</button>
<button>button&nbsp;7</button>
<button>button&nbsp;8</button>
<button>button&nbsp;9</button>
<button>button&nbsp;10</button>
<button>button&nbsp;11</button>
<button>button&nbsp;12</button>
</div>
 
<div id="line_wrap3">
<span>line_wrap justify</span>
<button>button&nbsp;1</button>
<button>button&nbsp;2</button>
<button>button&nbsp;3</button>
<button>button&nbsp;4</button>
<button>button&nbsp;5</button>
<button>button&nbsp;6</button>
<button>button&nbsp;7</button>
<button>button&nbsp;8</button>
<button>button&nbsp;9</button>
<button>button&nbsp;10</button>
<button>button&nbsp;11</button>
<button>button&nbsp;12</button>
</div>
 
<div id="line_wrap4">
<span>line_wrap vcenter justify</span>
<button>button&nbsp;1</button>
<button>button&nbsp;2</button>
<button>button&nbsp;3</button>
<button>button&nbsp;4</button>
<button>button&nbsp;5</button>
<button>button&nbsp;6</button>
<button>button&nbsp;7</button>
<button>button&nbsp;8</button>
<button>button&nbsp;9</button>
<button>button&nbsp;10</button>
<button>button&nbsp;11</button>
<button>button&nbsp;12</button>
</div>
 
<div id="line_wrap5">
<span>line_wrap fill_line</span>
<button>button&nbsp;1</button>
<button>button&nbsp;2</button>
<button>button&nbsp;3</button>
<button>button&nbsp;4</button>
<button>button&nbsp;5</button>
<button>button&nbsp;6</button>
<button>button&nbsp;7</button>
<button>button&nbsp;8</button>
<button>button&nbsp;9</button>
<button>button&nbsp;10</button>
<button>button&nbsp;11</button>
<button>button&nbsp;12</button>
</div>
 
<div id="line_wrap6">
<span>line_wrap fill_line fixed_height</span>
<button>button&nbsp;1</button>
<button>button&nbsp;2</button>
<button>button&nbsp;3</button>
<button>button&nbsp;4</button>
<button>button&nbsp;5</button>
<button>button&nbsp;6</button>
<button>button&nbsp;7</button>
<button>button&nbsp;8</button>
<button>button&nbsp;9</button>
<button>button&nbsp;10</button>
<button>button&nbsp;11</button>
<button>button&nbsp;12</button>
</div>
 
</body>
</html>
 
Figure 1 - Scripted line wrapping layout
Figure 3 - Scripted line wrapping layout in narrow window.

posted @ Friday, April 09, 2010 4:00 PM | Feedback (0)

Monday, March 15, 2010

More CSS Scripting Layout - Tables

 
CSS Scripting– Table Layout
 
 
CSS Script HTML Table Emulation
 
In Example 1 we present a CSS Scripting Layout policy that emulates a HTML table.  For comparison we display the emulation in green overlaying a HTML table in blue containing the same content. The Script table layout is able to achieve a better content distribution consuming less screen space as can be seen in Figure 1.
 
See the CSS Scripting Layout Model blog entry for a detailed description of layout model used in this example.
 
Example 1 – HTML Table
 
The HTML in Example 1 produces the screen shot in Figure 1.
 
Example 1 – Html Table Overlay
 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
 <title>HTML Table Overlay</title>
<style type="text/css">
 
@layout-policy HTMLTable {
initial-script: "\
function setNumColumns(nc,space) {\
if (arguments.length>1) spacing=space;\
if (numColumns!=nc) {\
numColumns=nc;\
columns = new Array(numColumns);\
for(var i=numColumns; --i>=0;) {\
var column = columns[i] = new Object;\
column.rects = rectangles(i,container.numChildren,numColumns);\
}\
numRows = Math.ceil(container.numChildren/numColumns);\
rows = new Array(numRows);\
for(var i=numRows; --i>=0;) {\
var row=rows[i] = new Object;\
row.rects = rectangles(i*numColumns,(i+1)*numColumns);\
}\
}\
}\
var rows = null;\
var columns = null;\
var numColumns=0;\
var numRows=0;\
var widthDeficit = false;\
var excessiveHeight = false;\
var defaultHeight,defaultWidth;\
var spacing=0;\
function deriveWidth() {\
var width = (numColumns+1)*spacing;\
widthDeficit = true;\
for(var i=numColumns; --i>=0;) {\
var rects = columns[i].rects;\
widthDeficit &= rects.preferred_width.max > rects.current_width.max;\
width += rects.preferred_width.max;\
}\
return width;\
}\
function deriveHeight() {\
var height= (numRows+1)*spacing;\
excessiveHeight = false;\
for(var i=numRows; --i>=0;) {\
var rects = rows[i].rects;\
excessiveHeight |= rects.max_height.max > rects.preferred_height.max;\
height+= rects.preferred_height.max;\
}\
if (excessiveHeight) excessiveHeight = rectangles.size_deficit.eq(true).length == 0;\
return height;\
}\
function deriveRows() {\
for(var i=0; i<numRows; ++i) {\
var row = rows[i];\
var rects = row.rects;\
row.height = rects.preferred_height.max;\
if (i==0) {\
row.top = spacing;\
row.bottom = row.height+spacing;\
} else {\
row.top = rows[i-1].bottom+spacing;\
row.bottom = row.top+row.height;\
}\
}\
}\
function deriveColumns() {\
if (!excessiveHeight) {\
var pie=0;\
var usable_width=(widthDeficit?defaultWidth:container.current_width)-(numColumns+1)*spacing;\
for(var i=numColumns; --i>=0;) {\
var column = columns[i];\
var rects = column.rects;\
var isPliant = column.pliant = column.pliant !== false && rects.pliant.eq(false).length == 0;\
if (!isPliant) {\
usable_width -= column.portion = rects.min_width.max;\
} else {\
pie += column.portion = rects.preferred_width.max;\
}\
}\
var ratio=usable_width/pie;\
for(var i=0; i<numColumns; ++i) {\
var column = columns[i];\
column.width = column.pliant ? column.portion*ratio : column.portion;\
column.left = i!=0?columns[i-1].left+columns[i-1].width+spacing:spacing;\
}\
}\
}\
";
rectangle-attributes: '{\
"column":"columns[rectangle.position%numColumns]",\
"row":"rows[Math.floor(rectangle.position/numColumns)]",\
"max_height":"rectangle.preferred_height>=rectangle.current_height?\
      rectangle.preferred_height:rectangle.current_height",\
"max_width":"rectangle.preferred_width>=rectangle.current_width?\
      rectangle.preferred_width:rectangle.current_width",\
"pliant":"rectangle.pliant!==false&&rectangle.preferred_width<=rectangle.current_width",\
"size_deficit":"rectangle.preferred_width>rectangle.current_width\
      ||rectangle.preferred_height>rectangle.current_height",\
"min_width":"rectangle.pliant?0:rectangle.preferred_width"\
}';
container-script: "\
if (numColumns<=0) setNumColumns(Math.ceil(Math.sqrt(container.numChildren)));\
if (sizing) {\
defaultWidth=deriveWidth();\
defaultHeight=deriveHeight();\
} else {\
deriveRows();\
deriveColumns();\
}\
";
top:"rectangle.row.top";
left:"rectangle.column.left";
height:"rectangle.row.height";
width:"rectangle.column.width";
container-width:"defaultWidth";
container-height:"defaultHeight";
}
 
 
#body {
    border:0px green dotted;
    padding:0px;
    margin:0px;
    position:relative;
layout-policy: "HTMLTable";
initial-script: "setNumColumns(4,2);";
container-width:100%;
}
.text {
    margin:0px;
    position:absolute;
    color:green;
    border:1px green solid;
    padding:0px;
}
span {
float:left;
    border:1px red solid;
}
/*
html table rules
display:none;
*/
.table {
    border:0px blue dotted;
    margin:0px;
    padding:0px;
}
.ttext {
    margin:0px;
    color:blue;
    border:1px blue solid;
    padding:0px;
    vertical-align:top;
}
 
 </style>
</head>
 
<body id='body'>
 
<table class='table' cellspacing='2'>
<tr class='ttext'>
 
<td class='ttext'>
CSSScript in green HTML in blue...
</td>
 
<td class='ttext'>
Fusce enim sem, ornare in ornare nec, ornare sed neque. Ut sed felis orci, in pretium lectus. Cras nec felis sed nibh venenatis dignissim in sit amet massa.
</td>
 
<td class='ttext'>
veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
</td>
 
<td class='ttext'>
Cras posuere metus at ligula posuere in consequat lorem malesuada.
</td>
 
</tr>
 
<tr class='ttext'>
 
<td class='ttext'>
Nulla facilisi. Aliquam ultrices consequat rutrum.
</td>
 
<td class='ttext'>
In hac habitasse platea dictumst.
</td>
 
<td class='ttext'> 
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
</td>
 
<td class='ttext'>
Sed scelerisque fringilla ligula at laoreet. Cras posuere metus at ligula posuere in consequat lorem malesuada.
</td>
 
</tr>
 
<tr class='ttext'>
 
<td class='ttext'>
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima
</td>
 
<td class='ttext'>
Fusce quis lacus ligula, a dictum metus.
</td>
 
<td class='ttext'>
vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
</td>
 
<td class='ttext'>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum vestibulum fringilla interdum. Fusce suscipit vehicula nunc, nec sagittis risus mollis non. Cras non rhoncus magna. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nullam eleifend sapien velit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque gravida erat vel eros iaculis ac rhoncus nibh tincidunt.
</td>
 
</tr>
 
<tr class='ttext'>
 
<td class='ttext'>
Cras sodales mollis arcu, quis sagittis tellus euismod eu. Nulla facilisi.
</td>
 
<td class='ttext'>
Aliquam ultrices consequat rutrum. Quisque pharetra adipiscing porta.
</td>
 
<td class='ttext'>
Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
</td>
 
<td class='ttext'>
Nullam sem urna, fringilla tempus aliquet a, ornare non risus.
</td>
 
</tr>
 
<tr class='ttext'>
 
<td class='ttext'>
Nullam eleifend sapien velit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque gravida erat vel eros iaculis ac rhoncus nibh tincidunt.
</td>
 
<td class='ttext'>
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.
</td>
 
<td class='ttext'>
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque gravida erat vel eros iaculis ac rhoncus nibh tincidunt.
</td>
 
<td class='ttext'>
Sed id lobortis nulla.
</td>
 
</tr>
</table>
 
 
<div class='text'>
CSSScript in green HTML in blue...
</div>
 
<div class='text'>
Fusce enim sem, ornare in ornare nec, ornare sed neque. Ut sed felis orci, in pretium lectus. Cras nec felis sed nibh venenatis dignissim in sit amet massa.
</div>
 
<div class='text'>
veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
</div>
 
<div class='text'>
Cras posuere metus at ligula posuere in consequat lorem malesuada.
</div>
 
<div class='text'>
Nulla facilisi. Aliquam ultrices consequat rutrum.
</div>
 
<div class='text'>
In hac habitasse platea dictumst.
</div>
 
<div class='text'>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
</div>
 
<div class='text'>
Sed scelerisque fringilla ligula at laoreet. Cras posuere metus at ligula posuere in consequat lorem malesuada.
</div>
 
<div class='text'>
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima
</div>
 
<div class='text'>
Fusce quis lacus ligula, a dictum metus.
</div>
 
<div class='text'>
vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
</div>
 
<div class='text'>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum vestibulum fringilla interdum. Fusce suscipit vehicula nunc, nec sagittis risus mollis non. Cras non rhoncus magna. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nullam eleifend sapien velit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque gravida erat vel eros iaculis ac rhoncus nibh tincidunt.
</div>
 
<div class='text'>
Cras sodales mollis arcu, quis sagittis tellus euismod eu. Nulla facilisi.
</div>
 
<div class='text'>
Aliquam ultrices consequat rutrum. Quisque pharetra adipiscing porta.
</div>
 
<div class='text'>
Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
</div>
 
<div class='text'>
Nullam sem urna, fringilla tempus aliquet a, ornare non risus.
</div>
 
<div class='text'>
Nullam eleifend sapien velit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque gravida erat vel eros iaculis ac rhoncus nibh tincidunt.
</div>
 
<div class='text'>
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.
</div>
 
<div class='text'>
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque gravida erat vel eros iaculis ac rhoncus nibh tincidunt.
</div>
 
<div class='text'>
Sed id lobortis nulla.
</div>
 
</body>
</html>
 
Figure 1 – HTML Table emulation. The Script table in green overlays the HTML table in blue rendering a configuration that consumes less screen space.
 
This layout renders in less than 16 or up to 32 milliseconds on a Dell LATITUDE D630 Laptop (Intel Core 2 Duo T7500 2.20GHz, 2.49 GB RAM) running MS Windows XP V2002 Service Pack 3.

CSS Script Optimized Table – A Multiphase Layout

 
In Example 2 we present the same CSS Table Scripting Layout policy of Example 1 followed by an optimization step. The optimization step is achieved through a multiphase layout specification. Layout phases are delimited by colons in a rule’s layout-policy. Phases are executed sequentially in the order in which they appear. Each phase in a multiphase layout executes to completion as an independent layout, i.e. each phase converges to some solution. Subsequent phases begin with the final configuration of the prior phase. This allows the fine tuning of a configuration or any other kind of modification to achieve a desired result.
 
The Optimization phase defined in the Optimize layout-policy in Example 2 applies a heuristic measure to reduce the total whitespace in the table.
 
For comparison we display the optimized script table in green overlaying a HTML table in blue containing the same content as in Example 1. The Scripting table layout finds better content distributions resulting in a reduced total area as exhibited in Figure 2.
 
Other table optimizations that are more mathematically rigorous could be applied such as an adaptation of the Simple Continuous Table Layout or a hybrid.
 
Example 2 – Optimized Table Layout
 
The layout-policy defined in Example 2 extends Example 1 and produces the screen shot in Figure 2. The screen width of Figures 1 and 2 is identical.
 
Example 2 – Optimized Table
 
 
@layout-policy Optimize {
initial-script: "\
function deriveColumns() {\
if (!excessiveHeight) {\
var pie=0;\
var usable_width=(widthDeficit?defaultWidth:container.current_width)-(numColumns+1)*spacing;\
var wratio=container.width/(container.height+container.width);\
var hratio=container.height/(container.height+container.width);\
for(var i=numColumns; --i>=0;) {\
var column = columns[i];\
var rects = column.rects;\
var isPliant = column.pliant = rects.pliant.eq(false).length == 0;\
if (isPliant) {\
var colWaste = rects.waste;\
var rowWaste = rects.rowWaste;\
var rowWasteValue = hratio*(rowWaste.avg+(-1)*((0.5)*rowWaste.stddev\
+((-0.3)*(rowWaste.max+rowWaste.min))));\
var colWasteValue= wratio*(colWaste.avg+(-1)*((0.5)*colWaste.stddev\
+((-0.15)*(colWaste.max+colWaste.min))));\
var wasteArea = rowWasteValue-colWasteValue;\
pie += column.portion = rects.preferred_width.max\
+(wasteArea<0?-Math.sqrt(-wasteArea):Math.sqrt(wasteArea));\
} else {\
usable_width -= column.portion = rects.min_width.max;\
}\
}\
pie=usable_width/pie;\
for(var i=0; i<numColumns; ++i) {\
var column = columns[i];\
if (column.pliant) column.width = column.portion*pie;\
column.left = i!=0?columns[i-1].left+columns[i-1].width+spacing:spacing;\
}\
}\
}\
";
rectangle-attributes: '{\
"current_area":"rectangle.current_width*rectangle.current_height",\
"preferred_area":"rectangle.preferred_width*rectangle.preferred_height",\
"waste":"rectangle.current_area-rectangle.preferred_area-rectangle.requiredSpace",\
"requiredSpace":"(rectangle.current_width-rectangle.preferred_width)\
      *(rectangle.current_height-rectangle.preferred_height)",\
"rowRectsWaste":"rectangle.row.rects.remove(rectangle).waste",\
"rowWaste":"rectangle.rowRectsWaste.sum+(numColumns-1)*rectangle.rowRectsWaste.min",\
"pliant":"rectangle.preferred_width<=rectangle.current_width"\
}';
}
 
#body {
layout-policy: "HTMLTable:Optimize";
initial-script: "\
setNumColumns(4,2);\
";
container-width:100%;
    border:0px green dotted;
    padding:0px;
    margin:0px;
    position:relative;
}
 
 
 
 
Figure 2 – The optimized script table in green from Example 2 uses a multiphase layout that applies an optimization that reduces whitespace in the table. The result is a tighter configuration than otherwise possible by a HTML table shown in blue.
 
Depending on the window size, this layout renders somewhere between 15 and 50 milliseconds on a Dell LATITUDE D630 Laptop (Intel Core 2 Duo T7500 2.20GHz, 2.49 GB RAM) running MS Windows XP V2002 Service Pack 3.
 
An Optimized Cell Spanning Table
 
In Example 3 we present a CSS Table Scripting Layout policy that builds on the ideas presented in Examples 1 and 2 further extending capabilities by allowing cells to span multiple rows and columns. Cell spanning is achieved through rectangle-attributes colSpan and rowSpan. These values default to one in the SpanningTable layout-policy. Other classes define rectangle-attributes with colSpan and rowSpan values greater than one.
 
For comparison we display the Script table in green overlaying a HTML table in blue containing the same content and employing the same spans. As in the prior examples the Scripting table layout finds better content distributions resulting in a reduced total area as exhibited in Figure 3.
 
Example 3 – Cell Spanning Table Layout
 
The layout-policy defined in Example 3 produces the screen shot in Figure 3.
 
Example 3 – Cell Spanning Table
 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
 <title>Cell Spanning Table Overlaying Equivalent HTML</title>
<style type="text/css">
 
@layout-policy SpanningTable {
initial-script: "\
function fillCell(cell,rect) {\
var undefined;\
var rs=rect.rowSpan;\
var cs=rect.colSpan;\
var row=cell[0];\
var col=cell[1];\
var pos=rect.position;\
while(rs--) {\
var r = rows[row++];\
var x=cs;\
while(x--) r[col+x]=pos;\
}\
col+=cs;\
r = rows[cell[0]];\
if (pos+1!=rectangles.length)\
if (col >= numColumns || r[col]!==undefined) do {\
if (col >= numColumns) {\
r = rows[cell[0]=cell[0]+1];\
col=0;\
}\
while(col<numColumns && r[col]!==undefined) ++col;\
} while(col >= numColumns);\
cell[1]=col;\
}\
function setNumColumns(nc,space) {\
if (arguments.length>1) spacing=space;\
if (numColumns!=nc) {\
numColumns=nc;\
numRows = Math.ceil(rectangles.cellCount.sum/numColumns);\
rows = new Array(numRows);\
for(var i=0;i<numRows;++i) rows[i] = new Array(numColumns);\
var cell = new Array(0,0);\
for(var x=0;x<rectangles.length;++x) fillCell(cell,rectangles[x]);\
for(var i=0;i<numRows;++i) {\
var r=rows[i];\
var row=rows[i] = new Object;\
row.cells=rectangles(r);\
var len=r.length;\
for(var j=len-1;--j>=0;) {\
var k=j+1;\
if (r[j]==r[k]) while(--j>=0 && r[j]==r[k]); r.splice(j+1,k-j-1);\
}\
row.rects=len==r.length?row.cells:rectangles(r);\
}\
columns = new Array(numColumns);\
for(var i=0;i<numColumns;++i) {\
var column = columns[i] = new Object;\
var cells=rows[0].cells(i,i+1);\
var colRects=cells;\
for(var j=1;j<numRows;++j) {\
var r=rows[j].cells[i];\
if (r != colRects[colRects.length-1]) colRects=colRects.append(r);\
cells=cells.append(r);\
}\
column.cells=cells;\
column.rects=colRects;\
}\
for(var i=numRows;--i>=0;) rows[i].bottomRects=rectangles.bottomRow.eq(i);\
for(var i=numColumns;--i>=0;) columns[i].leftRects=rectangles.leftCol.eq(i);\
deriveRows();\
deriveColumns();\
}\
}\
var rows = null;\
var columns = null;\
var numColumns=0;\
var numRows=0;\
var widthDeficit = false;\
var excessiveHeight = false;\
var defaultHeight,defaultWidth;\
var spacing=0;\
function deriveWidth() {\
widthDeficit = true;\
for(var i=numColumns; --i>=0;) {\
var rects = columns[i].leftRects;\
widthDeficit &= rects.preferred_width.max > rects.current_width.max;\
}\
return spacing + columns[numColumns-1].cells.preferred_right.max;\
}\
function deriveHeight() {\
excessiveHeight = false;\
for(var i=numRows; --i>=0;) {\
var rects = rows[i].bottomRects;\
excessiveHeight |= rects.current_bottom.max > rects.preferred_bottom.max;\
}\
if (excessiveHeight) excessiveHeight = rectangles.size_deficit.eq(true).length == 0;\
return spacing + rows[numRows-1].cells.preferred_bottom.max;\
}\
function deriveRows() {\
for(var i=0; i<numRows; ++i) {\
var row = rows[i];\
if (i==0) {\
row.top = spacing;\
} else {\
row.top = rows[i-1].bottom+spacing;\
}\
row.bottom = row.bottomRects.preferred_bottom.max;\
row.height = row.bottom-row.top;\
}\
}\
function deriveColumns() {\
if (!excessiveHeight) {\
var pie=0;\
var usable_width=(widthDeficit?defaultWidth:container.current_width)-(numColumns+1)*spacing;\
for(var i=numColumns; --i>=0;) {\
var column = columns[i];\
var rects = column.rects;\
var isPliant = column.pliant = rects.pliant.eq(false).length == 0;\
if (!isPliant) {\
usable_width -= column.portion = rects.min_width(i).max;\
} else {\
pie += column.portion = rects.portion(i).max;\
}\
}\
var ratio=usable_width/pie;\
for(var i=0; i<numColumns; ++i) {\
var column = columns[i];\
if (i==0) {\
column.left = spacing;\
column.width = column.right = spacing + (column.pliant ? column.portion*ratio : column.portion);\
} else {\
column.left = columns[i-1].right+spacing;\
column.width = column.pliant ? column.portion*ratio : column.portion;\
column.right= column.left + column.width;\
}\
}\
}\
}\
function column(rect) {\
for (var i=0;i<columns.length;++i)\
if (columns[i].rects.contains(rect)) return i;\
}\
function row(rect) {\
for (var i=0;i<rows.length;++i)\
if (rows[i].rects.contains(rect)) return i;\
}\
function spansCol(currentCol){return this.colSpan+this.column-currentCol;}\
function portion(currentCol){\
var nc=this.colSpan-1;\
return nc>0\
?this.preferred_width*(columns[currentCol].width+(nc*spacing)/(nc+1))/this.cellWidth\
:this.preferred_width;\
}\
function min_width(currentCol){\
var mw=0;\
if (!this.pliant) {\
var nc=this.colSpan-1;\
var ratio=nc>0?(columns[currentCol].width+(nc*spacing)/(nc+1))/this.cellWidth:1;\
mw=this.preferred_width*ratio;\
}\
return mw;\
}\
function cellWidth(rect) {\
var c=rect.column;\
var nc=c+rect.colSpan-1;\
return columns[nc].right-columns[c].left;\
}\
";
rectangle-attributes: '{\
"column":"column(rectangle)",\
"row":"row(rectangle)",\
"leftCol":"rectangle.column+rectangle.colSpan-1",\
"bottomRow":"var br=rectangle.row+rectangle.rowSpan-1; br>=numRows?numRows-1:br",\
"portion":"portion",\
"cellWidth":"cellWidth(rectangle)",\
"cellBottom":"rows[rectangle.bottomRow].bottom",\
"spansCol":"spansCol",\
"cellCount":"rectangle.colSpan*rectangle.rowSpan",\
"colSpan":"1",\
"rowSpan":"1",\
"max_height":"rectangle.preferred_height>=rectangle.current_height?\
      rectangle.preferred_height:rectangle.current_height",\
"max_width":"rectangle.preferred_width>=rectangle.current_width?\
      rectangle.preferred_width:rectangle.current_width",\
"pliant":"rectangle.pliant!==false&&rectangle.preferred_width<=rectangle.current_width",\
"size_deficit":"rectangle.preferred_width>rectangle.current_width\
      ||rectangle.preferred_height>rectangle.current_height",\
"min_width":"min_width",\
"current_bottom":"rows[rectangle.row].top+rectangle.current_height",\
"preferred_bottom":"rows[rectangle.row].top+rectangle.preferred_height",\
"preferred_right":"columns[rectangle.column].left+rectangle.preferred_width"\
}';
container-script: "\
if (numColumns<=0) setNumColumns(Math.ceil(Math.sqrt(container.numChildren)));\
if (sizing) {\
defaultWidth=deriveWidth();\
defaultHeight=deriveHeight();\
} else {\
deriveRows();\
deriveColumns();\
}\
";
top:"rows[rectangle.row].top";
bottom:"rectangle.cellBottom";
left:"columns[rectangle.column].left";
right:"columns[rectangle.column+rectangle.colSpan-1].right";
container-width:"defaultWidth";
container-height:"defaultHeight";
}
 
@layout-policy Optimize {
initial-script: "\
function deriveColumns() {\
if (!excessiveHeight) {\
var pie=0;\
var usable_width=(widthDeficit?defaultWidth:container.current_width)-(numColumns+1)*spacing;\
var wratio=container.width/(container.height+container.width);\
var hratio=container.height/(container.height+container.width);\
for(var i=numColumns; --i>=0;) {\
var column = columns[i];\
var rects = column.rects;\
var isPliant = column.pliant = rects.pliant.eq(false).length == 0;\
if (isPliant) {\
var colWaste = rects.columnSpace(i);\
var rowWaste = rects.columnRowSpace(i);\
var rowWasteValue = hratio*((1.0)*rowWaste.avg+(-1)*((0.5)*rowWaste.stddev\
+((-0.3)*(rowWaste.max+rowWaste.min))));\
var colWasteValue= wratio*((1.0)*colWaste.avg+(-1)*((0.5)*colWaste.stddev\
+((-0.15)*(colWaste.max+colWaste.min))));\
var wasteArea = rowWasteValue-colWasteValue;\
var wasteArea = -colWasteValue;\
pie += column.portion = rects.portion(i).max\
+(wasteArea<0?-Math.sqrt(-wasteArea):Math.sqrt(wasteArea));\
} else {\
usable_width -= column.portion = rects.min_width(i).max;\
}\
}\
var ratio=usable_width/pie;\
for(var i=0; i<numColumns; ++i) {\
var column = columns[i];\
if (i==0) {\
column.left = spacing;\
column.width = column.right = spacing + (column.pliant ? column.portion*ratio : column.portion);\
} else {\
column.left = columns[i-1].right+spacing;\
column.width = column.pliant ? column.portion*ratio : column.portion;\
column.right= column.left + column.width;\
}\
}\
}\
}\
function columnSpace(currentCol){\
var nc=this.colSpan-1;\
var ws=this.whiteSpace;\
return nc>0\
?ws*(columns[currentCol].width+(nc*spacing)/(nc+1))/this.cellWidth\
:ws;\
}\
function cellHeight(rect) {\
var r=rect.row;\
var nr=r+rect.rowSpan-1;\
return rows[nr].bottom-rows[r].top;\
}\
function rowSpace(currentRow){\
var nr=this.rowSpan-1;\
var ws=this.whiteSpace;\
return nr>0\
?ws*(rows[currentRow].height+(nr*spacing)/(nr+1))/this.cellHeight\
:ws;\
}\
function columnRowSpace(currentCol){\
var nc=this.colSpan-1;\
var colPortion=nc>0?(this.cellWidth-columns[currentCol].width+(nc*spacing)/(nc+1))/this.cellWidth:0;\
var wasteValue= colPortion*this.whiteSpace;\
var ri=this.row;\
var nr=this.rowSpan;\
while (--nr>=0) {\
var rowRects=rows[ri+nr].rects.remove(this);\
var space=rowRects.rowSpace(ri+nr);\
if (colPortion>0) {\
var rowPortion=colPortion*this.rowSpace(ri+nr);\
wasteValue += space.sum+(numColumns-1)*(space.min<rowPortion?space.min:rowPortion);\
} else {\
wasteValue += space.sum+(numColumns-1)*space.min;\
}\
}\
return wasteValue;\
}\
";
rectangle-attributes: '{\
"cellHeight":"cellHeight(rectangle)",\
"whiteSpace":"rectangle.current_area-rectangle.preferred_area-\
      rectangle.requiredSpace",\
"current_area":"rectangle.current_width*rectangle.current_height",\
"preferred_area":"rectangle.preferred_width*rectangle.preferred_height",\
"columnSpace":"columnSpace",\
"columnRowSpace":"columnRowSpace",\
"rowSpace":"rowSpace",\
"requiredSpace":"(rectangle.current_width-rectangle.preferred_width)\
      *(rectangle.current_height-rectangle.preferred_height)",\
"rightWaste":"(rectangle.current_width-rectangle.preferred_width)\
      *rectangle.current_height",\
"pliant":"rectangle.preferred_width<=rectangle.current_width"\
}';
}
 
#body {
    border:0px green dotted;
    padding:0px;
    margin:0px;
    position:relative;
layout-policy: "SpanningTable:Optimize";
initial-script: "setNumColumns(4,2);";
container-width:100%;
}
.text {
    margin:0px;
    position:absolute;
    color:green;
    border:1px green solid;
    padding:0px;
}
.bigger {
rectangle-attributes: '{\
"rowSpan":"2",\
"colSpan":"2",\
}';
}
.taller {
rectangle-attributes: '{\
"rowSpan":"2",\
}';
}
.wider {
rectangle-attributes: '{\
"colSpan":"2",\
}';
}
.widest {
rectangle-attributes: '{\
"colSpan":"3",\
}';
}
/*
html table rules
*/
.table {
    border:0px blue dotted;
    margin:0px;
    padding:0px;
}
.ttext {
    margin:0px;
    color:blue;
    border:1px blue solid;
    padding:0px;
    vertical-align:top;
}
 
 </style>
</head>
 
 
<body id="body">
 
<table class="table" cellspacing="2">
<tr class="ttext">
 
<td class="ttext">
CSSScript in green HTML in blue...
</td>
 
<td class="ttext">
Fusce enim sem, ornare in ornare nec, ornare sed neque. Ut sed felis orci, in pretium lectus. Cras nec felis sed nibh venenatis dignissim in sit amet massa.
</td>
 
<td class="ttext" rowSpan="2">
veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
In hac habitasse platea dictumst.
veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
In hac habitasse platea dictumst.
veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
In hac habitasse platea dictumst.
</td>
 
<td class="ttext">
Cras posuere metus at ligula posuere in consequat lorem malesuada.
</td>
 
</tr>
 
<tr class="ttext">
 
<td class="ttext" colSpan="2">
Nulla facilisi. Aliquam ultrices consequat rutrum.
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
</td>
 
<td class="ttext" rowSpan="2">
Sed scelerisque fringilla ligula at laoreet. Cras posuere metus at ligula posuere in consequat lorem malesuada.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum vestibulum fringilla interdum. Fusce suscipit vehicula nunc, nec sagittis risus mollis non. Cras non rhoncus magna. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nullam eleifend sapien velit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque gravida erat vel eros iaculis ac rhoncus nibh tincidunt.
</td>
 
</tr>
 
<tr class="ttext">
 
<td class="ttext" colspan="3">
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima
Fusce quis lacus ligula, a dictum metus.
vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
</td>
 
</tr>
 
<tr class="ttext">
 
<td class="ttext">
Cras sodales mollis arcu, quis sagittis tellus euismod eu. Nulla facilisi.
</td>
 
<td class="ttext">
Aliquam ultrices consequat rutrum. Quisque pharetra adipiscing porta.
</td>
 
<td class="ttext" colSpan="2" rowSpan="2">
Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
Nullam sem urna, fringilla tempus aliquet a, ornare non risus.
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque gravida erat vel eros iaculis ac rhoncus nibh tincidunt.
Sed id lobortis nulla.
</td>
 
</tr>
 
<tr class="ttext">
 
<td class="ttext">
Nullam eleifend sapien velit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque gravida erat vel eros iaculis ac rhoncus nibh tincidunt.
</td>
 
<td class="ttext">
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.
</td>
 
</tr>
</table>
 
 
<div class="text">
CSSScript in green HTML in blue...
</div>
 
<div class="text">
Fusce enim sem, ornare in ornare nec, ornare sed neque. Ut sed felis orci, in pretium lectus. Cras nec felis sed nibh venenatis dignissim in sit amet massa.
</div>
 
<div class="text taller">
veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
In hac habitasse platea dictumst.
veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
In hac habitasse platea dictumst.
veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?
In hac habitasse platea dictumst.
</div>
 
<div class="text">
Cras posuere metus at ligula posuere in consequat lorem malesuada.
</div>
 
<div class="text wider">
Nulla facilisi. Aliquam ultrices consequat rutrum.
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
</div>
 
<div class="text taller">
Sed scelerisque fringilla ligula at laoreet. Cras posuere metus at ligula posuere in consequat lorem malesuada.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum vestibulum fringilla interdum. Fusce suscipit vehicula nunc, nec sagittis risus mollis non. Cras non rhoncus magna. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nullam eleifend sapien velit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque gravida erat vel eros iaculis ac rhoncus nibh tincidunt.
</div>
 
<div class="text widest">
sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima
Fusce quis lacus ligula, a dictum metus.
vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
</div>
 
<div class="text">
Cras sodales mollis arcu, quis sagittis tellus euismod eu. Nulla facilisi.
</div>
 
<div class="text">
Aliquam ultrices consequat rutrum. Quisque pharetra adipiscing porta.
</div>
 
<div class="text bigger">
Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
Nullam sem urna, fringilla tempus aliquet a, ornare non risus.
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque gravida erat vel eros iaculis ac rhoncus nibh tincidunt.
Sed id lobortis nulla.
</div>
 
<div class="text">
Nullam eleifend sapien velit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque gravida erat vel eros iaculis ac rhoncus nibh tincidunt.
</div>
 
<div class="text">
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.
</div>
 
</body>
</html>
 
  
 
Figure 3– Optimized Cell Spanning Table. The layout in Example 3 extends the ideas and techniques applied in Examples 1 and 2.  The Script table in green achieves better results than an equivalent HTML table.
Depending on the window size and V8 JavaScript garbage collection events, this layout renders somewhere between 50 and 250 milliseconds and most often under 100 milliseconds on a Dell LATITUDE D630 Laptop (Intel Core 2 Duo T7500 2.20GHz, 2.49 GB RAM) running MS Windows XP V2002 Service Pack 3.
 

posted @ Monday, March 15, 2010 10:54 AM | Feedback (5)

Thursday, July 16, 2009

CSS Scripting Layout Specification

 
CSS Scripting Layout Model
Table of Contents
Abstract   top
This document describes a new set of CSS properties and object specifications that together compose a more powerful means to describe complex arbitrary layout criteria that are reusable and extensible. The new properties are ECMAScript (JavaScript) expressions that are encapsulated in a construct as a layout policy. A layout policy is referenced in CSS rules. The expressions composing a layout policy are woven together virtually in a constraint resolving system to perform a specified layout. New object specifications and a set of global objects defined in the constraint resolution script runtime environment enable powerful operations to be expressed succinctly resulting in more readable and compact layout specifications.
Introduction   top
Many in the web development community are dissatisfied with the layout capabilities in the current CSS standard and often resort to various client-side JavaScript solutions to fulfill their layout needs. There are several proposals before the W3C CSS Working group that aim to broaden CSS layout capabilities and reduce or eliminate the need for client-side JavaScript. These proposals employ well-defined strategies each with their own set of specific properties. If adopted, these proposals will increase substantially the size and complexity of CSS implementations as well as CSS syntax.

We propose a more general-purpose CSS layout solution that brings scripting unobtrusively into CSS. This solution enables a wide number of layout strategies to be defined in terms suitable to each. This general-purpose solution avoids the complexities that a multitude of independent solutions saddles on CSS implementers and developers.

CSS Scripting Layout Properties   top
A Scripting layout is encapsulated in a CSS layout-policy @-rule. A layout-policy @-rule defines a name that is referenced in layout-policy properties within rules. The body of a layout-policy @-rule is composed of properties with String values that are JavaScript expressions.
@layout-policy name
{
	initial-script:”arbitrary JavaScript”
	container-script:”arbitrary JavaScript”
	container-width:”…”
	container-height:”…”
	rectangle-attributes:”JavaScript Associative Array”
	left:”arbitrary JavaScript”
	horizontal-center:”…”
	right:”…”
	width:”…”
	top:”…”
	vertical-center:”…”
	bottom:”…”
	height:”…”
}

initial-script is arbitrary JavaScript that is executed to define values, functions, or any other JavaScript object that may then be referenced in the expressions of other constraint properties. It is executed only once per layout request.

container-script is arbitrary JavaScript that is executed to define values, functions, or any other JavaScript object that may then be referenced in the expressions of other constraint properties. It may be executed multiple times per layout request depending on the number of cycles required to resolve the constraints.

container-width and container-height properties are JavaScript expressions that must compute to a JavaScript Number, the value of which determines the width or height of the container. These properties may also be ordinary length or percentage values.

rectangle-attributes defines a JavaScript associative array. This associative array defines a set of name-value pairs whereby the name defines a new arbitrary attribute applicable to each child element of the container. The attribute value is a JavaScript expression.

The other constraint properties are JavaScript expressions and apply to each of the child elements of a container. These properties must compute to a JavaScript Number, the value of which determines the corresponding aspect of the child element. These properties may also be ordinary length or percentage values.

Constraint and rectangle attribute JavaScript expressions are evaluated lazily, at most once per distinct reference per layout resolution execution cycle. Each subsequent reference uses the result of the first evaluation. A reference is distinct on each child element on which the expression applies.

layout-policy @-rules are referenced by name in CSS rules.

A layout-policy property is set in a rule that is applied to a container html element in which case the layout policy constraints are applied to the container and its immediate child elements.

.container
{
	layout-policy:”policy1 policy2”
	initial-script:”arbitrary JavaScript”
	container-script:”arbitrary JavaScript”
	container-width:”…”
	container-height:”…”
}

layout-policy values may reference more than one policy. In this case subsequent policies override and augment values from preceding policies.

Other properties may be included in a rule to override or augment corresponding layout-policy @-rule values.

Child elements may override or augment the constraint values of a layout policy.

.child
{
	rectangle-attributes:”JavaScript Associative Array”
	left:”arbitrary JavaScript”
	…
}

A rectangle-attributes specification in a successive policy reference or on a rule overrides and augments the value in the initial policy. In other words, the rectangle-attributes value used in the computation is the amalgam of all the rectangle-attributes specified.

An overriding constraint with a value of none rescinds any prior constraint value rendering it unconstrained.

CSS Layout Objects and Interfaces   top
The expressions of the new CSS properties may reference new global objects defined in the CSS Layout JavaScript runtime environment.

A container object supports the CSSContainer interface that extends the Rectangle interface. A container object represents the container on which a layout policy is defined.

Rectangle
{
	readonly attribute double left;
	readonly attribute double right;
	readonly attribute double horizontal_center;
	readonly attribute double top;
	readonly attribute double bottom;
	readonly attribute double vertical_center;
	readonly attribute double width;
	readonly attribute double height;
	readonly attribute double preferred_width;
	readonly attribute double preferred_height;
	readonly attribute double current_width;
	readonly attribute double current_height;
	double em(in double x);
	double ex(in double x);
	double inch(in double x);
	double cm(in double x);
	double mm(in double x);
	double pc(in double x);
	double pt(in double x);
}

The preferred values refer to the sizes of a rectangle’s unconstrained values. The current values refer to the sizes of a rectangle prior to the application of any constraint.

CSSContainer : Rectangle
{
	readonly attribute CSSRectangleList children;
	readonly attribute long numChildren;
}

A CSSContainer maintains an ordered list of child elements. The individual child elements are represented in the global execution environment by objects that support the CSSRectangle interface that also extends the Rectangle interface. CSSRectangle objects support referencing rectangle-attributes properties by name. The object returned represents the computational result of the attribute value’s expression. CSSRectangle objects may be referenced by name from the CSSContainer returning either a CSSRectangleList or CSSRectangle. The CSSRectangle name value is the id of the HTML element that it represents.

CSSRectangle: Rectangle
{
	readonly attribute unsigned long position;
	readonly attribute String name;
	readonly attribute CSSRectangle predecessor;
	readonly attribute CSSRectangle successor;
}

CSSRectangle objects may be referenced abstractly in expressions through global objects rectangle, predecessor, and successor. rectangle represents the CSSRectangle object on which behalf a constraint or attribute expression is executing. predecessor, and successor represent the preceding and succeeding CSSRectangle objects of rectangle in the container’s ordered list either of which may be null. These values change throughout execution as expressions are evaluated.

A rectangles global object supports the CSSRectangleList interface. This object represents the ordered list of elements in a container. CSSRectangleList objects are immutable.

CSSRectangleList objects support indexing values to return corresponding CSSRectangle objects.

A sublist of a CSSRectangleList may be constructed from an existing CSSRectangleList by referencing it as a function with integer arguments:

CSSRectangleList(start, end, stride, count)

start and end indicate a range of index values. start may be greater than end indicating that the values are set in reverse order.

The lesser of start and end must be between zero and one less than the CSSRectangleList length.

The greater of start and end must be between one and the CSSRectangleList length.

stride indicates how many values to skip between successive values and count indicates how any values to include each stride. count must be less than or equal to stride.

Both stride and count default to one.

A new CSSRectangleList may also be constructed from an existing CSSRectangleList by referencing it as a function with an Array of integer values. The integer values represent the indices of values to include in the new CSSRectangleList.

Additionally, CSSRectangleList objects support referencing rectangle-attributes properties by name. A CSSRectangleListValue is returned to represent these values.

CSSRectangleList
{
 	readonly attribute unsigned long length;
	readonly attribute CSSRectangleListValue position;
	readonly attribute CSSRectangleListValue left;
	readonly attribute CSSRectangleListValue right;
	readonly attribute CSSRectangleListValue horizontal_center;
	readonly attribute CSSRectangleListValue top;
	readonly attribute CSSRectangleListValue bottom;
	readonly attribute CSSRectangleListValue vertical_center;
	readonly attribute CSSRectangleListValue width;
	readonly attribute CSSRectangleListValue height;
	readonly attribute CSSRectangleListValue preferred_width;
	readonly attribute CSSRectangleListValue preferred_height;
	readonly attribute CSSRectangleListValue current_width;
	readonly attribute CSSRectangleListValue current_height;
      	CSSRectangleListValue em(in double x);
      	CSSRectangleListValue ex(in double x);
      	CSSRectangleListValue inch(in double x);
      	CSSRectangleListValue cm(in double x);
      	CSSRectangleListValue mm(in double x);
      	CSSRectangleListValue pc(in double x);
      	CSSRectangleListValue pt(in double x);
	CSSRectangleListIterator iterator();
	CSSRectangleList remove(in int x);
	CSSRectangleList remove(in int x, int length);
	CSSRectangleList remove(in CSSRectangle x);
      	CSSRectangleList append(in CSSRectangle x);
      	CSSRectangleList append(in CSSRectangleList x);
	long indexOf(in CSSRectangle x);
	boolean contains(in CSSRectangle x);
}

A CSSRectangleListIterator provides a simple means to iterate through a CSSRectangleList.

CSSRectangleListIterator 
{
      readonly attribute unsigned long index;
      readonly attribute CSSRectangle next;
      readonly attribute boolean more;
}

A CSSRectangleListValue represents a set of values from a CSSRectangleList. CSSRectangleListValue objects support indexing values to return objects representing the corresponding values in the list.

CSSRectangleListValue : CSSRectangleListFilter
{
	readonly attribute double min;
	readonly attribute double max;
	readonly attribute double sum;
	readonly attribute double avg;
	readonly attribute double stddev;
	readonly attribute double variance;
	readonly attribute CSSRectangleList sort;
	readonly attribute CSSRectangleListFilter exclude;
	readonly attribute CSSRectangleListFilter truncate;
	readonly attribute CSSRectangleListFilter cumulate;
	readonly attribute CSSRectangleListValueRect rect;
}

A CSSRectangleListFilter represents a set of operations that may be executed on a CSSRectangleListValue. These operations return a CSSRectangleListFilterOp.

CSSRectangleListFilter
{
	CSSRectangleListOp eq;
	CSSRectangleListOp ne;
	CSSRectangleListOp le;
	CSSRectangleListOp lt;
	CSSRectangleListOp ge;
	CSSRectangleListOp gt;
}

A CSSRectangleListFilterOp represents a set of operations that may be executed on a CSSRectangleListFilter. These operations return a new CSSRectangleList.

CSSRectangleListFilterOp
{
	readonly attribute CSSRectangleList left;
	readonly attribute CSSRectangleList right;
	readonly attribute CSSRectangleList horizontal_center;
	readonly attribute CSSRectangleList top;
	readonly attribute CSSRectangleList bottom;
	readonly attribute CSSRectangleList vertical_center;
	readonly attribute CSSRectangleList width;
	readonly attribute CSSRectangleList height;
	readonly attribute CSSRectangleList preferred_width;
	readonly attribute CSSRectangleList preferred_height;
	readonly attribute CSSRectangleList current_width;
	readonly attribute CSSRectangleList current_height;
}

CSSRectangleListFilterOp objects may be referenced as a function with a single numeric argument.

Additionally, CSSRectangleListFilterOp objects support referencing rectangle-attributes properties by name. A CSSRectangleList is returned to represent the value of the operation.

A CSSRectangleListValueRect represents a set of operations that return a CSSRectangle object.

CSSRectangleListValueRect
{
	readonly attribute CSSRectangle min;
	readonly attribute CSSRectangle max;
}

The following examples illustrate valid usage:

 

Expression Return Value
container.em(1) The number of pixels in 1em of the container’s font
rectangles.width.max the maximum width of all the rectangles in the CSSRectangleList
rectangles.width.rect.max the CSSRectangle that has the maximum width of all the rectangles in the list
rectangles.width.sum the sum of the widths of the rectangles in the list
rectangles.width.gt(100) A new CSSRectangleList including only those CSSRectangle objects with a width greater than 100px
rectangles.preferred_width. gt.current_width A new CSSRectangleList including only those CSSRectangle objects with a preferred width greater than their current width.
rectangles.width.exclude. gt(100) A new CSSRectangleList excluding those CSSRectangle objects with a width greater than 100px
rectangles.width.truncate. gt(100) A new CSSRectangleList truncated at the position of the first CSSRectangle that has a width greater than 100px
rectangles.width.cumulate. gt(100) A new CSSRectangleList truncated at the position of the first CSSRectangle that has a width that when summed with all preceding CSSRectangle widths is greater than 100px
rectangles(0, rectangles.length, 2) A new CSSRectangleList composed of every other CSSRectangle in the list
rectangles(rectangles.length, 0) A new CSSRectangleList in reverse order

 

Resolving Constraints   top
The constraint resolver executes the initial-script JavaScript to initialize the execution environment. The initial-script values referenced in the container’s layout-policy references are executed in the order presented followed by the initial-script value of the container itself.

After initialization the constraints for all the contained elements are resolved deterministically according to how dependencies among the constraints are expressed in the constraint values.

For instance, the top side of an element may be affixed to the bottom side of its predecessor according to the following constraint:

top:”predecessor.bottom”

In this case, the execution of the top constraint is interrupted in order to determine the bottom constraint of the predecessor. The predecessor may or may not have an explicit bottom constraint. If the constraint exists, it is evaluated, the result returned, and the top constraint execution is resumed. If the bottom constraint does not exist then its value is determined via other related constraints in the vertical dimension, e.g. a top and height constraint. Once all constraints are satisfied a layout computation is complete.

The constraint resolver strategy involves the repeated computation of container size and child rectangle configurations within the container. The child rectangle geometries are held constant at their current values during the computation of the container size. Conversely, the container size is held constant during the computation of the child rectangle configurations.

A global Boolean value, sizing, is defined in the runtime environment to distinguish between the computation of the container size and the child rectangle configurations.

The constraint resolver uses a set of heuristics to determine when to terminate. The primary heuristic is to stop when the last container size computation is a repeat of some prior computation, but only when all child rectangles’ sizes are at least as large as their preferred sizes, i.e. their content does not overextend their bounds. However, this second heuristic is relaxed in the case where all rectangle preferred sizes are a repeat of some prior computation. In this case, it is probably impossible to configure the child rectangles without some overextension.

In under-constrained or abstractly constrained cases multiple solutions may be indicated by a particular layout specification and set of content. In this case, the solution with the least area container in which all child rectangles fit their bounds is chosen. In cases where child rectangles must overextend then the configuration with the largest area container prevails.

This constraint resolution strategy enables layout solutions for more abstractly constrained specifications heretofore unrealizable in CSS while retaining the ability to resolve more typically constrained layout specifications quickly and efficiently.

A detailed discussion of size negotiation among elements is beyond the scope of this paper, but the subject is worthy of thorough examination. Geometry management as prescribed by the X Toolkit Intrinsics XtQueryGeometry1 is a good reference for this subject.

In a conventional layout specification, constraints are explicit and convergence to a solution occurs in one or two iterations. In these instances layouts are resolved quickly consuming little CPU time.

More interestingly, specifications with more abstract constraints may be realized. These make use of feedback from suboptimal early generation solutions to improved succeeding generation solutions converging to a final solution in the manner of a genetic algorithm. Example specifications follow that illustrate layout policies that include these features. Moreover, these examples will show how layouts can adapt to changes in screen real estate from window resize events.

CSS Scripting Layout – Security issues   top
The global object for the CSS Layout JavaScript runtime environment is an ordinary Object. Not using the browser window as the global object reduces or eliminates the possibility of any serious cross-site scripting (XSS) attack. As such, the CSS Layout JavaScript runtime environment does not include any of the HTML DOM objects or any client-side JavaScript Browser objects, including:
  • Window
  • Navigator
  • Screen
  • History
  • Location
  • Document

Likewise, the Asynchronous JavaScript and XML (AJAX) XMLHttpRequest object is unavailable in this runtime environment.

CSS Scripting Layout - Sample Implementation   top
To validate the CSS Scripting Layout specification a sample implementation was coded as an extension to Google Chrome. A 12.7MB zipped windows XP compatible executable of this implementation is located at the eFORCE site here. In this implementation scripting layout is limited to the elements of container elements that are positioned absolutely.
Comments on Layout in the Current CSS Standard

Dissatisfaction with CSS layout capability has been expressed by many in the Web Development community10,11,12,13,14,15,16,17,18,19,20 including members of the W3C CSS WG.21,22,23 The CSS Scripting Layout Model described here resolves many, if not most, of these legitimate concerns.

CSS, apparently, was conceptualized to enable a newspaper-like layout in a Web page.24,25 Whatever the case, in regard to layout, it should not be considered controversial to state that CSS was influenced primarily by the demands of print media and little on User Interface demands. This is understandable since, at the time, the WWW was dominated by static print media. However, rendering Web content now involves much more than mere typography. The Web has evolved into a GUI rich environment in which JavaScript Libraries like YUI26, Dojo Toolkit27, Ext JS28 , and others29 that enable layout features not easily achievable or impossible to achieve in CSS.

Interestingly, thirty-two leaders in the fields of web design and development interviewed for a Teach the Web monograph ranked layout third in importance among 62 skills that students should know by the time they graduate.30 This is further testimony to the inadequate state of CSS regarding layout and a need for tools and, moreover, new standards that address its shortcomings.

There are several layout related proposals31,32,33,34,35 in various states of development before the CSS Working Group and others36 that are not. These proposals appear to address various shortcomings, but do so at the cost of greatly increasing complexity with the introduction of a multitude of new properties that are largely mutually exclusive. The layout specification described here could mitigate the need for some of these proposals.

Conclusion

Layout is inherently complex. Layout designs must adapt to any imaginable change in screen size, configuration, or composition in real-time. The possibilities are limitless. It is an impossible task for any single high-level specification, or even a small set of specifications, to cope with every conceivable circumstance.

The W3C's Web Content Accessibility Guidelines' checkpoint 3.3, a priority-2 checkpoint, states "use style sheets to control layout and presentation."37 With this directive in mind it is incumbent on the W3C to provide lower-level tools to enable the broadest set of layout strategies and handle unforeseeable eventualities. As a practical matter, the most suitable tools for this purpose must incorporate aspects of actual programming languages. We believe that the combination of a scripting language and the Object Interfaces presented here meets this challenge most effectively in conformance with W3C's design principles.38

1 X Toolkit Intrinsics - Chapter 6 - Geometry Management
http://lesstif.sourceforge.net/doc/super-ux/g1ae03e/part1/contents.html

10We need something better for layout.
http://ajaxian.com/archives/css-for-layout-another-rant

11Wanted: Layout System
http://meyerweb.com/eric/thoughts/2009/02/17/wanted-layout-system/

12Here are a short list of the some disadvantages of using pure CSS on web layouts and designs.
http://www.articlesbase.com/web-design-articles/advantages-and-disadvantages-of-using-css-833019.html

13There are lots of things which we’d like to put in CSS but don’t because CSS just can’t do many of the things we should expect of it. Real-world CSS is likely to get longer, not shorter, as CSS evolves toward… all manner of complex layouts for which we currently turn to table elements and layout systems...
http://alex.dojotoolkit.org/2008/08/css-variables-are-the-future/

14There’s also no indication that the [W3C CSS Working Group] has taken stabs exposing the expressive power that Microsoft exposed with CSS Expressions.
http://alex.dojotoolkit.org/2007/12/the-w3c-cannot-save-us/

15Epicycles: are complex css layouts the new nested tables?
http://www.brucelawson.co.uk/2006/are-complex-css-layouts-the-new-nested-tables/

16If CSS layout code were as easy to write as HTML tables, making the leap would be a no-brainer; …the tools that CSS provides are not suited to the layout tasks we want to accomplish.
http://carsonified.com/blog/design/tables-the-next-evolution-in-css-layout/

17Real world layout is still dependent on source order. Some effects (equal height columns) are still hard to do... CSS and web standards keep popping up where they're least expected.
http://www.paulhammond.org/2006/06/atmedia/ericmeyer

18… layouts still requires trickery and some magic even after all this time.
http://www.nczonline.net/blog/2007/10/08/css-sucks/

19The fundamental problems with CSS3
http://mattwilcox.net/archive/entry/id/1031/

20Why CSS needs to borrow from programming languages
http://mattwilcox.net/archive/entry/id/991/

21Layout Is Expensive
http://fantasai.inkedblade.net/weblog/2009/layout-is-expensive/

22Web layout standards so far have taken a lot from the history of formatting printed documents and very little from the history of designing user interfaces. We need more of a balance...
http://dbaron.org/log/2007-09#e20070920a

23WaSP Community CSS3 Feedback 2008 - Layout
http://fantasai.inkedblade.net/style/discuss/wasp-feedback-2008#layout

24Chapter 20 of Cascading Style Sheets, designing for the Web
http://www.w3.org/Style/LieBos2e/history/

25Cascading HTML style sheets -- a proposal
http://www.w3.org/People/howcome/p/cascade.html

26An open-source JavaScript library for building richly interactive web applications
http://en.wikipedia.org/wiki/Yahoo!_UI_Library

27dojox.layout Experimental and Extended Layout Widgets
http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/layout/README

28A cross-browser JavaScript library for building rich internet applications
http://www.extjs.com/

2910 Promising CSS Framework That Worth A Look
http://www.webdesignbooth.com/10-promising-css-framework-that-worth-a-look/

30Perspectives on web education: What to teach the next generation of web professionals.
http://teachtheweb.com/monograph.php

31Template Layout Module
http://www.w3.org/TR/css3-layout/

32Multi-column Layout Module
http://www.w3.org/TR/css3-multicol/

33Table Model
http://www.w3.org/TR/CSS2/tables.html#table-display

34Flexible Box Layout Model
http://www.w3.org/TR/css3-flexbox/

35Grid Positioning Module Level 3
http://www.w3.org/TR/css3-grid/

36Matrix Layout
http://snook.ca/technical/matrix-layouts/

37Checkpoint 3.3
http://www.w3.org/TR/WCAG10-TECHS/#tech-style-sheets

38What is a good standard?
http://www.w3.org/People/Bos/DesignGuide/introduction

 
 
Example 1 – Introductory Concepts   back
The HTML in Example 1 produces the screen shot in Figure 1.

The rendering of this example demonstrates many of the features of CSS Script Layout.

Example 1 – Nested Containers

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
  <title>Nested Containers</title>

<style type="text/css">

@layout-policy pack_column {
    initial-script: "\
        var margin=container.em(0.5);\
    ";
    rectangle-attributes: "{\
        'topOffset':0\
    }";
    horizontal-center:"container.width/2";
    top: "rectangle.topOffset+margin\
        +(predecessor ? predecessor.bottom : 0)";
    container-height: "margin*(rectangles.length+1)\
        +rectangles.height.sum+rectangles.topOffset.sum";
    container-width: "2*margin+rectangles.width.max";
}
@layout-policy override {
    initial-script: "\
        var margin=container.em(0.25)\
    ";
    horizontal-center:none;
    left:"margin";
}
@layout-policy pack_row {
    initial-script: "\
        var margin=0;\
    ";
    vertical-center:"container.height/2";
    left:"margin+(predecessor ? predecessor.right : 0)";
    container-width:"margin*(rectangles.length+1)\
        +rectangles.width.sum";
    container-height:"2*margin+rectangles.height.max;";
}
.body {
    layout-policy: 'pack_column';
    position:relative;
    border:1px black dashed;
    padding:0px;
}
.container {
    layout-policy: 'pack_row';
    initial-script: "margin=container.ex(2);";
    position:absolute;
    border:1px black solid;
    padding:0px;
 }
.container1 {
    layout-policy: 'pack_column override';
    width:130px;
    position:absolute;
    border:1px black dotted;
    margin:0px;
    padding:0px;
 }
.text {
    position:absolute;
    border:1px black dashed;
    padding:0px;
 }
.extension {
    rectangle-attributes: "{\
        'topOffset':'container.em(1)+margin'\
    }";
    width:200px;
    padding:10px;
 }
</style>

</head>

<body class='body'>
<span class='text'>test nesting containers</span>

<span class='container'>
a nested container that overrides the default margin.<br>
this text is in a relative span and<br>is not constrained by the container.
<span class='text'>
this&nbsp;span&nbsp;of&nbsp;text&nbsp;is&nbsp;centered&nbsp;vertically
</span>
<button style='position:absolute;'>button</button>

<span class='container1'>
relative text
<span class='text extension'>
this span has an explicit padding and width specification and a topOffset rectangle attribute.
</span>
<span class='text' style='width:150px'>
notice also the override policy specification overrides the margin and alignment...
</span>
<span class='text'>hence the spans are now left aligned and the margin is smaller.
</span>

</span>

</span>
</body>
</html>

Figure 1 - Nested Containers

This layout renders in less than 32 milliseconds on a Dell LATITUDE D630 Laptop (Intel Core 2 Duo T7500 2.20GHz, 2.49 GB RAM) running MS Windows XP V2002 Service Pack 3.

 
 
Example 2 – Three-Column Presentation   back
The Common Three-Column Presentation 2,3,4 HTML in Example 2 produces the screen shot in Figure 2.

The rendering of this example demonstrates how elements may be referenced by their HTML id in the script. Additionally, in this example there is no dependency on the order of the elements in the HTML as to where they are rendered. This is an important point for those concerned with Search Engine Optimization (SEO).

The totality of the layout here is distributed among the rules of each element in the window. Notable here is that the desired result is clearly evident from the constraint specifications within each rule and presented rationally without resorting to hacks or tricks and without any compromises. All elements are free to resize as required by their content.

Example 2 – Common Three-Column Presentation

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
  <title>Three Column Layout</title>
<style type="text/css">

@layout-policy entire_window {
initial-script: "\
var margin=4;\
var content_area=container.content_area;\
var header=container.header;\
var header_content=container.header_content;\
var footer=container.footer;\
var footer_content=container.footer_content;\
var primary_navigation=container.primary_navigation;\
var secondary_navigation=container.secondary_navigation;\
var min_content_width = 200;\
var max_content_width = 600;\
";
container-script: "\
var content_width = container.width-2*margin-\
	primary_navigation.width-secondary_navigation.width;\
";
container-height:100%;
container-width:100%;
}

#body {
    position:relative;
    layout-policy: 'entire_window';
    border:0px black solid;
    margin:0px;
    padding:0px;
}

#content_area {
    top:"header.bottom";
    bottom:"footer.top";
    left:"primary_navigation.right";
    width:"content_width<min_content_width?min_content_width:\
	content_width>max_content_width?max_content_width:content_width";
    position:absolute;
    border:1px black solid;
}

#primary_navigation {
    left:"margin";
    width:"rectangle.ex(10)+8+container.width*0.1;";
    top:"header.bottom";
    bottom:"footer.bottom";
    position:absolute;
    border:1px black solid;
}

#secondary_navigation {
    top:"header.bottom";
    bottom:"footer.bottom";
    left:"content_area.right";
    width:"rectangle.ex(8)+8+container.width*0.1;";
    position:absolute;
    border:1px black solid;
}

#header {
    top:"margin";
    height:"header_content.height+2*margin";
    left:"margin";
    right:"secondary_navigation.right";
    position:absolute;
    border:1px black solid;
}

#header_content {
    width:"header.width-2*margin";
    vertical-center:"header.vertical_center";
    horizontal-center:"header.horizontal_center";
    position:absolute;
    border:1px black solid;
}

#footer {
    height:"footer_content.height+2*margin";
    top:"header.bottom+Math.max(content_area.preferred_height,\
primary_navigation.preferred_height-footer.height,\
secondary_navigation.preferred_height-footer.height)";
    left:"primary_navigation.right";
    right:"secondary_navigation.left";
    position:absolute;
    border:1px black solid;
}

#footer_content {
    width:"footer.width-2*margin";
    horizontal-center:"footer.horizontal_center";
    vertical-center:"footer.vertical_center";
    position:absolute;
    border:1px black solid;
}

  </style>
</head>


<body id='body' class='body'>


<span id='content_area'>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem 
accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae 
ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt 
explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut 
odit aut fugit, sed quia consequuntur magni dolores eos qui ratione 
voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum 
quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam 
eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat 
voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam 
corporis suscipit laboriosam, nisi ut aliquid ex ea commodi 
consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate 
velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum 
fugiat quo voluptas nulla pariatur?
</span>

<span id='primary_navigation'>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse 
massa lacus, consectetur vitae commodo sed, aliquet eget sapien. 
Quisque erat odio, convallis non aliquam vitae, pulvinar a diam. 
In hac habitasse platea dictumst. Aenean non tempor ipsum. Sed scelerisque 
fringilla ligula at laoreet. Cras posuere metus at ligula posuere in 
consequat lorem malesuada. Sed id lobortis nulla.
</span>

<span id='secondary_navigation'>
Fusce enim sem, ornare in ornare nec, ornare sed neque. Ut sed felis 
orci, in pretium lectus. Cras nec felis sed nibh venenatis dignissim in 
sit amet massa. Cras sodales mollis arcu, quis sagittis tellus euismod 
eu. Nulla facilisi. Aliquam ultrices consequat rutrum. Quisque pharetra 
adipiscing porta. Nullam sem urna, fringilla tempus aliquet a, ornare 
non risus.
</span>

<span id='header_content'>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum 
vestibulum fringilla interdum. Fusce suscipit vehicula nunc, nec 
sagittis risus mollis non. Cras non rhoncus magna. Vestibulum ante 
ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; 
Nullam eleifend sapien velit. Cum sociis natoque penatibus et magnis 
dis parturient montes, nascetur ridiculus mus. Quisque gravida erat vel 
eros iaculis ac rhoncus nibh tincidunt.
</span>

<span id='footer_content'>
Fusce quis lacus ligula, a dictum metus. Aenean risus odio, sagittis ac 
posuere vel, viverra et erat. Aenean eros lorem, fringilla ut aliquam 
id, pulvinar et nulla. Pellentesque imperdiet eros non odio faucibus 
fringilla. Nam ut nulla at tellus vestibulum mattis.</span>
<span id='header'</span>
<span id='footer'></span>

</body>

</html>

Figure 2 - Common Three Column Presentation

The Three-Column layout renders in 16 milliseconds on a Dell LATITUDE D630 Laptop (Intel Core 2 Duo T7500 2.20GHz, 2.49 GB RAM) running MS Windows XP V2002 Service Pack 3.

2 In Search of the Holy Grail
http://www.alistapart.com/articles/holygrail/
3 CSS Three Column Liquid Layout
http://www.manisheriar.com/holygrail/index.htm
4 Why CSS should not be used for layout
http://www.flownet.com/ron/css-rant.html
 
 
Example 3 – HTML Table comparison   back
The HTML in Example 3 produces the screen shot in Figure 3. In the first row the layout policy accounts for and minimizes a cell’s total area rather than relying on a cell’s width as in the HTML table below it. Deficiencies with table layout are described in Poorly Laid-out Tables.5

Example 3 – Script vs. HTML Table

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
  <title>Script vs. HTML Table</title>
<style type="text/css">

@layout-policy pack_column {
initial-script: "\
var margin=1;\
var space=(rectangles.length+1)*margin;\
";
width:"container.width";
height:"rectangle.preferred_height";
top:"margin+(predecessor ? predecessor.bottom : 0)";
container-height:"space+rectangles.preferred_height.sum";
container-width:"rectangles.preferred_width.max";
}

@layout-policy least_area_horizontal {
initial-script: "\
var margin=2;\
var space=(rectangles.length-1)*margin;\
var governor=-0.24;\
var accelerator=2;\
";
container-script: "\
var reserved=rectangles.pliant.eq(false);\
var pliant=rectangles.pliant.ne(false);\
var usable_width=container.width-space-reserved.preferred_width.sum;\
var area_ratio=usable_width/pliant.area.sum;\
";
rectangle-attributes: "{\
'current_area':'rectangle.current_width*rectangle.current_height',\
'preferred_area':'rectangle.preferred_width*rectangle.preferred_height',\
'area':'rectangle.preferred_area*accelerator+rectangle.current_area*governor',\
'max_width':'rectangle.preferred_width>=rectangle.width?rectangle.preferred_width:rectangle.width',\
'pliant':'rectangle.pliant!==false&&rectangle.preferred_width<=rectangle.current_width'\
}";
top:0;
height:"container.height";
width:"rectangle.pliant?rectangle.area*area_ratio:rectangle.preferred_width";
left:"predecessor ? predecessor.right+margin : 0";
container-width:"rectangles.max_width.sum+space";
container-height:"rectangles.preferred_height.max";
}
.body {
    padding:0px;
    margin:0px;
    layout-policy: 'pack_column';
    border:1px black solid;
    position:relative;
    container-width:100%;
}
/* script layout rules */
.text {
    margin:0px;
    position:absolute;
    border:1px black solid;
    padding:0px;
}
.row {
    layout-policy: 'least_area_horizontal';
    position:absolute;
    border:2px black dotted;
    margin:0px;
    padding:0px;
}
/* html table rules */
.table {
    position:absolute;
    border:2px black dotted;
    margin:0px;
    padding:0px;
}
.ttext {
    vertical-align:top;
    margin:0px;
    border:1px black solid;
    padding:0px;
}

  </style>
</head>

<body id='body' class='body'>

<div id='top' class='row'>

<span id='text2' class='text'>
<img src="small.gif"><img src="small.gif"><img src="big.gif"><img src="big.gif">
</span>

<span id='text1inner' class='text'>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum 
vestibulum fringilla interdum. Fusce suscipit vehicula nunc, nec 
sagittis risus mollis non. Cras non rhoncus magna. Vestibulum ante 
ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; 
Nullam eleifend sapien velit. Cum sociis natoque penatibus et magnis 
dis parturient montes, nascetur ridiculus mus. Quisque gravida erat vel 
eros iaculis ac rhoncus nibh tincidunt.
</span>

<span id='text1inner' class='text'>
Fusce quis lacus ligula, a dictum metus. Aenean risus odio, sagittis ac 
posuere vel, viverra et erat. Aenean eros lorem, fringilla ut aliquam 
id, pulvinar et nulla. Pellentesque imperdiet eros non odio faucibus 
fringilla. Nam ut nulla at tellus vestibulum mattis. Fusce at tincidunt 
nunc. Aliquam pharetra faucibus nisl, auctor dignissim tortor vehicula 
rutrum. Pellentesque tincidunt mi ut elit congue sit amet eleifend dui 
euismod. Donec luctus, lorem et placerat pulvinar, justo nunc dapibus 
lorem, id porta velit diam sed diam. Nulla et erat libero. Donec auctor 
sapien in dolor pretium ornare.
</span>
</div>

<table id='table' class='table'>
<tr class='ttext'>

<td id='text2' class='ttext'>
<img src="small.gif"><img src="small.gif"><img src="big.gif"><img src="big.gif">
</td>

<td id='text1inner' class='ttext'>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum 
vestibulum fringilla interdum. Fusce suscipit vehicula nunc, nec 
sagittis risus mollis non. Cras non rhoncus magna. Vestibulum ante 
ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; 
Nullam eleifend sapien velit. Cum sociis natoque penatibus et magnis 
dis parturient montes, nascetur ridiculus mus. Quisque gravida erat vel 
eros iaculis ac rhoncus nibh tincidunt.
</td>
<td id='text1inner' class='ttext'>
Fusce quis lacus ligula, a dictum metus. Aenean risus odio, sagittis ac 
posuere vel, viverra et erat. Aenean eros lorem, fringilla ut aliquam 
id, pulvinar et nulla. Pellentesque imperdiet eros non odio faucibus 
fringilla. Nam ut nulla at tellus vestibulum mattis. Fusce at tincidunt 
nunc. Aliquam pharetra faucibus nisl, auctor dignissim tortor vehicula 
rutrum. Pellentesque tincidunt mi ut elit congue sit amet eleifend dui 
euismod. Donec luctus, lorem et placerat pulvinar, justo nunc dapibus 
lorem, id porta velit diam sed diam. Nulla et erat libero. Donec auctor 
sapien in dolor pretium ornare.
</td>
</tr>
</table>

</body>
</html>

Figure 3 - Script vs. HTML Table

The layout in Figure 3 renders in less than 32 milliseconds on a Dell LATITUDE D630 Laptop (Intel Core 2 Duo T7500 2.20GHz, 2.49 GB RAM) running MS Windows XP V2002 Service Pack 3.

5Poorly Laid-out Tables
http://nothings.org/computer/badtable/
 
 
 
Example 4 – Advanced Concepts – Near Optimal Least Area Layout   back
The HTML in Example 4 produces the screen shots in Figures 4 and 5. The Near Optimal Least Area layout nests containers to a depth of four with varying layout policies for each. Notable here is that in the execution of the layout policies the constraint resolver searches for and converges on solutions that minimize the area taken by the rectangles for a given width of the window. There is no guarantee that the most optimal layout is found, but only one that approaches it which is likely acceptable if not imperceptible from the optimum to the average viewer.

A description of the actual layout policies and how they function is beyond the scope of this paper. More to the point is that layouts may be developed and shared among developers without the need for end users to understand the execution details. De facto or even de jure standards could emerge from this process.

Example 4 – Near Optimal Least Area

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
  <title>Near Optimal Least Area</title>
<style type="text/css">

@layout-policy pack_column {
initial-script: "\
var margin=1;\
var space=(rectangles.length+1)*margin;\
";
width:"container.width";
height:"rectangle.preferred_height";
top:"margin+(predecessor ? predecessor.bottom : 0)";
container-height:"space+rectangles.preferred_height.sum";
container-width:"rectangles.preferred_width.max";
}

@layout-policy proportional_width {
initial-script: "\
var margin=2;\
var governor=-0.25;\
var accelerator=2;\
var space=(rectangles.length-1)*margin;\
";
container-script: "\
var reserved=rectangles.pliant.eq(false);\
var pliant=rectangles.pliant.ne(false);\
var usable_width=container.width-space-reserved.preferred_width.sum;\
var area_ratio=usable_width/pliant.area.sum;\
";
rectangle-attributes: "{\
'area':'rectangle.preferred_width*rectangle.preferred_height*accelerator+\
rectangle.current_width*rectangle.current_height*governor',\
'max_width':'rectangle.preferred_width>=rectangle.width?rectangle.preferred_width:rectangle.width',\
'pliant':'rectangle.pliant!==false&&rectangle.preferred_width<=rectangle.current_width'\
}";
top:0;
height:"container.height";
width:"rectangle.pliant?rectangle.area*area_ratio:rectangle.preferred_width";
left:"predecessor ? predecessor.right+margin : 0";
container-width:"rectangles.max_width.sum+space";
container-height:"rectangles.preferred_height.max";
}

@layout-policy proportional_height {
initial-script: "\
var margin=2;\
var governor=-0.25;\
var accelerator=2;\
var space=(rectangles.length-1)*margin;\
";
container-script: "\
var reserved=rectangles.pliant.eq(false);\
var pliant=rectangles.pliant.ne(false);\
var usable_height=container.height-space-reserved.preferred_height.sum;\
var area_ratio=usable_height/pliant.area.sum;\
";
rectangle-attributes: "{\
'area':'rectangle.preferred_width*rectangle.preferred_height*accelerator+\
rectangle.current_width*rectangle.current_height*governor',\
'pliant':'rectangle.pliant!==false&&rectangle.preferred_height<=rectangle.current_height'\
}";
top:0;
width:"container.width";
height:"rectangle.pliant?rectangle.area*area_ratio:rectangle.preferred_height";
top:"predecessor ? predecessor.bottom+margin : 0";
container-height:"rectangles.preferred_height.sum+space";
container-width:"rectangles.preferred_width.max";
}

.body {
    padding:0px;
    margin:0px;
    layout-policy: 'pack_column';
    border:1px black solid;
    position:relative;
    container-width:100%;
}
.column {
    position:absolute;
    padding:0px;
    margin:0px;
    layout-policy: 'proportional_height';
    border:2px black solid;
}
.text {
    margin:0px;
    position:absolute;
    border:1px black solid;
    padding:0px;
 }

.row {
    layout-policy: 'proportional_width';
    position:absolute;
    border:2px black dotted;
    margin:0px;
    padding:0px;
}

  </style>
</head>

<body id='body' class='body'>

<div id='top' class='row'>

<span id='textimagemixlong' class='text'>
<img src="small.gif" border="0"> <img src="small.gif" border="0"> 
<img src="small.gif" border="0"> <img src="small.gif" border="0">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse 
massa lacus, consectetur vitae commodo sed, aliquet eget sapien. 
Quisque erat odio, convallis non aliquam vitae, pulvinar a diam.
<img src="small.gif" border="0"> <img src="small.gif" border="0"> 
<img src="small.gif" border="0"> <img src="small.gif" border="0">
In hac habitasse platea dictumst. Aenean non tempor ipsum. Sed 
scelerisque fringilla ligula at laoreet.
</span>

<span id='text2' class='text'> 
<img src="small.gif"> <img src="small.gif"> 
<img src="small.gif"> <img src="small.gif"> 
<img src="big.gif"> <img src="big.gif"> 
<img src="big.gif"> <img src="big.gif"> 
</span> 

<span id='text1inner' class='text'>
Cras posuere metus at ligula posuere
<img src="small.gif" border="0">
in consequat
<img src="small.gif" border="0">
lorem malesuada.
<img src="small.gif" border="0">
Sed id lobortis nulla.
<img src="small.gif" border="0">
Fusce enim sem, ornare in ornare nec, ornare sed neque. Ut sed felis 
orci, in pretium lectus. Cras nec felis sed nibh venenatis dignissim in 
sit amet massa. Cras sodales mollis arcu, quis sagittis tellus euismod eu.
</span>

<div id='inner' class='column'>

<span id='text1inner' class='text'>
Nulla facilisi. Aliquam ultrices
<img src="small.gif" border="0">
consequat
<img src="small.gif" border="0">
rutrum.
<img src="small.gif" border="0">
Quisque pharetra
<img src="small.gif" border="0">
adipiscing porta. Nullam sem urna, fringilla tempus aliquet a, ornare non risus.
</span>

<span id='text2inner' class='text'>
<img src="small.gif" border="0"> This is a nice simple paragraph of text,
<img src="small.gif" border="0"> 
which has been chosen to  height as the other cell, since they are about equally long.
</span>

</div>

</div>

<div id='bottom' class='row'>

<span id='textbr' class='text'>
This paragraph has encoded *<br>
line-breaks after each asterisk *<br>
to confound the layout.  Content *<br>
management systems may include *<br>
content with embedded html or *<br>
images that confound sensitive *<br>
css specifications. Content *<br>
authors often are unaware of where*<br>
their content is consumed.*<br>
</span>

<span id='textimagemixlong' class='text'>
<img src="small.gif" border="0"> <img src="small.gif" border="0"> 
<img src="small.gif" border="0"> <img src="small.gif" border="0">
Sed ut perspiciatis unde omnis iste natus error sit voluptatem 
accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae 
ab illo inventore veritatis et quasi architecto beatae vitae dicta
<img src="small.gif" border="0"> <img src="small.gif" border="0"> 
<img src="small.gif" border="0"> <img src="small.gif" border="0">
sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur 
aut odit aut fugit,
</span>

<div id='innerbottom' class='column'>

<div id='innerbottomrow' class='row'>

<span id='smallinner' class='text'>
<img src="small.gif" border="0"> <img src="small.gif" border="0"> 
<img src="small.gif" border="0"> <img src="small.gif" border="0">
</span>

<span id='text1inner' class='text'>
sed quia consequuntur magni
<img src="small.gif" border="0">
dolores eos
<img src="small.gif" border="0">
qui ratione
<img src="small.gif" border="0">
voluptatem sequi
<img src="small.gif" border="0">
nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit 
amet, consectetur, adipisci velit, sed quia non numquam eius modi 
tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. 
Ut enim ad minima
</span>

<span id='text2inner' class='text'>
<img src="small.gif" border="0">
veniam, quis
<img src="small.gif" border="0">
nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut 
aliquid ex ea commodi consequatur? Quis autem
</span>

</div>

<span id='text2inner' class='text'>
<img src="small.gif" border="0">
vel eum iure reprehenderit qui in ea
<img src="small.gif" border="0"> 
voluptate velit esse quam nihil molestiae consequatur, vel illum qui 
dolorem eum fugiat quo voluptas nulla pariatur?
</span>

</div>

</div>

</body>
</html>

Figure 4 - Near Optimal Least Area Layout

Example 4 is an extreme case demonstrating the ability of the containers to cooperate in the layout resolution. Note that no explicit heights or widths are specified. In this instance the layout adjusts to the content and vice versa in a virtuous cycle.

In situations where content is generated by a CMS team that is separate from the Web design team6 or where content may be reused in many applications not known in advance7,8 it may be necessary to leave element sizes unspecified and accommodate their natural sizes in a self-organizing layout. Otherwise poor renderings may result as demonstrated in the HTML table in Example 3.

In Figure 5 a resize widening the window results in the layout adjusting accordingly.

Figure 5 - Near Optimal Least Area Layout. Layout adjusts to increased window width.

The layout in Examples 4 and 5 renders in somewhere between 0.2 and 2.0 seconds, usually toward the lower end, depending on the window size as it unpredictably effects the rate of convergence. This may be acceptable performance for some applications.9

6 laying out images consistently within a design is difficult; especially when you hand the keys over to someone else to fill in the content.
http://www.alistapart.com/articles/figurehandler/
7 we must build pages that adapt to unpredictable content and unpredictable users.
http://blog.rebeccamurphey.com/2009/02/13/css-vs-tables-maybe-the-design-is-to-blame/
8 The challenge is writing CSS that looks good if you don't know ahead of time what your content is going to be.
http://rondam.blogspot.com/2009/02/css-and-meaning-of-life.html
9 Fast is better than slow. Slow is better than closed.
http://alex.dojotoolkit.org/2009/08/some-orthodox-heresies/

 

posted @ Thursday, July 16, 2009 10:56 AM | Feedback (21)

Home
Contact
RSS 2.0 Feed
Login
May, 2010 (1)
April, 2010 (1)
March, 2010 (1)
July, 2009 (1)
CSS Scripting Layout (rss)

Powered by: