Flutter Layouts & Responsive Design

MainAxis & CrossAxis Alignment

45 min Lesson 2 of 16

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.

Note: Always think about which widget you are using (Row or Column) before applying alignment. The same alignment value produces different visual results depending on whether the main axis is horizontal or vertical.

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]...
Tip: The difference between 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
Warning: When using 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).
Note: If you use 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.stretch to make all children fill the cross axis -- requires a bounded parent.
  • Use CrossAxisAlignment.baseline with textBaseline to align text of different sizes.
  • spaceEvenly distributes equal gaps everywhere; spaceAround gives half-gaps at edges; spaceBetween has no edge gaps.