Contents
4.4 Example - Normal Box - Overflow
4.5 Example - Normal Box - Overflow Auto
5. Progress So Far Towards Solution
7. Shrink To Fit - display:table;
7.1 Explanation of Shrink To Fit Rules
8. Progress So Far Towards Solution
9. Float and Absolute : Shrink-To-Fit
9.1 The same rules apply as for tables
1. Introduction
I have been trying to create a multi-level tree. Nothing unusual about that.
I have the following requirements:-
- Each entry in the tree would appear on its own line, and, critically, text lines should not wrap, except at explicit line-breaks.
- Each group of entries would be wrapped in a bordered
div
element. - The bordered
div
element should at least fit its contents. I.e. the text should notoverflow
the border of thediv
. - The
div
and any parent boxes should be as wide as, but no wider than, the longest (non-wrapped) text line inside. - These rules should apply even where the tree is inside a
div
that hasoverflow:auto;
set on it.
Here is a screen-shot of an example (except for rule 5).
I thought this would be a hard problem. But in fact it was relatively easy to solve, because there is already a feature of the CSS specification called "shrink-to-fit", which does a lot of the work for me.
In looking at this, I had occasion to try to fathom the CSS2 Visual Formatting Model. Not an easy read at all, and I still don't understand it. Or at least, my understanding fades very quickly after reading it. No wonder it is so hard to implement.
I thought I would share with you the results of my study. My explanations need quite a lot of polishing, but I don't have the time, so I thought would share with
2. The Main Requirements
To re-iterate, the two main requirements are:-
- there should be no word wrapping, and lines should not break, except at a
br
,p
etc - the borders of each of the parent
div
elements should shrink-wrap to the longest text line, with no overflow.
I am not here going to talk about border, padding, or content boxes. Just the basic calculation principles for "content width". I am also not going to try to deal with all the subtle rendering quirks which browsers may show.
3. Solution
Lets get to the solution first, because the rest of this blog entry is so long.
My preferred solution uses a float and in this example uses white-space: nowrap
(and the deprecated nowrap
element property for IE) to force lines not to be wrapped.
The shrink to fit
rules for floated elements then do the job of shrink-wrapping the box borders onto these unwrapped lines.
<h2>Solution - Float Left</h2>
<div style="border:1px solid blue; padding:10px; width:200px; height:150px; overflow:auto; white-space:nowrap;" noWrap>
<div style="border:1px solid purple; padding:10px; float:left;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
One slight niggle is that because the element is taken out of the flow, the padding seems a bit messed-up, particularly on (gasp) Opera.
For instance, it seems that Opera's padding is too much or too little on the right, and when a vertical overflow happens, it seems to loose track of the padding at the bottom when a scrollbar is added.
This may be standards compliant, but it looks a little scruffy.
I have tackled this with a bit of a hack: a white bordered div rather than padding, for top left and right borders, and a separate cleared div
at the bottom. This is the only cross-browser answer I could find, and it may be a problem if you need transparent borders, as I think IE has an issue with that.
Any better ideas?
<h2>Solution - Float Left - White Border / Div At Bottom</h2>
<div style="border:1px solid blue; padding:0px; width:200px; height:150px; overflow:auto; white-space:nowrap;" noWrap>
<div style="border:solid white; border-width:10px 10px 0px 10px; float:left;">
<div style="border:1px solid purple; padding:10px;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
<div style="clear:both; height:10px; overflow:hidden;"></div>
</div>
4. Normal boxes
4.1 Formatting Rules
The starting point for understanding the solution is to understand the rules that apply to normal boxes(called Block-level, non-replaced elements in normal flow).
They obey (or should obey) two basic rules:-
- They don't fit the width of their content, they are either the width of (or a pecentage of the width of) their containing element, or the fixed width you have set for them.
- If any text content within them cannot be word-wrapped to fit within the parent width, or any box content has a fixed width greater than the parent width, it will overflow (and look ugly).
The one notorious exception to these rules is Internet Explorer : if Internet Explorer cannot fit content within a box, it will expand that box until it can fit that content. More on this later.
To quote Section 10.3.3 of the CSS2 Specification:
The following constraints must hold among the used values of the other properties:-
'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' + scrollbar width (if any) = width of containing block
If 'width' is not 'auto' and 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + scrollbar width (if any) (plus any of 'margin-left' or 'margin-right' that are not 'auto') is larger than the width of the containing block, then any 'auto' values for 'margin-left' or 'margin-right' are, for the following rules, treated as zero.
If all of the above have a computed value other than 'auto', the values are said to be "over-constrained" and one of the used values will have to be different from its computed value. If the 'direction' property of the containing block has the value 'ltr', the specified value of 'margin-right' is ignored and the value is calculated so as to make the equality true. If the value of 'direction' is 'rtl', this happens to 'margin-left' instead.
If there is exactly one value specified as 'auto', its used value follows from the equality.
If 'width' is set to 'auto', any other 'auto' values become '0' and 'width' follows from the resulting equality.
If both 'margin-left' and 'margin-right' are 'auto', their used values are equal. This horizontally centers the element with respect to the edges of the containing block.
The "scrollbar width" value is only relevant if the user agent uses a scrollbar as its scrolling mechanism. See the definition of the 'overflow' property.
Very difficult to comprehend, I found.
In order to comprehend it, I found this table useful, as it is important to understand the range of possible values each item in the formula supports. When I refer to fixed, I mean that it does not depend on any other box's width; em
widths are relative to the calculated font-size, so treat them as fixed for these purposes.
style | possible widths | can have auto? |
margin-left | auto; fixed; or % of width of containing block | yes |
border-left-width | fixed | no |
padding-left | fixed; or % of width of containing block | no |
width | auto; fixed; or % of width of containing block | yes |
padding-right | fixed; or % of width of containing block | no |
border-right-width | fixed | no |
margin-right | auto; fixed; or % of width of containing block | yes |
scrollbar | 16px(IE); 15px(Others) | n/a |
The basic calculation is top down:-
- Calculate the width and height of the viewport (the window)
- Calculate the width of the
html
within the viewport (ignore if you are IE in quirks mode). - Calculate the width of the
body
withinhtml
(or viewport if you are IE in quirks mode). - For each child-box of
body
, calculate its width - For each of those child-boxes, get its child-boxes
- For each of those child-boxes, calculate its width, then goto 5.
As noted, the calculated width is going to either be fixed
or or width of (or percentage of width of) its parent box (which itself ay be fixed or dependent on its parent box)
.
4.2 Overflow
If a box cannot be made to fit, then an overflow will happen (i.e. the box will overflow the calculated width of the parent box).
Overflow can happen in two ways:-
- The box width is calculated as wider than its container, that box will overflow its container.
- You have some
non-breaking
text within that box, which is longer than the width of the box, that text will overflow its box.
To quote the CSS spec again:-
Generally, the content of a block box is confined to the content edges of the box. In certain cases, a box may overflow, meaning its content lies partly or entirely outside of the box, e.g.:
A line cannot be broken, causing the line box to be wider than the block box.
A block-level box is too wide for the containing block. This may happen when an element's 'width' property has a value that causes the generated block box to spill over sides of the containing block.
An element's height exceeds an explicit height assigned to the containing block (i.e., the containing block's height is determined by the 'height' property, not by content height).
A box is positioned absolutely.
It has negative margins.
4.3 Example - Normal Box
The starting point is that the browser will try to fit everything into the parent box.
Here is an example for equal or lesser widths:-
<h2>Example - Static - Width Auto</h2>
<h3>Expands to fit viewport</h3>
<div style="border:1px solid blue; padding:10px;">
<div style="border:1px solid purple; padding:10px;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
<h2>Example - Static - Inner Width Percentage</h2>
<h3>Expands to fit viewport</h3>
<div style="border:1px solid blue; padding:10px;">
<div style="border:1px solid purple; padding:10px; width:50%;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
<h2>Example - Static - Inner Width Fixed</h2>
<h3>Expands to fit viewport</h3>
<div style="border:1px solid blue; padding:10px;">
<div style="border:1px solid purple; padding:10px; width:200px;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
4.4 Example - Normal Box - Overflow
Here are some overflow examples.
Remeber that Internet Explorer does not do overflow, and will expand the box and parent boxes if minimum width of the box is greater than the parent.
<h2>Example - Static - Width 200px - Inner Box 250px</h2>
<h3>Box overflows for all browsers except IE, and text overflows box!</h3>
<h3>IE expands each box separately to fit</h3>
<div style="border:1px solid blue; padding:10px; width:200px;">
<div style="border:1px solid purple; padding:10px; width:250px;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand.Expand.Expand.Expand.Expand.Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand.Expand.Expand.Expand.</p>
</div>
</div>
</div>
Here is how it looks on Opera and IE:-
4.5 Example - Normal Box - Overflow Auto
When you set overflow:auto
on an element then scrollbars will be added and the overflowing box will be hidden. However, importantly for my problem:-
- If the box width is
auto
then it is calculated based on the actual visible width of its parent, and not the potential width if the inner box were allowed to expand to the potential unlimited width afforded byoverflow:auto
. See example 1 below. This is logical as normal boxes depend on a container box for width auto calculations, so if you take that away, what do you have : infinity. - Unbreakable text will still overflow its box.
<h2>Example - Static - Width 200px/Overflow Auto - Inner Box Auto</h2>
<h3>Box overflows for all browsers except IE, and text overflows box!</h3>
<h3>IE expands each box separately to fit</h3>
<div style="border:1px solid blue; padding:10px; width:200px; overflow:auto;">
<div style="border:1px solid purple; padding:10px;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand.Expand.Expand.Expand.Expand.Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand.Expand.Expand.Expand.</p>
</div>
</div>
</div>
<h2>Example - Static - Width 200px/Overflow Auto - Inner Box 250px</h2>
<h3>Box overflows for all browsers except IE, and text overflows box!</h3>
<h3>IE expands each box separately to fit</h3>
<div style="border:1px solid blue; padding:10px; width:200px; overflow:auto;">
<div style="border:1px solid purple; padding:10px; width:250px;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand.Expand.Expand.Expand.Expand.Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand.Expand.Expand.Expand.</p>
</div>
</div>
</div>
This is how these look on Opera. I don't give examples for IE as all boxes expand.
5. Progress So Far Towards Solution
What we have learned so far is that:-
The overflow rules prevent use of normal boxes as a solution for my problem, because boxes do not fit to contents.
Internet Explorer can get towards my solution, because its boxes do expand; the only down-side is that boxes expand to their content size and not the largest of the sub-boxes, so the result is boxes of staggered widths.
6. Forcing lines not to break
One of the first aspects that is going to be required in any solution, is a means of stopping word-wrap. This is needed because:-
- Internet Explorer's non-standard overflow behaviour still tries to wrap words to the minimum possible.
- All of the other solutions specified below (which use a
shrink to fit
rule in the CSS2 rules) will shrink to fit to the smallest possible size, if a containing box is too small, and we want the "smallest possible" that in which words are not wrapped.
I started a quick look at this issue on various search engines, and it feels like the tip of the iceberg.
There are potential issues with all of the options below, including failure to validate, lack of consistent cross-browser support or implementation, etc, etc, so the options below are really to experiment with, and perfection (however I may define it) may not be achievable.
The results are pretty good in the most recent browsers as far as I can tell.
6.1 white-space: nowrap;
This is the standards way of doing it.
Setting white-space
to nowrap
means that lines are only broken at explicit line ends. E.g. br
, end of a p
. Lines are not word-wrapped.
I am not sure how widely this is supported yet, but it is the future.
A visit to Quirksmode will probably tell.
<div style="border: 1px solid blue; overflow:auto; width:200px; height:100px;">
<p style="white-space: nowrap">Please do not wrap. Please do not wrap. Please do not wrap. Please do not wrap. Please do not wrap. Please do not wrap.</p>
</div>
6.2 noWrap
The second way is the deprecated noWrap
attribute.
This is a deprecated property which Microsoft at least continues to apply to BODY, DD, DIV, DT, TD, TH
HTML 4 only applies it to TD, and TH, and deprecates it in favour of the CSS 'white-space' attribute.
As noted, Internet Explorer still supports this on DIV
elements, and it seems to work quite well. It is also inherited by all children, so you only need to use it once on the outer div
. Needless to say you can only use this for Internet Explorer.
<div style="border: 1px solid blue; overflow:auto; width:200px; height:100px;">
<div nowrap><p>Please do not wrap. Please do not wrap. Please do not wrap. Please do not wrap. Please do not wrap. Please do not wrap.</p></div>
</div>
6.3
The next way is
(non-breaking space).
I am not sure if all browsers will always obey this, and I am not sure I would recommend it, given the availability of other options stated above.
<div style="border: 1px solid blue; overflow:auto; width:200px; height:100px;">
<p>Please do not wrap. Please do not wrap</p>
</div>
6.4 <nobr>
I dont know much about this element. I think it is old, and non-standard, but it is an option, although it does not validate.
<div style="border: 1px solid blue; overflow:auto; width:200px; height:100px;">
<p><nobr>Please do not wrap. Please do not wrap. Please do not wrap. Please do not wrap. Please do not wrap. Please do not wrap.</nobr></p>
</div>
6.5 Conclusion
For my purposes I am going to stick with the first two options, which should hopefully cover IE and other browsers. For belt and braces
I might add the nobr
element.
7. Shrink To Fit - display:table;
7.1 Explanation of Shrink To Fit Rules
So we can now force lines to their full length. Now we need to force boxes (and their parent boxes) to stretch to their contents (except for IE of course) to get over the overflow
problem.
I looked on the internet, and the solution I came accross was to use display:table
.
What it does is to cause browsers to treat the element and each sub-child as cell
/ column
(I am not sure which, perhaps both) and to apply the table formatting rules. Extracted below:-
[1] Calculate the minimum content width (MCW) of each cell: the formatted content may span any number of lines but may not overflow the cell box. If the specified 'width' (W) of the cell is greater than MCW, W is the minimum cell width. A value of 'auto' means that MCW is the minimum cell width.
[2] Also, calculate the "maximum" cell width of each cell: formatting then content without breaking lines other than where explicit line breaks occur.
[3] For each column, determine a maximum and minimum column width from the cells that span only that column.
[4] The minimum is that required by the cell with the largest minimum cell width (or the column 'width', whichever is larger). The maximum is that required by the cell with the largest maximum cell width (or the column 'width', whichever is larger).
[5] For each cell that spans more than one column, increase the minimum widths of the columns it spans so that together, they are at least as wide as the cell. Do the same for the maximum widths. If possible, widen all spanned columns by approximately the same amount.
[6]This gives a maximum and minimum width for each column.
The width of the table is then calculated as:-
[A]If the 'table' or 'inline-table' element's 'width' property has a specified value (W) other than 'auto', the property's computed value is the greater of W and the minimum width required by all the columns plus cell spacing or borders (MIN). If W is greater than MIN, the extra width should be distributed over the columns.
If the 'table' or 'inline-table' element has 'width: auto', the computed table width is the greater of the table's containing block width and MIN. However, if the maximum width required by the columns plus cell spacing or borders (MAX) is less than that of the containing block, use MAX.
It is the latter calculation - - which is the key - it is the shrink to fit
calculation.
It is quite difficult to follow, but as best as I can make out, there are three values:-
- The width (PARENT WIDTH) of the table's parent box.
- The minimum (TABLE MIN) width required by the table (word wrapping where possible).
- The maximum (TABLE MAX) width required by the table (effectively assuming
white-space:nowrap
)
The width of 1 (PARENT WIDTH) determines whether 2 (TABLE MIN) or 3 (TABLE MAX) is used.
- If 1 (PARENT WIDTH) is greater than 3 (TABLE MAX), then use 3 (TABLE MAX).
- If 1 (PARENT WIDTH) is less than 3 (TABLE MAX) but greater than 2 (TABLE MIN), then use 1 (PARENT WIDTH).
- If 1 (PARENT WIDTH) is less then 2 (TABLE MIN), then use 2 (TABLE MIN).
7.2 Examples (Not IE)
Lets use some examples (not using tables) to illustrate.
<h2>Rule 1: PARENT WIDTH wider than TABLE MAX</h2>
<div style="border:1px solid blue; padding:10px; width:700px;">
<div style="border:1px solid purple; padding:10px; display:table;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
<br>
<h2>Rule 2: PARENT WIDTH less than TABLE MAX, but greater than TABLE MIN</h2>
<h3>Expands to PARENT WIDTH</p>
<div style="border:1px solid blue; padding:10px; width:300px;">
<div style="border:1px solid purple; padding:10px; display:table;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
<br>
<h2>Rule 3: PARENT WIDTH less than TABLE MAX and less than than TABLE MIN</h2>
<h3>Should overflow to TABLE MIN</h3>
<div style="border:1px solid blue; padding:10px; width:100px;">
<div style="border:1px solid purple; padding:10px; display:table;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
<br>
<h2>Solution: Force TABLE MIN be same as TABLE MAX</h2>
<h3>Should overflow to TABLE MAX</h3>
<div style="border:1px solid blue; padding:10px; width:200px;">
<div style="border:1px solid purple; padding:10px; display:table; white-space:nowrap;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
<br>
<h2>Solution: Force TABLE MIN be same as TABLE MAX</h2>
<h3>overflow:auto;</p>
<div style="border:1px solid blue; padding:10px; width:200px; overflow:auto;">
<div style="border:1px solid purple; padding:10px; display:table; white-space:nowrap;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
7.3 Conclusion
This option solves the overflow problem simply for all browsers (except IE). It ensures that the width of the element is never less than its minimum width
to ensure no overflow.
However, minimum width
is not enough for my use, I want the minimum width
to be the maximum width
. So the solution is to use white-space:nowrap
to ensure that the minimum width
is the same as the maximum width
. See the example above.
8. Progress So Far Towards Solution
8.2 Solution So Far
<h2>Solution: Force TABLE MIN be same as TABLE MAX</h2>
<h3>overflow:auto;</p>
<div style="border:1px solid blue; padding:10px; width:200px; overflow:auto;">
<div style="border:1px solid purple; padding:10px; display:table; white-space:nowrap; width:1px;" nowrap>
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
What we have learned so far is that:-
8.2 Internet Explorer
For Internet Explorer, we can force boxes and parent boxes to expand to the width of the longest line inside, simply by setting nowrap
and width:1px
on a containing div element
.
This is not perfect because the result is staggered : individual child boxes only expand to the width of their line, rather than to the width that the largest line causes.
8.3 Other Browsers
For other browsers, if they support display:table
, there is a shrink-to-fit calculation which does the job, if we set white-space:nowrap
on the parent element.
8.4 Any Better?
Can we do any better, because IE is neither one thing nor the other.
9. Float and Absolute : Shrink-To-Fit
9.1 The same rules apply as for tables
At first I thought this was going to be a hard problem to solve to get any further on.
Then I bothered to read Chapter 10 of CSS2 Specification, and low it showed me (and in fact reminded me) that shrink-to-fit
applies as well to: floats, and absolutely positioned elements.
And better still, Internet Explorer does it properly (almost! - there is the infamous 3 pixel text jog on floated elements - and it still does not do overflow
- but does it really matter?).
Effectively shrink to fit
applies to:-
- tables (or elements with
display:table
set, for browsers that implement it) - elements with
float:left
(or right) set - elements with
position:absolute
To quote from 10.3.5 of the CSS2 Specification:-
10.3.5 Floating, non-replaced elements
If 'width' is computed as 'auto', the used value is the "shrink-to-fit" width.
Calculation of the shrink-to-fit width is similar to calculating the width of a table cell using the automatic table layout algorithm. Roughly:
10.3.7 Absolutely positioned, non-replaced elements
'left' and 'width' are 'auto' and 'right' is not 'auto', then the width is shrink-to-fit. Then solve for 'left'
'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right'
Calculation of the shrink-to-fit width is similar to calculating the width of a table cell using the automatic table layout algorithm.
So we have exactly the same calculations as for a table, and we are in effect home and dry.
9.2 Float Examples
<h1>FLOAT EXAMPLES</h1>
<h2>Rule 1: PARENT WIDTH wider than TABLE MAX</h2>
<h3>Expands to TABLE MAX</h3>
<div style="border:1px solid blue; padding:10px; width:700px;">
<div style="border:1px solid purple; padding:10px; float:left;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
<br>
<div style="clear:both"><!--Clear the float for the next example--></div>
<h2>Rule 2: PARENT WIDTH less than TABLE MAX, but greater than TABLE MIN</h2>
<h3>Expands to PARENT WIDTH</p>
<div style="border:1px solid blue; padding:10px; width:300px;">
<div style="border:1px solid purple; padding:10px; float:left;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
<br>
<div style="clear:both"><!--Clear the float for the next example--></div>
<h2>Rule 3: PARENT WIDTH less than TABLE MAX and less than than TABLE MIN</h2>
<h3>Should overflow to TABLE MIN</h3>
<div style="border:1px solid blue; padding:10px; width:100px;">
<div style="border:1px solid purple; padding:10px; float:left;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
<br>
<div style="clear:both"><!--Clear the float for the next example--></div>
<h2>Solution: Force TABLE MIN be same as TABLE MAX</h2>
<h3>Should overflow to TABLE MAX</h3>
<div style="border:1px solid blue; padding:10px; width:200px;">
<div style="border:1px solid purple; padding:10px; float:left; white-space:nowrap;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
<br>
<div style="clear:both"><!--Clear the float for the next example--></div>
<h2>Solution: Force TABLE MIN be same as TABLE MAX</h2>
<h3>overflow:auto;</p>
<div style="border:1px solid blue; padding:10px; width:200px; overflow:auto;">
<div style="border:1px solid purple; padding:10px; float:left; white-space:nowrap;" nowrap>
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
The only problem (apart from IE) is that Opera does not respect the padding-bottom
when overflow:auto
.
9.3 position:absolute Examples
Here are some examples with position:absolute
.
The containing box needs position:relative
to position correctly. Overflows will result unless overflow:auto
is set, so some examples now have an explicit height.
<h1>POSITION:ABSOLUTE EXAMPLES</h1>
<h2>Rule 1: PARENT WIDTH wider than TABLE MAX</h2>
<h3>Expands to TABLE MAX</h3>
<div style="border:1px solid blue; padding:10px; width:700px; height:160px; position:relative;">
<div style="border:1px solid purple; padding:10px; position:absolute;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
<br>
<div style="clear:both"><!--Clear the float for the next example--></div>
<h2>Rule 2: PARENT WIDTH less than TABLE MAX, but greater than TABLE MIN</h2>
<h3>Expands to PARENT WIDTH</p>
<div style="border:1px solid blue; padding:10px; width:300px; height:160px; position:relative;">
<div style="border:1px solid purple; padding:10px; position:absolute;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
<br>
<div style="clear:both"><!--Clear the float for the next example--></div>
<h2>Rule 3: PARENT WIDTH less than TABLE MAX and less than than TABLE MIN</h2>
<h3>Should overflow to TABLE MIN</h3>
<div style="border:1px solid blue; padding:10px; width:100px; height:160px; position:relative;">
<div style="border:1px solid purple; padding:10px; position:absolute;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
<br>
<div style="clear:both"><!--Clear the float for the next example--></div>
<h2>Solution: Force TABLE MIN be same as TABLE MAX</h2>
<h3>Should overflow to TABLE MAX</h3>
<div style="border:1px solid blue; padding:10px; width:200px; height:150px; position:relative;">
<div style="border:1px solid purple; padding:10px; position:absolute; white-space:nowrap;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
<br>
<div style="clear:both"><!--Clear the float for the next example--></div>
<h2>Solution: Force TABLE MIN be same as TABLE MAX</h2>
<h3>overflow:auto;</p>
<div style="border:1px solid blue; padding:10px; width:200px; height:150px; overflow:auto; position:relative;">
<div style="border:1px solid purple; padding:10px; position:absolute; white-space:nowrap;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
<br>
<div style="clear:both"><!--Clear the float for the next example--></div>
<h2>Solution: Force TABLE MIN be same as TABLE MAX</h2>
<h3>overflow:auto; Bordered div for padding</p>
<div style="border:1px solid blue; width:200px; height:150px; overflow:auto; position:relative;">
<div style="border:10px solid white; position:absolute; white-space:nowrap;">
<div style="border:1px solid purple; padding:10px; position:absolute; white-space:nowrap;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
</div>
9.4 Perfection?
Not really.
The only remaining problem, is that all of the browsers differ in how they handle padding etc inside boxes with overflow:auto;
set.
The only solution I have so far, is that in section 2.
10. Conclusion
Hurrah, shrink to fit
was there all along.
I have set out my preferred solution in section 2.
I would like to propose that for Section 10.3.3 Block-level, non-replaced elements in normal flow that there be another value for the width
element, called shrink-to-fit
(or as someone else has suggested content
) which triggers the shrink-to-fit algorithm. I suppose that this is already present with the display:table
option, but not quite so explicit.
11. Further Ideas
11.1 % of content
If you apply a percentage width within a float, you can effectively get a kind of % of content
measure, box-model issues aside.
<h1>FLOAT EXAMPLES</h1>
<h2>Rule 1: PARENT WIDTH wider than TABLE MAX</h2>
<h3>Expands to 50% of TABLE MAX effectively</h3>
<div style="border:1px solid blue; padding:10px; float:left;">
<div style="border:1px solid purple; padding:10px; width:50%;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
11.2 JavaScript to Calculate Content Width
You can go even further and use JavaScript to calculate the maximum width of an object with unbroken lines.
<html>
<head>
<script>
function go()
{
var element = document.getElementById("testBox");
var maxWidth = HTMLElement_GetContentMaximumWidth(element);
element.style.width = maxWidth;
}
function HTMLElement_GetContentMaximumWidth (
element /*: HTMLElement*/,
box /*: enum_BOX */
) /*: int*/
{
var width /*: int*/ = 0;
var elementStyle /*: CSSStyleDeclaration*/ = element.style;
var previousPosition /*: String*/ = elementStyle.position;
var previousWidth /*: String*/ = elementStyle.width;
var previousWhitespace /*: String*/ = elementStyle.whiteSpace;
var previousNoWrap /*: Boolean*/ = !!(element.noWrap);
elementStyle.position = "absolute";
elementStyle.width = "auto";
elementStyle.whiteSpace = "nowrap";
element.noWrap = true;
width = element.offsetWidth;
elementStyle.position = previousPosition || "";
elementStyle.width = previousWidth || "";
elementStyle.whiteSpace = previousWhitespace || "";
element.noWrap = previousNoWrap;
width = isNaN(width) ? element.offsetWidth : width;
return width;
}
</script>
</head>
<body>
<p onclick="go()">Click here to set the following box to content width</p>
<div id="testBox">
<div style="border:1px solid purple; padding:10px;">
<div style="border:1px solid purple; padding:10px; margin-bottom:10px;">
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand. Expand. Expand.</p>
</div>
</div>
<div style="border:1px solid purple; padding:10px;">
<p style="margin:0px;">Expand. Expand. Expand. Expand.</p>
</div>
</div>
</div>
</body>
</html>
Thats enough, for now...
No comments made on this entry.