1. Overview
This section is not normative.
This specification adds new keywords on the float property.
This document allows to specify whether a float floats to align with a float reference inline box, column, region or page. In the case of floats with a reference fragmentation container, placement can be deferred to a subsequent fragmentation container with the float-defer properties.
New values on the clear property add further ways of refining layouts.
The way contents wrap around floats can be controlled by changing the value of the wrap-flow property which initially is set to both for page floats.
Page floats as defined here work with different types of fragmentation types (columns, regions, pages) as well as container elements. The specification is no longer specific to print or to pages. At the same time, inline floats and page floats differ in many ways, and it may (or may not) be a good idea to separate the two entirely. Therefore, the name CSS Page Floats should probably be replaced with a more appropriate name.
1.1. Value Definitions
This specification follows the CSS property definition conventions from [CSS2] using the value definition syntax from [CSS-VALUES-3]. Value types not defined in this specification are defined in CSS Values & Units [CSS-VALUES-3]. Combination with other CSS modules may expand the definitions of these value types.
In addition to the property-specific values listed in their definitions, all properties defined in this specification also accept the CSS-wide keywords as their property value. For readability they have not been repeated explicitly.
2. Terminology
- Float
- An element which has float set to something else than none.
- Inline float
- A float which has float set to inline.
- Page float
- A float which has float set to something else than inline or none.
- Float block formatting context
- The block formatting context which is generated by a float and which contains its contents.
- Float anchor
- The float anchor is the point in the flow where the float had appeared had it not been a float and instead had been an empty inline element with no margins, borders or padding.
- Float containing block formatting context
- The block formatting context inside of which an float is embedded.
- Initial float reference
- The entity to which the float is aligned initially, before float placement takes place.
- Float reference
- The entity to which the float is aligned.
- Not overlapping
- Two elements are not overlapping if the margin box of one element is not overlapping the margin box of the other element.
3. Floating to the inline-start/inline-end and block-start/block-end
Floating elements can float to the start or end of the float anchor’s line or block, specified by the float attribute. The floats are aligning to the start or end of a float reference, specified by the float-reference attribute. The float reference can be the float anchor’s line box, column, region or page.
3.1. The float-reference property
Name: | float-reference |
---|---|
Value: | inline | column | region | page |
Initial: | inline |
Applies to: | all elements. |
Inherited: | no |
Percentages: | N/A |
Computed value: | specified keyword |
Canonical order: | per grammar |
Animation type: | discrete |
- inline
-
The float reference is the line box of the float anchor.
The float containing block formatting context is the same as that of the float anchor.
The float is an inline float.
- column
-
The float reference is the column in a multi column environment in
which the float anchor is placed. If the float anchor is not
inside a column, the float reference is the line box of the float
anchor.
The float containing block formatting context is a new block formatting context with the same dimensions and placement as the float reference.
The float is a page float.
- region
-
The float reference is the region in a region-chain within which the float anchor is placed. If the float anchor is not inside a
region, the float reference is the line box of the float
anchor.
The float containing block formatting context is a new block formatting context with the same dimensions and placement as the float reference.
The float is a page float.
- page
-
The float reference of the float is the page within which the float
anchor is placed. If the float anchor is not inside a page, the float reference is the line box of the float anchor.
The float containing block formatting context is a new block formatting context with the same dimensions and placement as the float reference.
The float is a page float.
Maybe something like:
<style>
.float {
float-reference: float-container;
}
#container {
float-container: true;
}
</style>
<div id="container">
<p>First paragraph<span class="float">FLOAT</span></p>
<p>Second paragraph
<span class="inline-block">[<span class="float">FLOAT</span>] </span>
And some more text</p>
</div>
This should float both floats with reference to the <div id="container"> element, rather than the <P> and inline <SPAN> elements.
3.2. The float property
Name: | float |
---|---|
Value: | block-start | block-end | inline-start | inline-end | snap-block | <snap-block()> | snap-inline | <snap-inline()> | left | right | top | bottom | none |
Initial: | none |
Applies to: | all elements. |
Inherited: | no |
Percentages: | N/A |
Computed value: | as specified |
Canonical order: | per grammar |
Animation type: | by computed value type |
- inline-start
-
If the float reference is a line box, the element generates a box that
is floated to the line-start outer edge of the float reference and
content flows on the line-end side of the box.
If the float reference is not a line box, the element generates a box that is floated to the line-start and block-start outer edges of the float reference.
- inline-end
-
If the float reference is a line box, the element generates a box that
is floated to the line-ebd outer edge of the float reference and
content flows on the line-start side of the box.
If the float reference is not a line box, the element generates a box that is floated to the line-end and block-end outer edges of the float reference.
- block-start
-
If the float reference is a line box, block-start behaves like
inline-start.
If the float reference is not a line box, the element generates a box that is floated to the block-start and line-start outer edges of the float reference.
The initial value of the max-width or max-height property that refers to the inline size of the float is '100%'.
Content flows on the block-end side of the box.
- block-end
-
If the float reference is a line box, block-end behaves like inline-end.
If the float reference is not a line box, the element generates a box that is floated to the block-end and line-end outer edges of the float reference.
The initial value of the max-width or max-height property that refers to the inline size of the float is '100%'.
Content flows on the block-start side of the box.
- left
-
If the float reference is a line box, behaves like inline-start or
inline-end, whichever corresponds to line-left for the float reference.
Otherwise, behaves like block-end, inline-start or inline-end depending on the float containing block’s direction and writing-mode.
- right
-
If the float reference is a line box, behaves like inline-start or
inline-end, whichever corresponds to line-right for the float reference.
Otherwise, behaves like block-start, inline-start or inline-end depending on the float containing block’s direction and writing-mode.
- top
- Behave like block-start or inline-start depending on the float containing block’s direction and writing-mode.
- bottom
- Behave like block-end or inline-end depending on the float containing block’s direction and writing-mode.
- snap-block()
-
The snap-block() function is defined as:
snap-block() = snap-block( <length> , [ start | end | near ]? )
Has no effect if the element is an inline float.
If the element is a page float, it makes the element float to the start or the end of the block if it naturally appears within a certain distance from either one. The length value(s) specifies the maximum distance from the start/end that an element must be within in order to be floated; one length value specifies the distance from both the start and the end, two length values specify the distance from the start and end, respectively.
The optional keyword value specifies where the element is floated: start, end, or the nearest of the two. The initial value is near. If near is in effect and the element is within the specified distance both from the start and the end, end wins.
- snap-block
- Behaves as
snap-block(2em, near)
- snap-inline()
-
The snap-inline() function is defined as:
snap-inline() = snap-inline( <length> , [ left | right | near ]? )
Has no effect if the element is an inline float.
If the element is a page float, it makes the element float to the line start or line end if it naturally appears within a certain distance from the start or end of the line. The length value(s) specifies the maximum distance from the start/end that an element must be within in order to be floated; one length value specifies the distance from both the start and the end, two length values specify the distance from the start and end, respectively.
The optional keyword value specifies where the element is floated: line start, line end, or the nearest of the two. The initial value is near. If near is in effect and the element is within the specified distance both from the start and the end, end wins.
- snap-inline
- same as
snap-inline(2em, near)
- none
- The box is not floated.
.figure { float-reference: column; float: block-start; width: 50% }
To avoid the white space, the image can be floated to the nearest edge (in the block direction):
.figure { float-reference: column; float: snap-block }
In this example, the figure is already at the nearest edge, so it does not move. However, floats allow subsequent content to be displayed before the float and the white space can therefore be filled:
In this example, two figures naturally appear in the text flow:
A typographer would typically try to avoid single lines of text above/below figures, which can be achieved with:
div.figure { float-reference: column; float: snap-block(1.5em) }
The length value specifies the reach of the snap function; in this example the second figure is affected, but not the first.
In this example, two figures naturally appear in the text flow:
To make the figures snap to the nearest edges, this code can be applied:
div.figure { float-reference: column; float: snap-block(2.5em) }
The resultant rendering is:
table { float: snap } table { float: snap-block(3em) } table { float: snap-block(3em, bottom) } table { float: snap-block(3em 2em, bottom) }
4. The clear property
Name: | clear |
---|---|
Value: | inline-start | inline-end | block-start | block-end | left | right | top | bottom | none |
Initial: | none |
Applies to: | block-level elements, floats, regions, pages |
Inherited: | no |
Percentages: | N/A |
Computed value: | specified keyword |
Canonical order: | per grammar |
Animation type: | discrete |
To prevent stacking of floats, the clear property can be used:
- inline-start
-
If applied to an inline float, requires that the block-start outer edge of
the box comes after the block-end outer edge of any inline-start-floats
with an inline-start-float-reference that resulted from elements earlier
in the source document.
If applied to a page float, the float reference in which the page float is placed will be seen as full when determining whether it can host subsequent page floats that float in the inline-start direction.
- inline-end
-
If applied to a block-level element or an inline float, requires
that the block-start outer edge of the box comes after the block-end outer
edge of any inline-end-floats with an inline-end-float-reference that
resulted from elements earlier in the source document.
If applied to a page float, the float reference in which the page float is placed will be seen as full when determining whether it can host subsequent page floats that float in the inline-end direction.
- block-start
-
If applied to a block-level element or an inline float, behaves like
inline-start.
If applied to a page float, the float reference in which the page float is placed will be seen as full when determining whether it can host subsequent page floats that float in the block-start direction.
- block-end
-
If applied to a block-level element or an inline float, behaves
like inline-end.
If applied to a page float, the float reference in which the page float is placed will be seen as full when determining whether it can host subsequent page floats that float in the block-end direction.
- left
- Behave like block-end, inline-start or inline-end depending on the float containing block’s direction and writing-mode.
- right
- Behave like block-start, inline-start or inline-end depending on the float containing block’s direction and writing-mode.
- top
- Behave like block-start or inline-start depending on the float containing block’s direction and writing-mode.
- bottom
- Behave like block-end or inline-end depending on the float containing block’s direction and writing-mode.
- both-inline
- Behave like inline-start and inline-end.
- both-block
- Behave like block-start and block-end.
- both
- Behave like both-inline.
- all
- Behave like both-block and both-inline.
.figure { float-reference: column; float: bottom; clear: none } <div class=figure></div> <div class=figure></div>
.figure { float-reference: column; float: bottom; clear: bottom } <div class=figure></div> <div class=figure></div>
.figure { float-reference: column; float: bottom; clear: top } <div class=figure></div> <div class=figure></div>
.figure { float-reference: column; float: bottom; clear: bottom } <div class=figure></div> <div class=figure></div>
.figure { float-reference: page; float: top; clear: top } <div class=figure></div> <div class=figure></div>
.figure.one { float-reference: column; float: top; clear: top } .figure.two { float-reference: column; float: bottom; clear: bottom } <div class="figure one"></div> <div class="figure two"></div>
5. Deferring page floats
Users can influence the placement of a page float by deferring them to another fragmentation container than where the float anchor is placed.
A float that is an inline float cannot be deferred.
Float deferring assigns an initial float reference, yet float stacking can lead page floats being moved to a subsequent fragmentation container if their initial float reference lacks the space to host them.
The float-defer property is introduced to control deferring floats:
5.1. The float-defer property
Name: | float-defer |
---|---|
Value: | <integer> | last | none |
Initial: | none |
Applies to: | floats |
Inherited: | no |
Percentages: | N/A |
Computed value: | specified keyword or integer |
Canonical order: | per grammar |
Animation type: | discrete |
This property specifies whether the initial float reference of a page float is the fragmentation container in which the float anchor is placed after previous page floats have been placed, or in another one.
This property is ignored if the element is an inline float.
Values are:
- none
- The initial float reference is the fragmentation container in which the float anchor is placed after all previous page floats have been placed.
- <integer>
-
A positive integer value indicates that the initial float reference of
the page float should be Nth fragmentation container of the `fragmentation
flow`, where N is the value of the `float-defer` property plus the order
number of the fragmentation container in which the float anchor is placed
after all previous page floats have been placed within the given fragmentation context. If N is larger than the order number of the last fragmentation container within the given fragmentation context at the time of
assignment, then N is the order number of the last fragmentation container within the given fragmentation context.
A negative integer value indicates that the initial float reference of the page float should be a fragmentation container of the fragmentation context, counting backward from the end, so that -1 is the last fragmentation container, -2 is the next-to-last, etc. . In the case of a negative integer value, the initial float reference is the Nth fragmentation container of the fragmentation context, where N is 1 plus the order number of the last fragmentation container within the given fragmentation context after all previous page floats have been placed plus the value of the `float-defer` property.
Zero is the same as `none`.
If the value of the `float-defer` property would cause the initial float reference to be an inexistent fragmentation container, the property is interpreted as if it were zero.
Negative float-defer values put the initial float reference a certain number to be a certain amount of fragmentation containers from the last fragmentation container at the time of the placement. Subsequent page float stacking can mean that a page float is being placed in a later fragmentation container (a page float with float-defer set to -3 can end up being placed in the last fragmentation container), and later page floats may mean that new fragmentation containers are added, so that the a fragmentation container that previously was Nth last fragmentation container within a fragmentation context now is the N+Xth last. Additional fragmentation container(s) that are added after the page float was placed, will not cause the page float to be moved.
- last
- The initial float reference is the last fragmentation container within the given fragmentation context after all previous page floats have been placed.
.figure { float-reference: region } .figure { float: top } .figure { float-defer: 1 }
.figure { float-reference: column; float: top; float-defer: -2 }
.figure { float-reference: page } .figure { float: top } .figure { float-defer: -1 }
.figure { float-reference: column } .figure { float: top } .figure { float-defer: last }
.figure { float-reference: column; float: top; float-defer: last }
6. Wrapping around page floats
Page floats have their wrap-flow property set to both initially and are treated like exclusions. This specification does not make any further specification about wrapping contents around page floats.
7. The float-offset property
Name: | float-offset |
---|---|
Value: | <length> | <percentage> |
Initial: | 0 |
Applies to: | floats |
Inherited: | no |
Percentages: | see prose |
Computed value: | computed <length-percentage> value |
Canonical order: | per grammar |
Animation type: | by computed value type |
This property pushes a page float in direction opposite of the where it has been floated with float.
If the element is an inline float, this property is ignored.
This property can only influence a page float along an axis along which it has been floated.
- <percentage>
-
Percentage values are computed according to this formula:
(containing-block-width - float-width) * percentage (containing-block-height - float-height) * percentage
img { float-reference: column; float: left; float-offset: 2em; }
In this example, the image is floated to the left. Therefore, float-offset may only push the element to the right.
8. Page float placement
The order of page floats placement is determined by the following rules:
- All page floats with float-reference set to `page` are placed, in document order, before those with float-reference set to `region` and `column`.
- Thereafter, page floats with float-reference set to `column` and `region` are placed in document order.
The placement of a single page float is a process that has to be terminated entirely before the placement of a subsequent page float can be initiated. The placement process consists of the following steps:
- Determine the initial float reference by considering the fragmentation container in which the float anchor is placed and the `float-defer` property of the page float. The float reference is initially set to be the same as the initial float reference.
- Determine if the given float reference has enough space or can be expanded to host the page float, if the rules of float stacking and float reference growth are to be followed. If this is not the case, and the float reference is not the last fragmentation container within the given fragmentation context, then make the following fragmentation container within the given fragmentation context the float reference. Repeat this step until the float reference can be expanded enough to host the page float or it is the last fragmentation container within the given fragmentation context.
- If the float reference is the last fragmentation container within
the given fragmentation context, and it has not enough space and cannot be
expanded to host the page float, then do the following:
- If the fragmentation context allows for the addition of another fragmentation container and an additional fragmentation container would have the needed size to host the page float, a new fragmentation container is added to the end of the fragmentation context. The float reference is set the newly created fragmentation container.
- Otherwise, if the fragmentation container is a region, then the 'regionOverset` attribute of the fragmentation container is set to `overset`.
- The page float is placed in the float reference according to the rules of 'float stacking' and 'float reference growth'.
8.1. Float reference growth
Float references can grow up to the their `max-height` and `max-width` or their `available size`, whichever is the lowest, in order to accommodate page floats.
8.2. Rules for page float stacking
Page floats are stacked within a given float reference in the order of their placement and in the direction of the inline- and flow-directions of the fragmentation context while not overlapping with any other page floats with the same float reference and by keeping a distance N between the page float’s margin edge and the padding edge of the float reference as well as between the page float’s margin edge and the margin edge of the last previously placed page float with the same float reference and the same float value, where N is the float-offset value of the page float.
For the purpose of calculating whether enough space is available for a page floats within the float reference, it is assumed that the page floats in the block directions fill the entire line size of the float reference and page floats in the inline direction fill the entire block size of the float reference.
For the purpose of placement, page floats in the block-start direction are also placed at the inline-start edge of the float reference and vice versa, and page floats in the block-end direction are placed at the inline-end edge of the float reference and vice versa.
If the page float has a defined clear-value, then the float reference in which the page float is placed is closed for all subsequent page floats that floating in the direction specified by the clear-value.
We can effectively currently float to two corners: inline-start/block-start and inline-end/block-end. We should augment this with the option to have a secondary float direction to allow basic 2D floating.
9. Floats and absolutely positioned exclusions
Floats and absolutely positioned exclusions share some common traits, but in the case of inline floats they are not the same. Floats that are not inline floats should behave the same as absolutely positioned exclusions with positions and sizes manually set to prevent overlap between floats and to prevent floats from moving beyond the edges of the float reference, with the float reference being grown as much as needed up to its maximum extend to accommodate all containing floats.
9.1. Differences between inline floats and absolutely positioned elements
This section is not normative.
Inline floats and absolutely positioned elements are both out-of-flow elements. Absolutely positioned elements that are also exclusions can imitate many of the features of floats.
However, in the case of inline floats, the block formatting context that contains them (the float containing block formatting context) is required to include the area occupied by the float, which is not a requirement for absolutely positioned elements.
<style>
.float {
float: left;
margin: 5px;
}
.border {
border: 3px solid black;
margin: 5px;
}
#outer {
border: 1px solid green;
display: inline-block;
}
canvas {
background-color: brown;
}
p {
margin: 5px;
}
</style>
<div id="outer">
<p class="border">
<span class="float border">
<canvas width="100" height="100"/>
</span>
First paragraph.
</p>
<p class="border">
Second paragraph and some more text.
</p>
</div>
In comparison, the below is the same HTML, but the float is replaced by an absolutely positioned element that is also an exclusion. The float containing block formatting context is still given by a display-inline-block element. However, the element, marked by a green border, does not expand to include the brown, absolutely positioned element.
<style>
.float {
position: absolute;
top: 8px;
left: 8px;
wrap-flow: both;
}
.border {
border: 3px solid black;
margin: 5px;
}
#outer {
border: 1px solid green;
display: inline-block;
position: relative;
}
canvas {
background-color: brown;
}
</style>
<div id="outer">
<p class="border">
<span class="float border">
<canvas width="100" height="100"/>
</span>
First paragraph.
</p>
<p class="border">
Second paragraph and some more text.
</p>
</div>
10. Overconstrained floats
In many cases, the specified values on these properties cannot be honored.
The number of columns is limited, and high values therefore cannot be honored:
.figure { float-reference: column; float: top; float-defer: 1000 }
.figure { float-reference: column; float: top; float-defer: -5 }
p { float-reference: page; float: top; float-defer: last }
Floats are processed in the order they appear in the source. However, the visual order of floats may not be the same as the source order.
.one { float-reference: page; float: top; float-defer: last } .two { float-reference: column; float: top; clear: column } <div class=one></div> <div class=two></div>
In this example, the first element requests to appear on the last page, while the second element requests to appear in the natural column. If the natural column of the second element appears on a page before the last page, the second element will appear visually before the first.
Consider this code:
.one { float-reference: page; float: top; float-defer: last } .two { float-reference: page; float: top; clear: page; } <div class=one></div> <div class=two></div>
If all content can fit on one page, the first page will also be the last page. The first element is processed first and is placed on top of the first page. Then the second element is processed. It requests a clear top, something which is not possible on the first page. Therefore, a second page is created and the first element is moved there. Even if the first element requests to be on the last page, it will not appear there.
When resolving over-constrained layouts, the order of importance for defined goals are:
- honor 'clear: top/bottom'
- honor float-defer
- honor 'float: top/bottom'
- display all content (as described by other CSS properties)
- keep the number of pages to a minimum
Acknowledgments
This specification is made possible by input from Rossen Atanassov, Tab Atkins Jr., David Baron, Lars Erik Bolstad, Bert Bos, Mike Bremford, Dave Cramer, Michael Day, Werner Donné, Brady Duga, James Elmore, Elika Etemad, Michel Fortin, Daniel Glazman, Melinda Grant, Ian Hickson, Laurens Holst, Brad Kemper, Toru Kawakubo, Rune Lillesveen, Peter Linss, Cameron McCormack, Paul E. Merrell, Del Merritt, Markus Mielke, Kelly Miller, Alex Mogilevsky, Peter Moulder, Shinyu Murakami, Michel Onoff, Anton Prowse, Liam R E Quin, Jacob Grundtvig Refstrup, Florian Rivoal, Christian Roth, Allan Sandfeld Jensen, Simon Sapin, Alan Stearns, Morten Stenshorne, Philip Taylor, Ian Tindale, Ladd Van Tol, Lea Verou, Tarquin (Mark) Wilton-Jones, Steve Zilles, Tantek Çelik and the CSS Working Group members.