# Part 3: Flexbox

## Introduction

Before Flexbox, building a horizontal navigation bar or vertically centring content required floats, negative margins, or table hacks. Flexbox changed that. It is the layout system I reach for most often — any time I need to align or distribute items along a single axis, Flexbox is the right tool.

This part covers every Flexbox property I use, the mental model behind it, and the patterns that show up repeatedly in real layouts.

***

## The Flexbox Mental Model

Flexbox operates on two elements: a **flex container** and its direct **flex items**.

```html
<div class="container">   <!-- flex container -->
  <div class="item">A</div>
  <div class="item">B</div>
  <div class="item">C</div>
</div>
```

```css
.container {
  display: flex;  /* activates flexbox */
}
```

Flexbox introduces two axes:

* **Main axis** — the primary direction items are laid out (default: horizontal, left to right)
* **Cross axis** — perpendicular to the main axis (default: vertical)

All Flexbox properties interact with these two axes.

***

## Container Properties

### `flex-direction`

Sets the main axis direction.

```css
.container {
  flex-direction: row;             /* default: left to right */
  flex-direction: row-reverse;     /* right to left */
  flex-direction: column;          /* top to bottom */
  flex-direction: column-reverse;  /* bottom to top */
}
```

When `flex-direction: column`, the main axis becomes vertical and the cross axis becomes horizontal.

### `flex-wrap`

By default, flex items try to fit on one line and shrink if needed. `flex-wrap` controls this:

```css
.container {
  flex-wrap: nowrap;    /* default: single line, items may shrink */
  flex-wrap: wrap;      /* items wrap to new lines when needed */
  flex-wrap: wrap-reverse;  /* wraps to lines above */
}
```

### `flex-flow` Shorthand

```css
/* flex-direction + flex-wrap */
.container {
  flex-flow: row wrap;
  flex-flow: column nowrap;
}
```

### `justify-content`

Aligns items along the **main axis**.

```css
.container {
  justify-content: flex-start;     /* default: pack to start */
  justify-content: flex-end;       /* pack to end */
  justify-content: center;         /* centre */
  justify-content: space-between;  /* equal gaps between items, none at edges */
  justify-content: space-around;   /* equal gaps including half-gap at edges */
  justify-content: space-evenly;   /* equal gaps including full gap at edges */
}
```

`space-between` is what I use for navigation bars where items should spread evenly. `center` is what I use when centring a single element or group.

### `align-items`

Aligns items along the **cross axis**.

```css
.container {
  align-items: stretch;      /* default: items stretch to fill container height */
  align-items: flex-start;   /* align to start of cross axis */
  align-items: flex-end;     /* align to end of cross axis */
  align-items: center;       /* centre on cross axis */
  align-items: baseline;     /* align text baselines */
}
```

`align-items: center` combined with `justify-content: center` is the shortest path to perfectly centring an element:

```css
.centred-wrapper {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
}
```

### `align-content`

When items wrap onto multiple lines (`flex-wrap: wrap`), `align-content` distributes those lines along the cross axis. It has no effect with a single line.

```css
.container {
  flex-wrap: wrap;
  align-content: flex-start;
  align-content: flex-end;
  align-content: center;
  align-content: space-between;
  align-content: space-around;
  align-content: stretch;   /* default */
}
```

### `gap`

Sets gaps between flex items without margin.

```css
.container {
  display: flex;
  gap: 1rem;             /* same for both axes */
  gap: 1rem 2rem;        /* row-gap column-gap */
  row-gap: 1rem;
  column-gap: 2rem;
}
```

`gap` does not add space at the edges of the container — only between items. This is preferable to using `margin` on items because it does not add unwanted space at the start or end.

***

## Item Properties

These properties are set on the flex **items** (children), not the container.

### `flex-grow`

Controls how much an item grows to fill available space. The value is a proportion.

```css
.item-a { flex-grow: 1; }  /* takes 1 share */
.item-b { flex-grow: 2; }  /* takes 2 shares — twice as wide as item-a */
.item-c { flex-grow: 0; }  /* default: does not grow */
```

All items with `flex-grow: 1` share available space equally.

### `flex-shrink`

Controls how much an item shrinks when there is not enough space.

```css
.item {
  flex-shrink: 1;   /* default: items shrink proportionally */
  flex-shrink: 0;   /* item will not shrink below its flex-basis */
}
```

### `flex-basis`

Sets the initial size of an item before grow/shrink is applied. Can be a length or a keyword.

```css
.item {
  flex-basis: auto;      /* default: use width/height */
  flex-basis: 0;         /* start from 0, all size comes from flex-grow */
  flex-basis: 200px;     /* fixed starting size */
  flex-basis: 25%;       /* percentage of container */
}
```

