Explain the difference between mainAxisAlignment and crossAxisAlignment
2 min read
Widgets & Layout
| Widget | Main axis | Cross axis |
|---|---|---|
Row | Horizontal (→) | Vertical (↕) |
Column | Vertical (↓) | Horizontal (↔) |
mainAxisAlignment divides the free space along the main axis. crossAxisAlignment decides where each child sits in the perpendicular dimension.
Visualising the options
Row with three boxes A, B, C:
start [A][B][C]___________
end ___________[A][B][C]
center _____[A][B][C]______
spaceBetween [A]______[B]______[C]
spaceAround __[A]___[B]___[C]__
spaceEvenly ___[A]___[B]___[C]___
crossAxisAlignment (Row, so vertical):
start align children to top
end align children to bottom
center centred vertically (default)
stretch stretch each child to fill height (child can't have height)
baseline align text baselines (must set textBaseline)
Code in action
// Navbar — items spread evenly
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: const [Icon(Icons.home), Icon(Icons.search), Icon(Icons.person)],
);
// Form fields — stretch to full width
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextField(decoration: const InputDecoration(labelText: 'Email')),
TextField(decoration: const InputDecoration(labelText: 'Password')),
ElevatedButton(onPressed: () {}, child: const Text('Login')),
],
);
// Centre a success state
Column(
mainAxisAlignment: MainAxisAlignment.center, // vertical centring
crossAxisAlignment: CrossAxisAlignment.center, // horizontal centring
children: const [Icon(Icons.check, size: 64), Text('Done')],
);
When to reach for which
| You want… | Use |
|---|---|
| Push children to one end | mainAxisAlignment: start / end |
| Spread items out (toolbar, footer) | spaceBetween / spaceAround / spaceEvenly |
| Centre everything | both axes set to center |
| Make column items full-width | crossAxisAlignment: stretch (no width on children) |
| Align text by baseline (mixed font sizes) | crossAxisAlignment: baseline + textBaseline |
Common mistakes to avoid
// ❌ mainAxisAlignment doing nothing
Row(
mainAxisSize: MainAxisSize.min, // shrink-wraps children
mainAxisAlignment: MainAxisAlignment.spaceBetween, // no free space → no effect
children: [...],
);
// ✅ Use the default mainAxisSize.max, or rethink the layout
// ❌ stretch on a child that already has a size
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [SizedBox(width: 100, child: ...)], // SizedBox width fights stretch
);
// ❌ Confusing axes between Row and Column
Column(mainAxisAlignment: MainAxisAlignment.center) // centres VERTICALLY, not horizontally
// ✅ For Column horizontal centring → crossAxisAlignment.center
// ❌ Forgetting textBaseline with baseline alignment
Row(
crossAxisAlignment: CrossAxisAlignment.baseline, // must also set textBaseline
);
Interview follow-ups
-
Why does
mainAxisAlignment: spaceBetweensometimes have no visible effect? Because there's no free space along the main axis. Common causes:mainAxisSize: MainAxisSize.min(the Row only wraps its children), or the Row is inside a parent that gave it unbounded width. -
What's the difference between
mainAxisSize.minandmainAxisSize.max?max(default) makes the Row/Column fill the available main-axis space — needed forspaceBetweenetc. to have anything to distribute.minshrink-wraps to just the children. -
Why does
crossAxisAlignment: stretchclash with sized children?stretchtries to force each child to fill the cross axis. If a child already declares its own cross-axis size (e.g.SizedBox(width: 100)inside a Column), you get conflicting constraints and Flutter complains or unexpectedly clamps. -
How do
SpacerandExpandedinteract withmainAxisAlignment? They consume the free space themselves — once a Flex hasExpanded/Spacerchildren, there's nothing left formainAxisAlignmentto distribute, so it effectively becomes a no-op.
How helpful was this content?
Please sign in to rate this article.