In Flutter, why does SizedBox(width: 100, height: 100) returned as the root widget fill the whole screen, and how do you fix it?
answer
- root gets tight constraints
- tightFor applied with enforce()
- clamping never widens the range
- Center or Align loosens
- minimums drop to zero
basics
~20 sThe root receives tight constraints equal to the screen, and SizedBox clamps its own 100 by 100 request into them, so it has to be screen-sized. Putting Center or Align in between loosens the constraints so the request fits.
solid answer
~40 s`SizedBox` creates a `RenderConstrainedBox` with `BoxConstraints.tightFor(width: 100, height: 100)`, but it applies those with `enforce()`, which clamps its wish into whatever the parent allowed. In a regular full-screen app the root box gets tight constraints equal to the view size, so min equals max, and clamping 100 into that single value gives the screen size. The SizedBox isn't broken; it has no choice. The fix is an ancestor that loosens the constraints: `Center` or `Align` pass `constraints.loosen()` (minimums zero, maximums kept), so 100 by 100 now fits, and they also position the box. `ConstrainedBox` or `Padding` do not help, because they keep a tight range tight. The same surprise appears anywhere a parent passes tight constraints, such as a vertical list's cross axis.
code
dart · 21 linesimport 'package:flutter/material.dart';
// Fills the screen: the root's tight constraints win.
void main() => runApp(
const SizedBox(
width: 100,
height: 100,
child: ColoredBox(color: Colors.teal),
),
);
// A 100 x 100 square in the middle: Center loosens first.
void mainFixed() => runApp(
const Center(
child: SizedBox(
width: 100,
height: 100,
child: ColoredBox(color: Colors.teal),
),
),
);go deeper
Recall that the root is forced to the screen size and that wrapping the box in Center fixes it.
Explain enforce(): the request is clamped into the parent's range, tight constraints leave one legal value, and Center or Align pass loosened constraints so the request fits.
Spot the same pattern in lists and fixed-size parents, and choose between Align, UnconstrainedBox or restructuring based on whether the child should be allowed to exceed its parent.
Use the example to show reviewers why sizing widgets are requests, and set team conventions (alignment parents, no magic sizes at the root) that keep screens predictable across device sizes.
## The symptom A classic interview snippet is a `runApp` or `build` method that returns `SizedBox(width: 100, height: 100, child: ColoredBox(color: ...))` directly. Beginners expect a small square in the corner. Instead the colour fills the screen. The same thing happens with `Container(width: 100, height: 100)`. The question is designed to check whether you understand **tight constraints** and how sizing widgets combine their request with what the parent allows. ## What SizedBox actually does `SizedBox` is a thin widget over `RenderConstrainedBox`. - With both dimensions set, it builds `BoxConstraints.tightFor(width: 100, height: 100)`, meaning min width = max width = 100 and the same for height. - `RenderConstrainedBox` does not pass those to its child directly. It computes `additionalConstraints.enforce(constraints)`, where `constraints` came from the parent. - `enforce()` **clamps each of the four values into the parent's range**. It can narrow what the parent allowed; it can never widen it. So a sizing widget adds a limit inside the parent's limits. That is the key sentence to say in the interview. ## Why the root is tight The root render object, the view, turns the window's size into `BoxConstraints` for the app's top widget. For a normal full-screen app that is a **tight** constraint: min width equals max width equals the screen width, and likewise for height. The root widget has exactly one legal size. Now run the clamp: | Value | SizedBox asks | Parent allows | `enforce()` result | |---|---|---|---| | minWidth | 100 | 400-400 | 400 | | maxWidth | 100 | 400-400 | 400 | | minHeight | 100 | 800-800 | 800 | | maxHeight | 100 | 800-800 | 800 | The SizedBox is 400 by 800 on that device. Its 100 by 100 is not ignored out of carelessness; there is simply no room to honour it. ## The fix: loosen before you size Insert a widget whose job is to transform tight constraints into loose ones: 1. **`Center`** (a pre-configured `Align`) lays out its child with `constraints.loosen()`: minimums become zero, maximums stay. The child may now be anywhere from 0 to 400 wide. 2. The `SizedBox` clamps 100 into 0-400 and keeps 100. 3. `Center` sizes itself. With bounded constraints and no `widthFactor`/`heightFactor`, it becomes as large as allowed (the whole screen) and places the 100 by 100 child in the middle. `Align` with any `alignment`, or `Container(alignment: ...)`, which wraps its child in `Align`, work the same way. `UnconstrainedBox` also works, but it removes the maximums too, so a child larger than the screen will overflow. Widgets that look like they should help but don't: - **`ConstrainedBox(constraints: BoxConstraints(maxWidth: 100))`** — it uses the same `enforce()` step, so under tight constraints it is still screen-sized. - **`Padding`** — it deflates the constraints by the padding. Tight stays tight: the child must be exactly 'screen minus padding'. - **A second `SizedBox`** around the first — it is clamped to the screen just the same. ## Where else it bites The root is the textbook case, but the pattern shows up wherever a parent passes tight constraints: - A box inside `SizedBox.expand` or any fixed-size parent without alignment. - Items of a vertical scrolling list receive a **tight cross-axis** width equal to the list's width, so `SizedBox(width: 100)` as a list item still spans the full width. - A child of a flex widget laid out with a tight fit, for example inside `Expanded`. In each case the diagnosis is the same: find the ancestor that made the constraints tight and add an `Align`/`Center` below it if the child should keep its own size. ## How to explain it in one breath 'SizedBox is a request clamped into the parent's constraints. The root's constraints are tight to the screen, so the only legal size is the screen. Put Center or Align in between: they loosen the minimum to zero, so the request fits, and they decide where the box sits.'
- Would ConstrainedBox(constraints: BoxConstraints(maxWidth: 100)) at the root make it narrower?No. `ConstrainedBox` applies its constraints with the same `enforce()` clamp, so it can only narrow within the parent's range. Under tight screen constraints the range is a single value, and the result is still screen-sized. Constraint widgets add limits; removing a minimum the parent imposed takes a loosening ancestor such as `Center`, `Align` or `UnconstrainedBox`.
- How big is the Center itself in that fix?`Center` is an `Align`. When its incoming constraints are bounded and no `widthFactor` or `heightFactor` is set, it sizes itself as large as allowed, here the full screen, and positions the child inside. It shrink-wraps the child only on an axis whose incoming maximum is infinite or when a size factor is given.
- Why does SizedBox(width: 100) as an item in a vertical ListView still span the full width?A vertical list lays out box children with a tight cross-axis constraint: min width equals max width equals the list's width. The SizedBox clamps 100 into that single value. Wrapping the item's content in `Align` (for example `Align(alignment: Alignment.centerLeft, ...)`) loosens the width so the 100-pixel request survives.
saying these in an interview costs you the question
- SizedBox at the root is ignored because of a framework bug.
- A ConstrainedBox with a smaller maxWidth forces the root to shrink.
- Padding loosens the constraints, so the SizedBox can keep 100 by 100.
- Center always shrinks to the size of its child.
- Setting both width and height makes a SizedBox's size absolute.