10.25 CSS 弹性布局算法

本章是给浏览器开发者阅读的,普通作者可忽略,除非想深入布局原理

9. Flex Layout Algorithm

This section contains normative algorithms detailing the exact layout behavior of a flex container and its contents. The algorithms here are written to optimize readability and theoretical simplicity, and may not necessarily be the most efficient. Implementations may use whatever actual algorithms they wish, but must produce the same results as the algorithms described here.

Note: This section is mainly intended for implementors. Authors writing web pages should generally be served well by the individual property descriptions, and do not need to read this section unless they have a deep-seated urge to understand arcane details of CSS layout.

The following sections define the algorithm for laying out a flex container and its contents.

9.1. Initial Setup

  1. Generate anonymous flex items as described in the Flex Items section.
  2. Re-order the flex items (and any absolutely positioned flex container children) according to their order. The flex items with the lowest (most negative) order values are first in the ordering. If multiple flex items share an order value, they’re ordered by document order. This effectively changes the order of their boxes in the box-tree, and how the rest of this algorithm deals with the generated flex items.

    Note: Absolutely-positioned children of a flex container do not participate in flex layout, but are reordered together with any flex item children.

9.2. Line Length Determination

  1. Determine the available main and cross space for the flex items. For each dimension, if that dimension of the flex container’s content box is a definite size, use that; otherwise, subtract the flex container’s margin, border, and padding from the space available to the flex container in that dimension and use that value. This might result in an infinite value.

    For example, the available space to a flex item in a floated auto-sized flex container is:

    • the width of the flex container’s containing block minus the flex container’s margin, border, and padding in the horizontal dimension
    • infinite in the vertical dimension
  2. Determine the flex base size and hypothetical main size of each item:
    1. If the item has a definite used flex basis, that’s the flex base size.
    2. If the flex item has ... then the flex base size is calculated from its inner cross size and the flex item’s intrinsic aspect ratio.
    3. If the used flex basis is content or depends on its available size, and the flex container is being sized under a min-content or max-content constraint (e.g. when performing automatic table layout [CSS21]), size the item under that constraint. The flex base size is the item’s resulting main size.
    4. Otherwise, if the used flex basis is content or depends on its available size, the available main size is infinite, and the flex item’s inline axis is parallel to the main axis, lay the item out using the rules for a box in an orthogonal flow [CSS3-WRITING-MODES]. The flex base size is the item’s max-content main size.

      Note: This case occurs, for example, in an English document (horizontal writing mode) containing a column flex container containing a vertical Japanese (vertical writing mode) flex item.

    5. Otherwise, size the item into the available space using its used flex basis in place of its main size, treating a value of content as max-content. If a cross size is needed to determine the main size (e.g. when the flex item’s main size is in its block axis) and the flex item’s cross size is auto and not definite, in this calculation use fit-content as the flex item’s cross size. The flex base size is the item’s resulting main size.

    When determining the flex base size, the item’s min and max main size properties are ignored (no clamping occurs).

    The hypothetical main size is the item’s flex base size clamped according to its min and max main size properties.

  3. Determine the main size of the flex container using the rules of the formatting context in which it participates. For this computation, auto margins on flex items are treated as 0.

9.3. Main Size Determination

  1. Collect flex items into flex lines:
    • If the flex container is single-line, collect all the flex items into a single flex line.
    • Otherwise, starting from the first uncollected item, collect consecutive items one by one until the first time that the next collected item would not fit into the flex container’s inner main size (or until a forced break is encountered, see §10 Fragmenting Flex Layout). If the very first uncollected item wouldn’t fit, collect just it into the line.

      For this step, the size of a flex item is its outer hypothetical main size.

      Repeat until all flex items have been collected into flex lines.

      Note that the "collect as many" line will collect zero-sized flex items onto the end of the previous line even if the last non-zero item exactly "filled up" the line.

  2. Resolve the flexible lengths of all the flex items to find their used main size (see section 9.7.).

