MainAxis & CrossAxis Alignment
Understanding Axes in Flutter
Every Row and Column has two axes: the main axis and the cross axis. Understanding how these axes work is essential for controlling the position and spacing of children within a layout widget.
- Row: Main axis = horizontal (left to right), Cross axis = vertical (top to bottom)
- Column: Main axis = vertical (top to bottom), Cross axis = horizontal (left to right)
Flutter provides two key properties to control alignment along these axes: mainAxisAlignment and crossAxisAlignment.
MainAxisAlignment
The mainAxisAlignment property controls how children are distributed along the main axis. There are six options:
MainAxisAlignment.start
Places children at the beginning of the main axis. This is the default value.
MainAxisAlignment.start
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(width: 60, height: 60, color: Colors.red),
Container(width: 60, height: 60, color: Colors.green),
Container(width: 60, height: 60, color: Colors.blue),
],
)
// Result: [Red][Green][Blue].................
MainAxisAlignment.end
Places children at the end of the main axis.
MainAxisAlignment.end
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Container(width: 60, height: 60, color: Colors.red),
Container(width: 60, height: 60, color: Colors.green),
Container(width: 60, height: 60, color: Colors.blue),
],
)
// Result: .................[Red][Green][Blue]
MainAxisAlignment.center
Centers children along the main axis.
MainAxisAlignment.center
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(width: 60, height: 60, color: Colors.red),
Container(width: 60, height: 60, color: Colors.green),
Container(width: 60, height: 60, color: Colors.blue),
],
)
// Result: ........[Red][Green][Blue]........
MainAxisAlignment.spaceBetween
Distributes extra space evenly between children. The first child touches the start edge and the last child touches the end edge.
MainAxisAlignment.spaceBetween
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(width: 60, height: 60, color: Colors.red),
Container(width: 60, height: 60, color: Colors.green),
Container(width: 60, height: 60, color: Colors.blue),
],
)
// Result: [Red]........[Green]........[Blue]
MainAxisAlignment.spaceAround
Distributes extra space evenly, with half the space before the first child and after the last child.
MainAxisAlignment.spaceAround
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Container(width: 60, height: 60, color: Colors.red),
Container(width: 60, height: 60, color: Colors.green),
Container(width: 60, height: 60, color: Colors.blue),
],
)
// Result: ..[Red]....[Green]....[Blue]..
MainAxisAlignment.spaceEvenly
Distributes extra space evenly, including equal space before the first child and after the last child.
MainAxisAlignment.spaceEvenly
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(width: 60, height: 60, color: Colors.red),
Container(width: 60, height: 60, color: Colors.green),
Container(width: 60, height: 60, color: Colors.blue),
],
)
// Result: ...[Red]...[Green]...[Blue]...
spaceAround and spaceEvenly is subtle but important. With spaceAround, edge spacing is half the inter-child spacing. With spaceEvenly, all gaps are identical.CrossAxisAlignment
The crossAxisAlignment property controls how children are positioned along the cross axis. There are five options:
CrossAxisAlignment.center (default)
Centers children along the cross axis.
CrossAxisAlignment.center
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(width: 60, height: 40, color: Colors.red),
Container(width: 60, height: 80, color: Colors.green),
Container(width: 60, height: 60, color: Colors.blue),
],
)
CrossAxisAlignment.start
Aligns children at the start of the cross axis (top for Row, left for Column).
CrossAxisAlignment.start
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(width: 60, height: 40, color: Colors.red),
Container(width: 60, height: 80, color: Colors.green),
Container(width: 60, height: 60, color: Colors.blue),
],
)
CrossAxisAlignment.end
Aligns children at the end of the cross axis (bottom for Row, right for Column).
CrossAxisAlignment.end
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Container(width: 60, height: 40, color: Colors.red),
Container(width: 60, height: 80, color: Colors.green),
Container(width: 60, height: 60, color: Colors.blue),
],
)
CrossAxisAlignment.stretch
Stretches children to fill the entire cross axis. This is extremely useful for making all children the same height in a Row or the same width in a Column.
CrossAxisAlignment.stretch
SizedBox(
height: 100,
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(width: 60, color: Colors.red),
Container(width: 60, color: Colors.green),
Container(width: 60, color: Colors.blue),
],
),
)
// All three containers are now 100px tall
CrossAxisAlignment.stretch, the parent must have a finite size on the cross axis. For a Row, the parent must have a defined height. For a Column, the parent must have a defined width. Otherwise, Flutter cannot determine what size to stretch to.CrossAxisAlignment.baseline
Aligns children along their text baseline. This is essential when you have text of different sizes that should line up at the bottom of the letters. You must also set the textBaseline property when using this alignment.
CrossAxisAlignment.baseline
Row(
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: <Widget>[
Text('Large', style: TextStyle(fontSize: 40)),
Text('Medium', style: TextStyle(fontSize: 24)),
Text('Small', style: TextStyle(fontSize: 14)),
],
)
// All three text widgets align at their text baseline
The textBaseline Property
When using CrossAxisAlignment.baseline, you must specify which baseline to use:
- TextBaseline.alphabetic -- Aligns at the bottom of alphabetic characters (most common for Latin, Arabic, and similar scripts).
- TextBaseline.ideographic -- Aligns at the bottom of ideographic characters (used for CJK scripts like Chinese, Japanese, Korean).
CrossAxisAlignment.baseline without setting textBaseline, Flutter will throw an assertion error at runtime. Always pair them together.How Alignment Differs for Row vs Column
The same alignment property behaves differently depending on whether you use it in a Row or Column because the axes are swapped:
Same Alignment, Different Widget
// In a Row: children are centered HORIZONTALLY
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [Text('A'), Text('B'), Text('C')],
)
// In a Column: children are centered VERTICALLY
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [Text('A'), Text('B'), Text('C')],
)
// In a Row: children are stretched VERTICALLY
Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [Container(width: 50, color: Colors.red)],
)
// In a Column: children are stretched HORIZONTALLY
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [Container(height: 50, color: Colors.red)],
)
Practical Example: Centered Content
A common pattern is centering content both horizontally and vertically on the screen:
Fully Centered Content
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.check_circle, size: 80, color: Colors.green),
SizedBox(height: 16),
Text(
'Success!',
style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
),
SizedBox(height: 8),
Text(
'Your order has been placed.',
style: TextStyle(fontSize: 16, color: Colors.grey),
),
],
),
)
Practical Example: Evenly Spaced Navigation
Bottom navigation bars often use evenly-spaced items:
Bottom Navigation Layout
Container(
padding: EdgeInsets.symmetric(vertical: 8),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 4)],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Column(
mainAxisSize: MainAxisSize.min,
children: [Icon(Icons.home, color: Colors.blue), Text('Home', style: TextStyle(fontSize: 12))],
),
Column(
mainAxisSize: MainAxisSize.min,
children: [Icon(Icons.search, color: Colors.grey), Text('Search', style: TextStyle(fontSize: 12))],
),
Column(
mainAxisSize: MainAxisSize.min,
children: [Icon(Icons.favorite, color: Colors.grey), Text('Favorites', style: TextStyle(fontSize: 12))],
),
Column(
mainAxisSize: MainAxisSize.min,
children: [Icon(Icons.person, color: Colors.grey), Text('Profile', style: TextStyle(fontSize: 12))],
),
],
),
)
Practical Example: Baseline-Aligned Text
When displaying a price with currency, the numbers and currency symbol should align at the baseline:
Price Display with Baseline Alignment
Row(
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: <Widget>[
Text('\$', style: TextStyle(fontSize: 20, color: Colors.grey)),
Text('49', style: TextStyle(fontSize: 48, fontWeight: FontWeight.bold)),
Text('.99', style: TextStyle(fontSize: 20, color: Colors.grey)),
Text('/month', style: TextStyle(fontSize: 14, color: Colors.grey)),
],
)
Without baseline alignment, the different text sizes would be centered vertically by default, creating an unnatural look. Baseline alignment ensures all text sits on the same visual line.
Summary
- MainAxisAlignment controls distribution along the layout direction: start, end, center, spaceBetween, spaceAround, spaceEvenly.
- CrossAxisAlignment controls positioning perpendicular to the layout: start, end, center, stretch, baseline.
- The axes swap between Row (horizontal main) and Column (vertical main).
- Use
CrossAxisAlignment.stretchto make all children fill the cross axis -- requires a bounded parent. - Use
CrossAxisAlignment.baselinewithtextBaselineto align text of different sizes. spaceEvenlydistributes equal gaps everywhere;spaceAroundgives half-gaps at edges;spaceBetweenhas no edge gaps.