Frontal's Layout Scheme

From Frontal Wiki

Jump to: navigation, search

Looking at a Frontal document, how does the Frontal renderer decide where to place and how to size the visual representation of each element? What is Frontal's layout scheme?

Contents

The Normal Layout

This scheme is very close to that of HTML. We start by reading the document from the first element and giving it an initial placement at the top, left corner of the stage (the canvas Flash gives us to work with). Then we move to the next element and place it below the first and left-aligned to the stage. We continue until we've processed the entire document.

For example, here we have three 'div' elements. As described, they line up in a column pinned to the top, left corner of the stage.

<style><![CDATA[
    div
        {
            width: 20%;
            height: 20%;
            border-width: 1px;
            border-color: gray;
            background-color: orange;
            margin: 1px;
        }
]]></style>
<div /><div /><div />

Note that these 'div' elements line up in a column even though they're all listed on the same line in the Frontal document. That's because the way elements are laid out in the document doesn't effect how they'll be laid out in the rendered site, except in cases where the document layout effects the relationship of one element to another. In those cases, the rendered layout will be effected as well.

To follow up on this last note, what happens if we put a div inside of another div? Well, our layout scheme is the same as before but now the "stage" for the children elements isn't the whole stage provided by Flash -- it's just that portion covered by their parent.

For example, below we add three div elements inside the second of our original divs. See how they line up just like the first three did, but are confined to their parent.

<style><![CDATA[
    div
        {
            width: 20%;
            height: 20%;
            border-width: 1px;
            border-color: gray;
            background-color: orange;
            margin: 1px;
        }
]]></style>
<div />
<div>
    <div /><div /><div />
</div>
<div />

This pattern will continue forever. For example, add three divs inside the second of the new divs just added.

<style><![CDATA[
    div
        {
            width: 20%;
            height: 20%;
            border-width: 1px;
            border-color: gray;
            background-color: orange;
            margin: 1px;
        }
]]></style>
<div />
<div>
    <div />
    <div>
        <div /><div /><div />
    </div>
    <div />
</div>
<div />

The Box Model

Wherever an element is placed, it's given a rectangle in which to draw itself. The size of this rectangle depends on the margin, borders, padding, width and height of the element. In fact it's the sum of these. How these different measurements are laid out within the element's rectangle is called the "box model", and for Frontal, it's exactly the same as it is for HTML.

The box model says that to determine an element's rectangle, we'll start with a rectangle that just encompasses its width and height. It's in the top left corner of this first rectangle that any children content will be placed, thus we'll call this first rectangle the "content rectangle".

Then, according to the box model, we'll wrap the content rectangle with a padding rectangle. The width of this second rectangle is the left padding, plus the width of the content rectangle, plus the right padding. The height is the top padding, plus the height of the content rectangle, plus the bottom padding. An element's background color is applied to this padding rectangle.

Next, according to the box model, come the borders. Their width and height are added to the total rectangle, and don't overlap the padding or margin in any way.

And finally, the box model says the whole thing is then surrounded by margins.

Putting all of this together, the width of a rendered element is the left margin, plus the left border, plus the left padding, plus the width, plus the right padding, plus the right border, plus the right margin.

And the height is the top margin, plus the top border, plus the top padding, plus the height, plus the bottom padding, plus the bottom border, plus the bottom margin.

In this example, we show a 'div' first with only a width and a height, then with padding, then with a border, and then with margin. You can see how this rectangle grows as the parts of the box model are given non-zero lengths.

<div style="width: 100px; height: 50px; background-color: red;" />
<div style="width: 100px; height: 50px; padding: 10px; background-color: green;" />
<div style="width: 100px; height: 50px; padding: 10px; border-width: 5px; background-color: blue;" />
<div style="width: 100px; height: 50px; padding: 10px; border-width: 5px; margin: 20px; background-color: orange;" />

Something to note here is that while all four divs in the above example have the same width and height styles, the rectangles they occupy are different sizes. This can sometimes be confusing until you know about the box model.

Positioning

An element can override the position calculated for it by the layout scheme by using the styles 'left', 'right', 'top' and 'bottom'. Changing the position of an element changes the layout of any remaining elements.

Consider our first example, let's set the right edge of the second container to 100% of the stage. This will move it right as far as it can go. It will not affect the position of the third element though because the third element wants to draw itself just below the previous element and left-aligned to the stage like normal.