9.4. Cross Size Determination

  1. Determine the hypothetical cross size of each item by performing layout with the used main size and the available space, treating auto as fit-content.
  2. Calculate the cross size of each flex line.

    If the flex container is single-line and has a definite cross size, the cross size of the flex line is the flex container’s inner cross size.

    Otherwise, for each flex line:

    1. Collect all the flex items whose inline-axis is parallel to the main-axis, whose align-self is baseline, and whose cross-axis margins are both non-auto. Find the largest of the distances between each item’s baseline and its hypothetical outer cross-start edge, and the largest of the distances between each item’s baseline and its hypothetical outer cross-end edge, and sum these two values.
    2. Among all the items not collected by the previous step, find the largest outer hypothetical cross size.
    3. The used cross-size of the flex line is the largest of the numbers found in the previous two steps and zero.

      If the flex container is single-line, then clamp the line’s cross-size to be within the container’s computed min and max cross-size properties. Note that if CSS 2.1’s definition of min/max-width/height applied more generally, this behavior would fall out automatically.

  3. Handle 'align-content: stretch'. If the flex container has a definite cross size, align-content is stretch, and the sum of the flex lines' cross sizes is less than the flex container’s inner cross size, increase the cross size of each flex line by equal amounts such that the sum of their cross sizes exactly equals the flex container’s inner cross size.
  4. Collapse visibility:collapse items. If any flex items have visibility: collapse, note the cross size of the line they’re in as the item’s strut size, and restart layout from the beginning.

    In this second layout round, when collecting items into lines, treat the collapsed items as having zero main size. For the rest of the algorithm following that step, ignore the collapsed items entirely (as if they were display:none) except that after calculating the cross size of the lines, if any line’s cross size is less than the largest strut size among all the collapsed items in the line, set its cross size to that strut size.

    Skip this step in the second layout round.

  5. Determine the used cross size of each flex item. If a flex item has align-self: stretch, its computed cross size property is auto, and neither of its cross-axis margins are auto, the used outer cross size is the used cross size of its flex line, clamped according to the item’s min and max cross size properties. Otherwise, the used cross size is the item’s hypothetical cross size.

    If the flex item has align-self: stretch, redo layout for its contents, treating this used size as its definite cross size so that percentage-sized children can be resolved.

    Note that this step does not affect the main size of the flex item, even if it has an intrinsic aspect ratio.

9.5. Main-Axis Alignment

  1. Distribute any remaining free space. For each flex line:
    1. If the remaining free space is positive and at least one main-axis margin on this line is auto, distribute the free space equally among these margins. Otherwise, set all auto margins to zero.
    2. Align the items along the main-axis per justify-content.

9.6. Cross-Axis Alignment

  1. Resolve cross-axis auto margins. If a flex item has auto cross-axis margins:
    • If its outer cross size (treating those auto margins as zero) is less than the cross size of its flex line, distribute the difference in those sizes equally to the auto margins.
    • Otherwise, if the block-start or inline-start margin (whichever is in the cross axis) is auto, set it to zero. Set the opposite margin so that the outer cross size of the item equals the cross size of its flex line.
  2. Align all flex items along the cross-axis per align-self, if neither of the item’s cross-axis margins are auto.
  3. Determine the flex container’s used cross size:
    • If the cross size property is a definite size, use that, clamped by the min and max cross size properties of the flex container.
    • Otherwise, use the sum of the flex lines' cross sizes, clamped by the min and max cross size properties of the flex container.
  4. Align all flex lines per align-content.

9.7. Resolving Flexible Lengths

