> For the complete documentation index, see [llms.txt](https://marcylabschool.gitbook.io/swe/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://marcylabschool.gitbook.io/swe/mod-3-html-css/4-flexbox.md).

# 4. Flexbox

{% hint style="info" %}
Follow along with code examples [here](https://github.com/The-Marcy-Lab-School/3-4-flexbox)!
{% endhint %}

**Table of Contents**:

* [Key Concepts](#key-concepts)
* [Explore Flexbox on Youtube](#explore-flexbox-on-youtube)
* [Flexbox Puts Things In A Row](#flexbox-puts-things-in-a-row)
  * [Example](#example)
* [Controlling Flex Items](#controlling-flex-items)
  * [Flex Direction (Flex Container Property)](#flex-direction-flex-container-property)
  * [Gap (Flex Container Property)](#gap-flex-container-property)
  * [Flex (Flex Item Property)](#flex-flex-item-property)
  * [Justify Content (Flex Container Property)](#justify-content-flex-container-property)
  * [Align Items (Flex Container Property)](#align-items-flex-container-property)
  * [Flex Wrap (Flex Container Property)](#flex-wrap-flex-container-property)
* [Challenge: Styling a Navbar using Flexbox](#challenge-styling-a-navbar-using-flexbox)
* [Some More Examples!](#some-more-examples)

**Resources**:

* [A guide to flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/)
* [Learn Flexbox in 15 minutes](https://www.youtube.com/watch?v=fYq5PXgSsbE\&ab_channel=WebDevSimplified)
* [A great video to learn flexbox](https://www.youtube.com/watch?v=u044iM9xsWU\&ab_channel=KevinPowell)

## Key Concepts

* **Flexbox** - a `display` type that arranges flexible elements in a container in a row or column.
* **Flex Container** - the element with `display:flex`.
* **Flex Item** - an element inside of a flex container.
* **Main Axis** — the direction that flex items flow in, (set by `flex-direction` and in the `row` direction by default).
* **Cross Axis** — the direction perpendicular to the main axis.
* The essential **flex container properties** are:
  * `flex-direction` - Determines the direction flex items will be arranged. Defaults to `row` but can be set to `column` to arrange flex items vertically.
  * `justify-content` — defines the spacing along the **main axis**
  * `align-items` — defines the alignment of elements along the **cross axis**
  * `gap` — controls spacing *between* flex items (not on outer edges)
* The essential **flex item properties** are:
  * `flex-grow` — defines the amount a flex item will grow relative to its siblings when there is excess space.
  * `flex-shrink` — defines the amount a flex item will shrink relative to its siblings when there is not enough space.
  * `flex-basis` — defines the starting size of a flex item.
  * `flex` — used as shorthand for the above 3 properties.

## Explore Flexbox on Youtube

Open <https://www.youtube.com/> and see how elements shift in size as you resize the window.

![Three youtube videos in a row](/files/L402NdAvWX69YjdJvQ93)

<details>

<summary><strong>Q: Look at a row of video "cards". Are they <code>display:inline</code>, <code>display:block</code> or something else? Guess, then inspect the page!</strong></summary>

They are `display: flex;` elements!

</details>

## Flexbox Puts Things In A Row

**Flexbox** (Flexible Box Layout) is a CSS layout system designed for arranging elements in one dimension—either as a row or as a column.

To use Flexbox, you need two things:

1. A **flex container** (the parent)
2. **Flex items** (the children)

![Flex containers and flex items](/files/usGB5d6lL932mt7Z7tOD)

* The parent element gets the `display: flex` property, making it a **flex container**.
* The children of the flex container are referred to as **flex items**.

### Example

Consider the following HTML elements:

{% code title="0-flexbox-demo/index.html" %}

```html
<section id="letters-container">
  <p>A</p>
  <p>AB</p>
  <p>ABC</p>
  <p>ABCD</p>
  <p>ABCDE</p>
</section>
```

{% endcode %}

They are styled with background colors and some padding but are otherwise using their default `display`. By default these elements elements will stack on top of each other.

![block elements will stack on top of each other](/files/8oJxuXsFzXgv7mpkX1pd)

<details>

<summary><strong>Q: Why are they stacked on top of each other rather than side by side?</strong></summary>

By default, `p` elements will be block elements. Block elements always stack on top of each other and take up the full width available to them.

</details>

By adding `display: flex;` to the parent container, its children will be placed horizontally in a row!

```css
#letters-container {
  display: flex;
}
```

![Adding display:flex will place the flex items in a row](/files/ZeXmiFFxFLmFR7yDbfwo)

The flex items will all stretch vertically to have equal height but will only take up as much width as is needed.

## Controlling Flex Items

With Flexbox applied to the parent container, we gain access to a bunch of options for arranging the flex items inside.

We can control:

1. the direction that flex items flow with `flex-direction`
2. how much space is between flex items with `gap`
3. how the flex items grow or shrink along the main axis with `flex`
4. how flex items are spaced along the main axis with `justify-content`
5. how flex items are stretch and are positioned along the cross axis with `align-items`
6. whether or not flex items wrap when they can't fit in one line with \`flex-wrap\`\`

Let's jump into each!

### Flex Direction (Flex Container Property)

Flexbox has two axes, the **main axis** and the **cross axis**. Flex items flow along the main axis and, by default stretch along the cross axis.

![flexbox has two axes, the main axis and the cross axis](/files/MzqiXFdFajd6gL2EtnfF)

By default, the main axis runs in the "row" direction, arranged left to right.

We can arrange flex items in a column (top to bottom) by setting the `flex-direction` property to `column`:

```css
#letters-container {
  display: flex;
  flex-direction: column;
}
```

`flex-direction: column` changes the orientation of the main and cross axes.

* The main axis is now vertical (top to bottom)
* The cross axis is now horizontal (left to right)

Knowing the direction of these two axes plays an essential role in controlling how flex items behave inside of a flex container. Let's look at how!

### Gap (Flex Container Property)

Gap is perhaps the most useful feature of Flexbox. The `gap` property makes adding space between elements incredibly easy:

```css
#letters-container {
  display: flex;
  gap: 1rem;
}
```

Note that the gap will only be applied to the space between the elements, not before the first element and after the last element.

![](/files/Jadol2FJYMWvdCqJrIy8)

<details>

<summary><strong>Q: Why can't we just use margin to do this?</strong></summary>

Thus far, if we've wanted to put space between elements, we've had to rely on adding a `margin`. However, margins have a few behaviors that can be annoying to deal with:

* Margins are applied to all sides, making it difficult to only add space *between* elements (the first and last elements will have extra margin on top and bottom)
* Margins can overlap causing unexpected spacing

Gap solves these problems entirely!

</details>

### Flex (Flex Item Property)

The `flex` property controls how much a flex item will grow or shrink within a container when there is extra space.

By default, flex items will only take up as much space as they need. However, if there is extra space, flex items with the `flex` property will flex to take up that space.

![](/files/ACQ2DJHg6WaMKK5L9E3m)

```css
/* The flex property controls the relative "growth rate" of a flex item when there is excess space */
#letters-container>p {
  flex: 1;
}

/* Hovering over a flex item will cause it to grow 3x the size of other flex items */
#letters-container>p:hover {
  flex: 3;
}
```

With `flex: 1;` applied to all flex items, they will all attempt to share the extra space evenly.

With `flex: 3;` applied to the one hovered element, it will take 3 times as much extra space as the other elements.

{% hint style="info" %}
`flex` is a shorthand for the three properties `flex-grow`, `flex-shrink`, and `flex-basis`. Read more about [the flex property on MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/flex)!
{% endhint %}

### Justify Content (Flex Container Property)

By default, flex items will arrange themselves at the start of the *main axis* (left to right in the row direction) of the flex container. We can change this behavior using `justify-content`:

```css
#letters-container {
  display: flex;
  justify-content: space-between;
}
```

![Justify content values showing flex-start, flex-end, center, space-between, space-around](/files/un6ntkyKlsZqwHmc05C6)

### Align Items (Flex Container Property)

By default, flex items will stretch along the *cross axis*. We can change this behavior using `align-items`.

```css
#letters-container {
  display: flex;
  align-items: flex-start;
}
```

![Align items values showing flex-start, flex-end, center, stretch, baseline](/files/w9pLzJHlRKEpAQkzcBv2)

### Flex Wrap (Flex Container Property)

By default, flex items will all try to fit onto one line. If there isn't enough space, they will overflow.

Setting `flex-wrap: wrap`, flex items will be pushed to the next line when there isn't enough space.

![Alt text](/files/WQqYYeCAcZ58yO6h4BF5)

```css
.container {
  flex-wrap: nowrap | wrap | wrap-reverse;
}
```

## Challenge: Styling a Navbar using Flexbox

One of the most common uses of flexbox is to style a navigation bar. Open up the `1-navbar` file and look at the `<header>` element:

```html
<!-- Often, the header contains a logo and a nav component -->
<header>
  <p id="header-logo">Ben's Blog</p>
  <nav>
    <!-- It is common to put a ul inside with links as list items -->
    <ul id="nav-links">
      <li><a href="#">Home</a></li>
      <li><a href="#">About</a></li>
      <li><a href="#">Contact</a></li>
    </ul>
  </nav>
</header>
```

Below, you can see what the header currently looks like (left) and what we want it to look like (right). What is different?

![Without flexbox, items are aligned vertically. With flex box, we can align items horizontally with nice spacing](/files/dEAm19KWHwd9UooYY1uq)

**Q: How do we fix this?**

<details>

<summary><strong>Solution</strong></summary>

* Most elements are `display: block` which means they are stacked on top of each other.
* We can apply `display: flex` to a parent element to put its children in a row horizontally

```css
header {
  display: flex; /* Makes the header a flex container */
  justify-content: space-between; /* main-axis spacing */
  align-items: center; /* cross-axis spacing */
}

ul {
  display: flex;
  gap: 1rem; /* increasing spacing between flex items */
}
```

* The essential **flex container properties** are:
  * `justify-content` — defines alignment along the **main axis**
  * `align-items` — defines alignment along the **cross axis**
  * `gap` — controls spacing *between* flex items (not on outer edges)
  * `flex-direction` - defaults to `row` but can be set to `column` to arrange flex items vertically.

</details>

## Some More Examples!

* Check out the `3-photo-gallery/` directory for a cool example of using flexbox to make a wall-to-wall flexible photo gallery based on this post: [Adaptive Photo Layout With Flexbox](https://css-tricks.com/adaptive-photo-layout-with-flexbox/)
* [19 CSS Flexbox Examples](https://freefrontend.com/css-flexbox-examples/)