<style><![CDATA[
    div
        {
            width: 20%;
            height: 20%;
            border-width: 1px;
            border-color: gray;
            background-color: orange;
            margin: 1px;
        }
]]></style>
<div /><div style="right: 100%;" /><div />

If we change the second 'div' to have its top edge at 0px, then the third element will be affected because now the bottom edge of the second element has moved.

<style><![CDATA[
    div
        {
            width: 20%;
            height: 20%;
            border-width: 1px;
            border-color: gray;
            background-color: orange;
            margin: 1px;
        }
]]></style>
<div /><div style="right: 100%; top: 0px;" /><div />

Stretching an Element by Positioning Opposite Edges

We saw in the previous section how an element can reposition itself in the normal layout. By repositioning opposite edges, we can stretch an element.

For example, here we position the left and right edges of the second element. We set the width to 'auto' so that it is calculated via the other dimensions (left and right in this case).

<style><![CDATA[
    div
        {
            width: 20%;
            height: 20%;
            border-width: 1px;
            border-color: gray;
            background-color: orange;
            margin: 1px;
        }
]]></style>
<div /><div style="left: 10%; right: 90%; width: auto;" /><div />

Resize your browser while looking at this example to see how the div's width changes. This is because resizing the browser changes the stage width and so also changes the calculation of "10%" and "90%".

We can also position the top and bottom, which will affect the normal flow of the other divs.

<style><![CDATA[
    div
        {
            width: 20%;
            height: 20%;
            border-width: 1px;
            border-color: gray;
            background-color: orange;
            margin: 1px;
        }
]]></style>
<div /><div style="top: 25%; bottom: 75%; height: auto;" /><div />

Finally, note that we can specify all four edges to stretch an element's width and height. For example:

<style><![CDATA[
    div
        {
            width: 20%;
            height: 20%;
            border-width: 1px;
            border-color: gray;
            background-color: orange;
            margin: 1px;
        }
]]></style>
<div style="left: 5%; right: 95%; top: 5%; bottom: 95%; width: auto; height: auto;" />

Floating Elements

So far, we've considered normal layouts. There are also "floating left" and "floating right" layouts.

When the floating left layout is in effect (done by setting the float style to "left"), the first element is still positioned at the top, left corner of the stage. But now the next element will be placed to its right and top-aligned with it. This will continue until the next element would extend beyond the right edge of the stage, at which point, the element will be moved down below any previous elements and left aligned to the stage. Then the process repeats.

Here's an example. Try resizing the width of your browser to see how it affects the layout. When the browser gets too narrow to hold an element, the element flows to the next row. When the browser gets wide enough to hold an element on a lower row, it floats up to a higher row.

<style><![CDATA[
    div
        {
            width: 200px;
            border-width: 1px;
            border-color: gray;
            background-color: orange;
            margin: 1px;
            float: left;
        }
]]></style>
<div style="height: 10%;" />
<div style="height: 15%;" />
<div style="height: 20%;" />
<div style="height: 25%;" />
<div style="height: 10%;" />
<div style="height: 15%;" />
<div style="height: 20%;" />
<div style="height: 25%;" />

A similar effect may be had with the floating right layout. In this case though, the first element starts with its upper right corner in the upper right corner of the stage. The subsequent elements line up to the left of this element until they hit the left edge of the stage.

As an example, change the float style above to "right;"

float: right;

Combining Left Floating, Right Floating and Normal Elements

When left and right floating elements are siblings, an additional rule is added to the layout scheme, which is that these elements won't overlap.

Here is an example to show that. We add the style class "right" for right floating elements.

<style><![CDATA[
    div
        {
            width: 200px;
            border-width: 1px;
            border-color: gray;
            background-color: orange;
            margin: 1px;
            float: left;
        }
    .right
        {
            background-color: deepskyblue;
            float: right;
        }
]]></style>
<div style="height: 10%;" /><div class="right" style="height: 10%;" />
<div style="height: 15%;" /><div class="right" style="height: 15%;" />
<div style="height: 20%;" /><div class="right" style="height: 20%;" />
<div style="height: 25%;" /><div class="right" style="height: 25%;" />
<div style="height: 10%;" /><div class="right" style="height: 10%;" />
<div style="height: 15%;" /><div class="right" style="height: 15%;" />
<div style="height: 20%;" /><div class="right" style="height: 20%;" />
<div style="height: 25%;" /><div class="right" style="height: 25%;" />