### `flex` Shorthand

`flex: grow shrink basis` — the shorthand I use in practice:

```css
flex: 0 1 auto;   /* default */
flex: 1;          /* flex: 1 1 0 — grow equally, shrink equally, start from 0 */
flex: auto;       /* flex: 1 1 auto — grow, shrink, size from content */
flex: none;       /* flex: 0 0 auto — no grow, no shrink, fixed size */
flex: 0 0 200px;  /* neither grow nor shrink, stay at 200px */
```

The most common value in real layouts is `flex: 1` — makes an item expand to fill available space equally with its siblings.

### `align-self`

Overrides `align-items` for an individual item.

```css
.item-special {
  align-self: flex-start;   /* even if container has align-items: center */
}
```

### `order`

Changes the visual order of items without changing the DOM order.

```css
.item-first {
  order: -1;    /* moves before all default (order: 0) items */
}

.item-last {
  order: 1;     /* moves after all default items */
}
```

Use `order` with caution — it creates a disconnect between DOM order (used by screen readers and keyboard navigation) and visual order.

***

## Common Flexbox Patterns

### Horizontal Navigation Bar

```css
.nav {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.nav__logo {
  margin-right: auto;  /* push remaining items to the right */
}
```

```html
<nav class="nav">
  <a href="/" class="nav__logo">Brand</a>
  <a href="/docs">Docs</a>
  <a href="/blog">Blog</a>
  <a href="https://github.com/Htunn" target="_blank" rel="noopener noreferrer">GitHub</a>
</nav>
```

The `margin-right: auto` on the logo consumes all available space and pushes the rest of the links to the right — a common and clean technique.

### Card Row That Wraps

```css
.card-list {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
}

.card {
  flex: 1 1 280px;   /* grow, shrink, but don't go below 280px */
  max-width: 100%;
}
```

Cards grow to fill the row but wrap when they would shrink below 280px.

### Vertically Centred Full-Page Layout

```css
.page-wrapper {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.page-content {
  flex: 1;   /* grows to push footer down */
}
```

### Sidebar Layout

```css
.layout {
  display: flex;
  gap: 2rem;
  align-items: flex-start;
}

.sidebar {
  flex: 0 0 240px;   /* fixed width sidebar */
  position: sticky;
  top: 2rem;
}

.main-content {
  flex: 1;           /* takes remaining space */
  min-width: 0;      /* prevents overflow on narrow screens */
}
```

The `min-width: 0` on flex items is important — flex items have an implicit `min-width: auto` which can cause overflow when the content (like long code blocks or tables) is wider than available space.

### Centring Anything

```css
.centre {
  display: flex;
  align-items: center;
  justify-content: center;
}
```

***

## `min-width: 0` — The Classic Flex Gotcha

A flex item's minimum width defaults to `auto`, meaning it cannot shrink below the size of its content. This causes overflow with long text, code blocks, or tables inside flex items.

```css
/* Without this, code blocks or long words can overflow */
.flex-child {
  min-width: 0;
  overflow: hidden;
}
```

This is the fix I apply whenever a flex item with text content overflows unexpectedly.

***

## Debugging Flexbox

Browser developer tools (Chrome, Firefox, Edge) have dedicated Flexbox inspectors. In Chrome DevTools:

* Select a flex container
* The Layout panel shows the flex configuration visually
* The overlay in the Elements panel highlights flex lines and gaps

Turning off `flex-wrap` temporarily can reveal whether items are shrinking more than expected.

***

## Summary

| Property          | Applies to | Purpose                                  |
| ----------------- | ---------- | ---------------------------------------- |
| `display: flex`   | Container  | Activates flexbox                        |
| `flex-direction`  | Container  | Sets main axis direction                 |
| `flex-wrap`       | Container  | Whether items wrap                       |
| `justify-content` | Container  | Main axis alignment                      |
| `align-items`     | Container  | Cross axis alignment (single line)       |
| `align-content`   | Container  | Cross axis alignment (multiple lines)    |
| `gap`             | Container  | Space between items                      |
| `flex-grow`       | Item       | How much item grows                      |
| `flex-shrink`     | Item       | How much item shrinks                    |
| `flex-basis`      | Item       | Initial size before grow/shrink          |
| `flex`            | Item       | Shorthand for grow/shrink/basis          |
| `align-self`      | Item       | Cross axis override for one item         |
| `order`           | Item       | Visual reordering                        |
| `min-width: 0`    | Item       | Fix for shrinking/overflow in flex items |

***

## Up Next

[Part 4](https://blog.htunnthuthu.com/getting-started/programming/css-101/css-101-part-4) covers CSS Grid — the two-dimensional layout system for complex page structures.