To resolve the flexible lengths of the items within a flex line:

  1. Determine the used flex factor. Sum the outer hypothetical main sizes of all items on the line. If the sum is less than the flex container’s inner main size, use the flex grow factor for the rest of this algorithm; otherwise, use the flex shrink factor.
  2. Size inflexible items. Freeze, setting its target main size to its hypothetical main size
  3. Calculate initial free space. Sum the outer sizes of all items on the line, and subtract this from the flex container’s inner main size. For frozen items, use their outer target main size; for other items, use their outer flex base size.
  4. Loop:
    1. Check for flexible items. If all the flex items on the line are frozen, free space has been distributed; exit this loop.
    2. Calculate the remaining free space as for initial free space, above. If the sum of the unfrozen flex items’ flex factors is less than one, multiply the initial free space by this sum. If the magnitude of this value is less than the magnitude of the remaining free space, use this as the remaining free space.
    3. Distribute free space proportional to the flex factors.
      If the remaining free space is zero
      Do nothing.
      If using the flex grow factor
      Find the ratio of the item’s flex grow factor to the sum of the flex grow factors of all unfrozen items on the line. Set the item’s target main size to its flex base size plus a fraction of the remaining free space proportional to the ratio.
      If using the flex shrink factor
      For every unfrozen item on the line, multiply its flex shrink factor by its inner flex base size, and note this as its scaled flex shrink factor. Find the ratio of the item’s scaled flex shrink factor to the sum of the scaled flex shrink factors of all unfrozen items on the line. Set the item’s target main size to its flex base size minus a fraction of the absolute value of the remaining free space proportional to the ratio. Note this may result in a negative inner main size; it will be corrected in the next step.
      Otherwise
      Do nothing.
    4. Fix min/max violations. Clamp each non-frozen item’s target main size by its min and max main size properties. If the item’s target main size was made smaller by this, it’s a max violation. If the item’s target main size was made larger by this, it’s a min violation.
    5. Freeze over-flexed items. The total violation is the sum of the adjustments from the previous step ∑(clamped size - unclamped size). If the total violation is:
      Zero
      Freeze all items.
      Positive
      Freeze all the items with min violations.
      Negative
      Freeze all the items with max violations.
    6. Return to the start of this loop.
  5. Set each item’s used main size to its target main size.

9.8. Definite and Indefinite Sizes

For the purposes of these definitions, a definite size is one that can be determined without measuring content, i.e. is a <length>, a size of the initial containing block, or a <percentage> that is resolved against a definite size. An indefinite size is one that is not definite.

Flexbox has several additional cases where a length can be considered definite:

  1. If a single-line flex container has a definite cross size, the outer cross size of any stretched flex items is the flex container’s inner cross size (clamped to the flex item’s min and max cross size) and is considered definite.
  2. If a percentage is going to be resolved against a flex item’s main size, and the flex item has a definite flex basis, and the flex container has a definite main size, the flex item’s main size must be treated as definite for the purpose of resolving the percentage, and the percentage must resolve against the flexed main size of the flex item (that is, after the layout algorithm below has been completed for the flex item’s flex container, and the flex item has acquired its final size).

9.9. Intrinsic Sizes

The max-content main size of a flex container is the smallest size the flex container can take while maintaining the max-content contributions of its flex items.

  1. For each flex item, subtract its flex base size from its max-content contribution size, then divide by its flex grow factor, floored at 1, or by its scaled flex shrink factor (if the result was negative, flooring the flex shrink factor at 1 if necessary). This is the item’s max-content flex fraction.
  2. Place all flex items into lines of infinite length.
  3. Within each line, find the largest max-content flex fraction among all the flex items. Add each item’s flex base size to the product of its flex grow factor (or scaled flex shrink factor, if the chosen max-content flex fraction was negative) and the chosen max-content flex fraction, then clamp that result by the max main size property.
  4. The flex container’s max-content size is the largest sum of the afore-calculated sizes of all items within a single line.

The min-content main size of a single-line flex container is calculated identically to the max-content main size, except that the flex item’s min-content contribution is used instead of its max-content contribution. For a multi-line container, it is simply the largest min-content contribution of all the flex items in the flex container.

The min-content cross size and max-content cross size of a flex container are the cross size of the flex container after performing layout into the given available main-axis space and infinite available cross-axis space.

The main-size min-content/max-content contribution of a flex item is its outer hypothetical main size when sized under a min-content/max-content constraint (respectively).

See [CSS3-SIZING] for a definition of the terms in this section.