When normal elements are added, they are laid out as if there were no floating left or floating right elements. The floating elements though will be affected. They are affected in that their top edge cannot be above the bottom of any normal elements that preceded them.

So in this example, we add a style class "normal" for normally laid-out elements. (This is done by setting the float style to "none".)

<style><![CDATA[
    div
        {
            width: 200px;
            border-width: 1px;
            border-color: gray;
            background-color: orange;
            margin: 1px;
            float: left;
        }
    .right
        {
            background-color: deepskyblue;
            float: right;
        }
    .normal
        {
            background-color: darkseagreen;
            float: none;
            alpha: 0.8;
            width: 100px;
            height: 15%;
        }
]]></style>
<div class="normal" />
<div style="height: 10%;">A</div>
<div class="normal" />
<div class="right" style="height: 10%;">B</div>
<div style="height: 15%;" /><div class="right" style="height: 15%;" />
<div style="height: 20%;" /><div class="right" style="height: 20%;" />
<div style="height: 25%;" />
<div style="height: 10%;" /><div class="right" style="height: 10%;" />
<div style="height: 15%;" /><div class="right" style="height: 15%;" />
<div style="height: 20%;" /><div class="right" style="height: 20%;" />
<div style="height: 25%;" /><div class="right" style="height: 25%;" />
<div class="normal">C</div>

Note how in this example, the first floating left element (labeled "A") does not rise above the normally laid-out sibling preceding it. Neither does the floating right element "B" rise above the second normally laid-out element.

Finally, note how the three normally laid-out elements are positioned as if there were no floating elements at all.

Clearing the Floating Groups

At any point, we may clear the groups of floating left and floating right elements. This has the effect of positioning any further floating elements in a new group below any previous floating elements.

For example, here we add the style clear set to "left" to the fifth element "B" causing the last four floating left elements to be always laid out below the first four.

<style><![CDATA[
    div
        {
            width: 200px;
            border-width: 1px;
            border-color: gray;
            background-color: orange;
            margin: 1px;
            float: left;
        }
]]></style>
<div style="height: 10%;" />
<div style="height: 15%;" />
<div style="height: 20%;" />
<div style="height: 25%;">A</div>
<div style="height: 10%; clear: left; background-color: darkorange;">B</div>
<div style="height: 15%; background-color: darkorange;" />
<div style="height: 20%; background-color: darkorange;" />
<div style="height: 25%; background-color: darkorange;" />

Setting the clear style to "left" will not have an effect on any right floating elements just as setting clear to "right" will not affect left floating elements. For example:

<style><![CDATA[
    div
        {
            width: 200px;
            border-width: 1px;
            border-color: gray;
            background-color: orange;
            margin: 1px;
            float: left;
        }
    .right
        {
            background-color: deepskyblue;
            float: right;
        }
]]></style>
<div style="height: 10%;" /><div class="right" style="height: 10%;" />
<div style="height: 15%;" /><div class="right" style="height: 15%;" />
<div style="height: 20%;" /><div class="right" style="height: 20%;" />
<div style="height: 25%;">A</div><div class="right" style="height: 25%;" />
<div style="height: 10%; clear: left; background-color: darkorange;">B</div><div class="right" style="height: 10%;" />
<div style="height: 15%; background-color: darkorange;" /><div class="right" style="height: 15%;" />
<div style="height: 20%; background-color: darkorange;" /><div class="right" style="height: 20%; clear: right; background-color: lightskyblue;" />
<div style="height: 25%; background-color: darkorange;" /><div class="right" style="height: 25%; background-color: lightskyblue;" />

Setting clear to "both" will clear both the floating left and floating right groups.

This raises another aspect of clear which is that the value of the float style effects its behavior. So, if "clear: left;" is applied to a floating right element, then any further floating right elements will be positioned below any previous floating left elements. Setting "clear: right;" on a floating left element, has a converse effect.

The clear style may also be set on a normally laid-out element, in which case it'll be placed below whichever floating groups were specified by the value.

For example, in the previous example, change the "clear: left;" style in the fifth floating-left element "B" to "clear: right;" and note how it and the remaining floating left elements will not rise above the fourth floating right element. This is the case even when they float up into the same row as the fourth floating left element "A".

