skip to content

In Flutter layout, what does the rule 'constraints go down, sizes go up, parent sets position' mean for a widget?

level: juniorimportance: must knowfreq 80%

answer

  1. four doubles from the parent
  2. child picks a size inside them
  3. size reported back up
  4. parent writes the child's offset
  5. child never learns its position

basics

~20 s

Each parent passes BoxConstraints (min and max width and height) down, each child picks a size inside them and reports it up, and the parent then places the child. A widget cannot choose its position or a size outside its constraints.

solid answer

~40 s

Flutter lays out its render tree in one pass. A parent hands each child a `BoxConstraints`: four doubles, `minWidth`, `maxWidth`, `minHeight`, `maxHeight`. The child lays out its own children the same way, picks a `Size` that satisfies its constraints and reports it back. Only then does the parent position the child by storing an offset the child never reads. Interviewers want two consequences: a widget usually can't be any size it wants, because a request outside the constraints is clamped, and a widget can't know or decide where it is on screen. To predict a widget's size you look at what its parent passed down, not only at its own `width` and `height`.

go deeper

for a junior

Recite the rule and the four doubles in BoxConstraints, then say that a widget cannot pick its own position or a size outside what its parent allows.

for a middle

Walk through the negotiation step by step and use it to explain one surprise, such as a SizedBox that ends up bigger than requested.

for a senior

Use the rule as a debugging method: trace which ancestor tightened, loosened or removed a constraint before reaching for a fix or a tool.

for a principal

Explain why a one-pass, parent-positions protocol keeps layout cheap during animations, and what design constraints that places on custom layout widgets a team writes.

## The rule in one sentence Flutter's layout documentation compresses the whole box protocol into one line: **constraints go down, sizes go up, parent sets position**. Every visible widget is backed by a render object, and for ordinary rectangular widgets that object is a `RenderBox`. Layout is a conversation between each `RenderBox` and its parent, and it happens top-down, in a **single pass** over the tree, once per frame for every box that needs layout. ## What a constraint is A constraint is a `BoxConstraints` object: four doubles. - `minWidth` and `maxWidth` — the range the width must fall into. - `minHeight` and `maxHeight` — the range the height must fall into. - The default constructor gives `0` for the minimums and `double.infinity` for the maximums, meaning 'anything goes'. - A **size** is simply a `Size(width, height)`; it is valid when it lies inside all four bounds. The constraint says what the child is *allowed* to be. It never says where the child is. ## The negotiation, step by step The Flutter docs walk through a padded column inside a 300 by 85 area. Generalised, every box does this: 1. **Receive constraints** from the parent, for example width 0-300 and height 0-85. 2. **Derive child constraints.** A widget with 5 pixels of padding tells its first child: width 0-290, height 0-75. Each child can get different constraints. 3. **Ask each child for its size.** The first child answers 290 by 20; the parent now knows only 55 pixels of height remain for the second child and constrains it accordingly. 4. **Position the children.** The parent decides the first child sits at (5, 5) and the second at (80, 25). The offset is stored in the child's parent data, which belongs to the parent. 5. **Report its own size** upward, within the constraints it received: say 300 by 60. That is the whole algorithm. The same five steps repeat at every level of the tree. ## What a widget can and cannot do The rule produces limitations that explain most 'why is my widget the wrong size' questions: - A widget **can decide its size only within its constraints**. `SizedBox(width: 100)` is a request, and if the parent's minimum width is 400, the box is 400 wide. - A widget **can't know or decide its own position**. Alignment is always the parent's job, which is why you wrap a child in `Center` or `Align` rather than giving the child an x and y. - Because the parent's constraints depend on *its* parent, you can't determine a widget's size without looking at the ancestors that shaped its constraints. - If a child wants a different size from its parent and the parent has no alignment rule, the child's wish may simply be ignored. The docs' advice is: **be specific when defining alignment**. | Direction | What travels | Who decides | |---|---|---| | Down | `BoxConstraints` (min/max width and height) | Parent | | Up | `Size` | Child, inside the constraints | | Sideways (after sizing) | Offset in parent data | Parent | ## Why Flutter works this way The protocol is designed so layout is **one pass**: each box is laid out once, and the information it needs flows in one direction at a time. That keeps layout roughly linear in the number of boxes, even for deep trees rebuilt every frame during an animation. A child that has reported its size cannot come back and ask for more room in the same pass, so the parent's constraints are final. This is a different model from layout systems that measure every element and then arrange it in a second full pass; in Flutter the parent sizes children as it goes. A second benefit is that position changes are cheap. A child does not know its position, so moving it (a parent changing the offset) does not necessarily mean laying it out again or repainting it. ## Using the rule to debug When a widget ends up the wrong size, walk upward and ask three questions: 1. What constraints did this widget receive? Tight (min equals max), loose (min zero) or unbounded (max infinite)? 2. Which ancestor produced those constraints, and did it tighten, loosen or remove them? 3. Did the widget's own request fit inside them, or was it clamped? Most layout puzzles — a `SizedBox` that fills the screen, a `Text` in a `Row` that overflows instead of wrapping, a box that throws 'BoxConstraints forces an infinite width' — are answered by those three questions before you open any tool.

  • Can a Flutter widget read its own screen position while it is being laid out?
    No. During layout a child receives only constraints and returns a size; the parent sets the offset afterwards in the child's parent data (for most boxes `BoxParentData.offset`). Code that needs the position must ask after layout, for example `RenderBox.localToGlobal` from a post-frame callback, and it should expect the answer to change when the parent moves the child.
  • Why does it matter that Flutter layout is a single pass?
    Each box is laid out once per frame: constraints travel down and sizes travel up in the same traversal, so layout cost stays roughly linear in the number of boxes. The trade-off is that the parent's constraints are final for that pass. A child cannot report a size and then negotiate for more room, so a request that does not fit is clamped or overflows.

Layout is like a parent handing a child a cardboard box with a minimum and maximum size marked on it: the child chooses how big to be within those marks and says so, and the parent then decides where on the shelf to put the box.

saying these in an interview costs you the question

  • A widget's width and height properties always decide its final size.
  • Layout runs a full measure pass and then a separate arrange pass.
  • A child reads its x and y position from the constraints it receives.
  • Constraints travel upward from children to their parent.
  • Alignment is set on the child itself rather than by a parent.