As a further example, return to the second example in the section #Combining Left Floating, Right Floating and Normal Elements above. Add the style "clear: left;" to the element "C". Now try "clear: right;". And finally, try "clear: both;". It's interesting to see how the element is laid out with the groups of floating elements.

If you're having trouble seeing the "C" element, then change the selector 'div' to "document > div" and add a rule set to your style sheet to enable scroll bars:

    document { scroll: auto; }

Pinned Elements

We've seen how elements position themselves relative to the top left corner of their parent element, or the stage if their parent element is the document element. It's also possible to position them on the stage with the pin-to-stage style set to "true" or to another element with the pin-to-container style set to the 'id' of another element.

When these styles are set, the element is no longer considered when laying out its siblings. Nor is it considered in laying out any sibling that may be in the target container. You should realize though that the Flash DisplayObject that is used to display the element remains a child of the element's parent, and so it's affected by things like its mask and its order in the display list.

Here's an early example from the section #The Normal Layout. First run it as shown with pin-to-stage on div "B" set to false.

<style><![CDATA[
    div
        {
            width: 20%;
            height: 20%;
            border-width: 1px;
            border-color: gray;
            background-color: orange;
            margin: 1px;
        }
]]></style>
<div id="A">A</div>
<div>
    <div />
    <div>
        <div /><div style="pin-to-stage: false; background-color: red;">B</div><div />
    </div>
    <div />
</div>
<div />

Now set it to true.

<style><![CDATA[
    div
        {
            width: 20%;
            height: 20%;
            border-width: 1px;
            border-color: gray;
            background-color: orange;
            margin: 1px;
        }
]]></style>
<div id="A">A</div>
<div>
    <div />
    <div>
        <div /><div style="pin-to-stage: true; background-color: red;">B</div><div />
    </div>
    <div />
</div>
<div />

Normally laid out, it was quite small but pinned to the stage, it's the same size as div "A" and completely obscures it. This is because it defines "20%" relative to the stage and not its normal containing block.

In this example, styles like 'left', 'right', 'top' and 'bottom' are also calculated relative to the stage. Add the styles "width: auto; height: auto; left: 0px; top: 0px; right: 100%; bottom: 100%;" to div "B" while "pin-to-stage" is set to true. Now "B" fills the stage but doesn't obscure all of the other divs. Add "z-index: 100;" to try to remedy this. It only partly works. Why? It's because this pinned element is still a grandchild of another div and so never able to be higher in the display list than its ancestors.

The "pin-to-container" style works similarly to "pin-to-stage" but relative to another container instead of the stage. Let's change the previous example to pin div "B" to div "A".

<style><![CDATA[
    div
        {
            width: 20%;
            height: 20%;
            border-width: 1px;
            border-color: gray;
            background-color: orange;
            margin: 1px;
        }
]]></style>
<div id="A">A</div>
<div>
    <div />
    <div>
        <div /><div style="pin-to-container: A; background-color: red;">B</div><div />
    </div>
    <div />
</div>
<div />

Now "B" is positioned relative to the top left corner of "A" and its size is 20% that of "A."

Add the style "margin: auto;" to div "B" to see how margins are calculated relative to a pinned element's target.

Specifying Dimensions

So far, we've seen how we can specify our dimensions (be it margin, border, padding, width or height) using a pixel value like "100px," a percentage value like "10%," or using "auto." Let's look more closely at these as well as a format that we haven't see yet which is a percentage of unallocated space that looks like "100% leftover".

Pixel Dimensions

Setting dimensions using pixels is very straightforward. Here we place a fixed-size div 100 pixels out from the top, left corner of the stage.

<style><![CDATA[
	div
		{
			width: 100px;
			height: 100px;
			left: 100px;
			top: 100px;
			background-color: blueviolet;
		}
]]></style>
<div />

Percentage Dimensions

A problem with pixels is that they do not compensate for changes in stage dimensions. So for example, how would we place this div at the bottom, right corner of the stage? We can't use pixels because unless the stage is a fixed size, the bottom, right corner changes depending on the size of the browser. We do know, though, that the bottom, right corner is always at 100% of the width and 100% of the height of the stage. So, if we set the right and bottom edges of our div at 100% then it will be positioned where we want it.

<style><![CDATA[
	div
		{
			width: 100px;
			height: 100px;
			right: 100%;
			bottom: 100%;
			background-color: darkviolet;
		}
]]></style>
<div />

So that's good but what if we need to calculate a value that involves both percentages and pixels? For example, what if we want the div in the bottom, right corner to actually be 100 pixels to the left of that point and 50 pixels above it? This is where margins come in handy. By mixing percentages and pixel dimensions in our margins and our edge positions, we can achieve flexible but precise layouts.

<style><![CDATA[
	div
		{
			width: 100px;
			height: 100px;
			right: 100%;
			bottom: 100%;
			margin-right: 100px;
			margin-bottom: 50px;
			background-color: darkviolet;
		}
]]></style>
<div />

Auto Dimensions

The third format is "auto." The rules for interpreting what "auto" means for a dimension are taken from CSS and are a bit complex but can be very useful.

First, when the width or height style is set to "auto" and the element has "intrinsic" dimensions then that intrinsic dimension is used. An element has intrinsic dimensions whenever it has a natural or preferred size. For example, the intrinsic dimensions of a 'video' tag are the dimensions of the video. As another example, the intrinsic dimensions of an 'img' tag are the dimensions of the loaded image, SWF or Flash library symbol.

In this example we load an image with the img tag. All img tags have width and height set to "auto" by default through The Default Frontal Style Sheet and this is why when the image loads its element is the same size as the image. We prove this by floating it left with another div. Note how that other div jumps when the image loads because the img element changes size. (Look sharp and clear your browser's cache to see this jump. It will happen quickly.)

<style><![CDATA[
	div
		{
			width: 100px;
			height: 100px;
			background-color: violet;
		}
]]></style>
<img style="float: left;" src="http://www.frontalcode.com/assets/images/image_1.jpg" />
<div style="float: left;" />

Okay, that was pretty straightforward but now the rules get a little hairy. In this discussion, we'll focus on our width-related styles but a similar discussion pertains to the height-related styles.

So, if an element has a "float" style of "none" (the default) or if its parent has a "stack" style of "layout", then a style of "left: auto;" is the same as "left: 0px;" and "right: auto;" is the same as "right: 100%;".

Then, if there is one "auto" value among the styles margin-left, border-left, padding-left, width, padding-right, border-right and margin-right then we deduce its value from the fact that the sum of those values must be equal to our target width. Our target width is the value of the right style or 100% if not specified minus the value of our left style or 0 if not specified.

If more than one value in that list of styles is "auto" including width, then all but the width are set to 0 and the width is deduced from the calculation above.

If margin-left and margin-right are auto then we use the above equation to calculate their sum and split it evenly between the two.

So, that was a quite complex and difficult to remember set of rules so instead let's give some examples of when these rules are useful.

First, let's take advantage of the rule that says if there are two auto values, then each is assigned half of the remaining target width. This means that if we set the left and right margin to auto, then we can center an element. In this example, we center a div at the top of the browser.

<style><![CDATA[
	div
		{
			width: 100px;
			height: 100px;
			background-color: mediumvioletred;
			margin-left: auto;
			margin-right: auto;
		}
]]></style>
<div />

And if we want to center it top to bottom then we can also set the top and bottom margins to auto. (Here we use the shortcut margin style to set all four styles at once.)

<style><![CDATA[
	div
		{
			width: 100px;
			height: 100px;
			background-color: gold;
			margin: auto;
		}
]]></style>
<div />

Another useful case is setting the width or height to auto. In this case, if the element does not have intrinsic dimensions, then they are assigned any unused space from the target width or height. So in this example, the width and height of the div are set to everything except for the 20% margins.

<style><![CDATA[
	div
		{
			width: auto;
			height: auto;
			background-color: thistle;
			margin: 20%;
		}
]]></style>
<div />

That's pretty useful because it allows us to use up whatever is leftover of the target width and height. It's so useful in fact that Frontal has expanded on the concept with "leftover" percentages.

Leftover Dimensions

When we talk about percentage dimensions, what are we actually measuring a percentage of? We're measuring the width of the containing div. So here we have a div with a gray border that has a width of 200 pixels and a height of 100 pixels. It contains two divs that are each 100% of this width and 50% of the height (and so fill it).

<style><![CDATA[
	#outer
		{
			width: 200px;
			height: 100px;
			border-color: gray;
			border-width: 2px;
			margin: auto;
		}
	.inner
		{
			width: 100%;
			height: 50%;
		}
]]></style>
<div id="outer" >
	<div class="inner" style="background-color: skyblue;" />
	<div class="inner" style="background-color: forestgreen;" />
</div>

Now, let's give the inner divs 10 pixel margins.

<style><![CDATA[
	#outer
		{
			width: 200px;
			height: 100px;
			border-color: gray;
			border-width: 2px;
			margin: auto;
		}
	.inner
		{
			width: 100%;
			height: 50%;
			margin: 10px;
		}
]]></style>
<div id="outer" >
	<div class="inner" style="background-color: skyblue;" />
	<div class="inner" style="background-color: forestgreen;" />
</div>

What happened?! That's not what we want. What we want is the margin to be removed from the width and not added to it. In other words, adding a margin had no effect on our calculation of the width or height of our inner div's; they are still 100% the width of the outer div and 50% of its height.

So what do we do? Let's try "auto" for the width and height since we know that in the case of a single "auto" value amongst all the width or height dimensions, it evaluates to the leftover width or height.

<style><![CDATA[
	#outer
		{
			width: 200px;
			height: 100px;
			border-color: gray;
			border-width: 2px;
			margin: auto;
		}
	.inner
		{
			width: auto;
			height: auto;
			margin: 10px;
		}
]]></style>
<div id="outer" >
	<div class="inner" style="background-color: skyblue;" />
	<div class="inner" style="background-color: forestgreen;" />
</div>

Well, that half worked. It got the width right but the height is twice what we want. Why is this? It's because the "auto" values for the "height" styles are evaluated independently for each of the two inner div's. This means each one evaluates to the full leftover height but in fact we only want half of that for each of the inner div's.

If we were using HTML this is where we would have to begin rethinking our layout. We could use a table or a combination of JavaScript and DHTML. Or we could try the new-and-not-so-well-adopted (a typical phrase when targeting all the major browsers and all their popular versions) table-layout styles. But with Frontal we have another option which is the "leftover" modifier on a percentage dimension.

The thing we like about "auto" is how it can be used to calculate "everything left over from the width of the containing div." That is, we know each div has a total width of its left margin, plus the left border, plus the left padding, plus the width, plus the right padding, plus the right border, plus the right margin. So in the case of width being "auto" and everything else having a fixed width, we can do a difference and assign a number for "auto." (Here by "fixed" we mean that the calculation of those styles is unaffected by any other styles on that element or its siblings. So "100px" or "20%" are considered "fixed".)

This is very handy but the idea can be extended. We know that the containing div has a width (and height) in which all of its children must fit. So it's possible to take that width and subtract from it all of the fixed width dimensions of all of the children and come up with the unallocated or leftover space. In Frontal, we can access this calculation with the "leftover" dimension style.

In our example above, we wanted the height of each of the two inner div's to be half of the leftover height of the outer div's height. We can write this as "height: 50% leftover;" like in the next example. We can also replace the "auto" value of the "width" style with "100% leftover."

<style><![CDATA[
	#outer
		{
			width: 200px;
			height: 100px;
			border-color: gray;
			border-width: 2px;
			margin: auto;
		}
	.inner
		{
			width: 100% leftover;
			height: 50% leftover;
			margin: 10px;
		}
]]></style>
<div id="outer" >
	<div class="inner" style="background-color: skyblue;" />
	<div class="inner" style="background-color: forestgreen;" />
</div>

Now we get what we were looking for!

By using "leftover" we can achieve some very useful layouts that are difficult to achieve in HTML. For example, this shows the basic layout of the Frontal workspace editor - a very useful layout that takes full advantage of the browser's dimensions.

<!-- 
    Create our header. It has a fixed width and height in that the
    calculation of these dimensions is unaffected by other styles
    on it or its siblings.
-->
<div style="width: 100%; height: 100px; background-color: orange;" />
 
<!-- 
    This div will use whatever part of the stage is unused by the header. 
-->
<div style="width: 100%; height: 100% leftover;">
 
    <!--
        This div will contain our editor's text input and some buttons.
        It uses whatever space is leftover after we place the right nav
        below.
    -->
    <div style="width: 100% leftover; height: 100%; float: left;">
 
        <!--
            This is our text input. It uses whatever space is leftover
            after we place our buttons below it.
        -->
        <text style="border-width: 1px; height: 100% leftover; width: 100%; flash-text-type: input;">content</text>
 
        <!--
            This is our button holder. It has fixed dimensions.
        -->
        <div style="width: 100%; height: 20px;">
             <text style="float: right;">Save | Save As... | Submit</text>
        </div>
    </div>
 
    <!--
        This div stands in for our right nav. It has fixed dimensions.
    -->
    <div style="width: 200px; height: 400px; background-color: gray; float: left;" />
</div>

Using Leftover with Floating Elements

Using leftover dimensions on floating elements is complicated by the fact that floating elements do not necessarily have a fixed layout. Depending on their size, their number and their containing divs' dimensions, they may lay out in any number of rows. Since leftover is a calculation based on the siblings sharing a row or column, this multiple layout characteristic means that leftover may be calculated in different ways.

To solve this problem, Frontal takes a two step approach: first, we layout the elements as if the leftover dimensions were all zero. Then we calculate leftover based on how much each floating element may expand horizontally and vertically without affecting that layout. These expansion amounts then become the leftover calculations.

For example, let's start with a div that contains two floating divs.

<style><![CDATA[
	#outer
		{
			width: 400px;
			height: 300px;
			margin: auto;
			border-width: 1px;
		}
	#inner1
		{
			float: left;
			background-color: blue;
			width: 100px;
			height: 100px;
		}
	#inner2
		{
			float: left;
			background-color: green;
			width: 100px;
			height: 100px;
		}
]]></style>
<div id="outer">
	<div id="inner1" />
	<div id="inner2" />
</div>

Now let's change the dimensions of the inner1 div to have width and height styles of "100% leftover".

<style><![CDATA[
	#outer
		{
			width: 400px;
			height: 300px;
			margin: auto;
			border-width: 1px;
		}
	#inner1
		{
			float: left;
			background-color: blue;
			width: 100% leftover;
			height: 100% leftover;
		}
	#inner2
		{
			float: left;
			background-color: green;
			width: 100px;
			height: 100px;
		}
]]></style>
<div id="outer">
	<div id="inner1" />
	<div id="inner2" />
</div>

So what's happened here is that Frontal initially laid out the two divs as if inner1 had zero width and zero height. This resulted in a layout where inner1 and inner2 were adjacent to one another and in the same row. Then, using that layout as a constraint, Frontal has calculated how much inner1 could expand horizontally and vertically. These expansion amounts became the leftover values and in our example, we have let inner1 use all of that space by setting the width and height styles to "100% leftover".

Here's a more complex example using left and right floating div's. Here there are four inner div's. The first is floating left and has width and height styles of "100% leftover". All the other divs have fixed dimensions and the third one is floating right. First, let's look at the result.

<style><![CDATA[
	#outer
		{
			width: 400px;
			height: 300px;
			margin: auto;
			border-width: 1px;
		}
	#inner1
		{
			float: left;
			background-color: blue;
			width: 100% leftover;
			height: 100% leftover;
		}
	#inner2
		{
			float: left;
			background-color: green;
			width: 100px;
			height: 100px;
		}
	#inner3
		{
			float: right;
			background-color: yellow;
			width: 100px;
			height: 100px;
		}
	#inner4
		{
			float: left;
			background-color: red;
			width: 350px;
			height: 100px;
		}
]]></style>
<div id="outer">
	<div id="inner1" />
	<div id="inner2" />
	<div id="inner3" />
	<div id="inner4" />
</div>

To see how this layout was achieved, first set the dimensions of the inner1 div to have zero width and height. Now it should be apparent how the leftover was calculated - it's the space that can be inserted without causing the left and right div to re-flow onto new rows.

Caveat Regarding Leftover Dimensions

Note that the calculation of leftover can get complex particularly when the dimensions of a containing element are affected by its children and those children are using leftover dimensions. It creates a chicken-and-egg scenario in which much iteration is necessary to find a stable solution. In such a case, it can cause the Frontal renderer to give up on the layout because it is taking too long. If you ever see a message like "10 renders run in one frame. Use the document option rendersPerFrameLimit to increase the limit" then this is the likely scenario. If this happens to you then see if perhaps you are using a leftover dimension that would be perfectly fine using a fixed dimension. Then propagate this change to the containing elements and children elements if possible. Oftentimes, this will solve the "10 renders" issue.


Personal tools
Get Adobe Flash player