Flexbox Rocks!
Tags: css, beginners, webdev, tutorial
Published: 2020-08-24 19:17:21

#Introduction

Yesterday I refactored a [Codesandbox](https://codesandbox.io/s/flexbox-practice-xji8g?file=/src/styles.css) with Flexbox, which displays cards of "Powerful People", their names, roles, hobbies and a picture. 

I wanted to accomplish two things. 
* structure the card itself using flexbox.
* display all the cards in either a responsive row of cards on wider screens, or a single column of cards on narrow screens.

The card.
![Screenshot of Flexbox layout card ](https://dev-to-uploads.s3.amazonaws.com/i/hqdgrf4lsm0bid8at1ld.jpeg)

The cards in flexbox row on wider screen.
![Screenshot of all the cards in flexbox rows widescreen](https://dev-to-uploads.s3.amazonaws.com/i/lqsrb3w7miof846x0l85.jpg)

The cards in a flexbox column on narrower screen.
![Screen shot of cards in flexbos column on narrow screen](https://dev-to-uploads.s3.amazonaws.com/i/g5dxl4d2bck3tmoz8b8s.jpg)

This post will attempt to breakdown not only how I did this with CSS and HTML, but also the process of designing the card beforehand.

##Step One - Design

I use [Excalidraw](https://excalidraw.com/) to mock up elements on a website. Excalidraw lets you quickly see your ideas on the screen and gives you a handy reference when you begin coding. 

I came up with this mockup for the card.

![Excalidraw card mockup](https://dev-to-uploads.s3.amazonaws.com/i/3nohj397hex5ut9l8c0s.jpg)

And the layout for all the cards.
![Excalidraw mockup for all the cards in rows](https://dev-to-uploads.s3.amazonaws.com/i/3980whni9xuf8isqg1h1.jpg)

Looks pretty good. Now the hard hard part is making my cards look and behave like I want. 

## Flexbox resources

![Flexbox Froggy frogs sitting on lily pads](https://dev-to-uploads.s3.amazonaws.com/i/vkpj09kxuhp1183s3y9a.jpeg)

If you have never tried to use CSS flex properties before, I highly recommend playing around with [Flexbox Froggy](https://flexboxfroggy.com/), which sort of makes learning flexbox a game. I promise if you go through the tutorial a couple times, you will have a much better idea of how to use flexbox. 

Another great resource is CSS-Tricks' [A Complete Guide to Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/).

## Step Two - Understanding Your Design

I started to understand flexbox when I started to imagine every element on the screen as its own mini screen. For example, the card is its own contained environment. The inner contents of the card do not (have to) care about the elements outside of it. And the layout that ALL the cards live in is ITS own environment. It does not (have to) care about the other elements on the screen.

I think it helps to start with the outermost "environment" (represented by a `<div>` in your HTML) and work inwards. The outermost environment of my Powerful Person site is represented by the outermost `<div>` in my HTML.

```html
<div className="App">
```

CSS

```css
.App {
  text-align: center;
}
```

The property `text-align: center;` places the title "Powerful People" in the center.

Next I want to display all my cards in rows. I need to create another "environment" where I can apply the flex properties to my cards and display them in rows.

Take a look at this image to see how I broke down the CSS and HTML:

![Excalidraw mockup of cards in rows](https://dev-to-uploads.s3.amazonaws.com/i/8xlqfx2ffqin2995drcm.jpg)

I create a new CSS class `.wrapper` that will "wrap" around all my cards and dictate their layout.

```css
.wrapper{
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: center;
 }
```

*EDIT: It has been pointed out to me that `row` is the default value for the `flex-direction` property. Which makes including it in `.wrapper` redundant. I am going to keep it here so that others can learn from this and I can reference it later if I need to.*

Flexbox has a lot of awesome properties, and one of those is `flex-direction`. You can do rows, columns, reverse rows, and reverse columns. `flex-direction: row` places the cards in a single, horizontal row.

What is `flex-wrap: wrap`?

To illustrate, I will comment out that line.

```css
.wrapper{
    flex-direction: row;
    /* flex-wrap: wrap; */
    justify-content: center;
}
```

Yikes. The cards are over-flowing off the screen. 

![Screenshot of cards running off the page without flex-wrap: wrap](https://dev-to-uploads.s3.amazonaws.com/i/baflg9zmf2cvizvd3yec.jpg)

Well that is just not great. The wrap property sends the last off-screen element down to create a new row within the confines of the parent div. 

`justify-content: center;` is pretty easy to understand. Let's take a look at examples with that line commented out and then when we add it back in.

```css
.wrapper{
    flex-direction: row;
    flex-wrap: wrap;
    /* justify-content: center; */
}
```

![Cards when justify-content: center is commented out](https://dev-to-uploads.s3.amazonaws.com/i/epzp9su7x28ldnt7dgd9.jpg)

With `justify-content: center;` back in.

![Cards with justify-content: center back in](https://dev-to-uploads.s3.amazonaws.com/i/qdizg4vbqaanli6ei13r.jpg)

## Shifting Gears - Responsive CSS

This is about the point in time when I realized that I was creating "desktop-first" design, and I wanted to shift to "mobile-first" design practices. 

Responsive web design makes websites adjust how they appear on the screen depending on the screen size. This is achieved with CSS "media queries" which the developer defines based on how they want their site to behave. If you are not familiar with CSS media queries, check out these examples from [w3schools.com](https://www.w3schools.com/css/css3_mediaqueries_ex.asp). 

CSS media queries are outside the scope of this post (and once I write one, I'll link it here). 

However, I must talk about how I refactored my `.wrapper` class to display my cards in a single column on a mobile device and added a second CSS file `responsive.css` with media query for my wrapper class to change the flex direction back to rows when the screen is wide enough. 

First my refactored, mobile-first CSS `.wrapper` class.

```css
.wrapper {
  display: flex;
  flex-direction: column;
}
```

Now all my cards are in a single, vertical column. Whatever the screen size is, my cards now will always be in a single, vertical column.

I want them still be displayed in rows on larger screens. I need a CSS media query.

(Don't forget to import `responsive.css` into your top-level component. For me that is `App.js`.)

```css
/* responsive.css */

@media only screen and (min-width: 1100px) {
  .wrapper{
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: center;
  }
}
```

*EDIT: I mentioned above that having `flex-direction: row;` was redundant, but it is NOT redundant here. This media query is over-riding the `flex-direction: column;` that I refactored earlier.*

I am telling my `.wrapper` class to change its flex direction back to rows whenever the screen device is 1100px or larger.

## Confession

I actually created the cards first. Before I figured out how to display all the cards in rows or columns. Before I switched from a desktop-first design to mobile-first design. 

There was a reason for that. At first I was using "dummy data" and only had one card on my screen. I had not yet created my [local API](https://dev.to/jamesncox/react-patterns-local-api-495j). No need for defining a layout.

BUT. It made sense first to talk about the concepts of flex from the outermost environment to the innermost (my cards). If you were creating your own layout, you could easily replace the cards with CSS placeholders if you want to see how elements might appear on the screen.

You could do something like:

```css
.card {
  align-self: center;
  background-color: rgb(20, 20, 20);
  margin: 1rem;
  width: 90%;
  height: 15rem;
}
```

And then your HTML:

```html
<div className="wrapper">
    <div className="card" />
    <div className="card" /> 
    <div className="card" />
    <div className="card" />
    <div className="card" />
    <div className="card" />
    <div className="card" />
    <div className="card" /> 
</div>

```

This will simulate multiple cards mapped and rendered to your screen.

## Step 3 (kind of) - Creating the Cards

Take a look at this Excalidraw sketch I made:

![Excalidraw mockup with CSS and HTML descriptions](https://dev-to-uploads.s3.amazonaws.com/i/tz1gginm3fcxthnz3n4z.jpg)

Remember my mental model that each element on your page can be considered its own "environment". Each card lives inside the `.wrapper` environment, but whatever is INSIDE the card will have no idea how to behave until we create a new environment that dictates how to look and act.

Each `.card` div has its own "wrapper" div called `.row`. 

```css
.row {
  display: flex;
  flex-direction: row;
}
```

Here we are telling the contents inside our card to display in a horizontal row, next to each other left to right.

Next, each element inside the `.row` class will be "wrapped" in a div called `.column`.

```css
.column {
  display: flex;
  flex-direction: column;
  flex: 1;
}
```

Now any elements inside the `.column` class will displayed vertically due to `flex-direction: column;`.

What is `flex: 1`?

According to [CSS Tricks](https://css-tricks.com/almanac/properties/f/flex/#:~:text=flex%3A%200%20auto%3B&text=It%20makes%20the%20flex%20item,items%20along%20the%20main%20axis.)
>flex: `positive-number`
Equivalent to flex: 1 0px. It makes the flex item flexible and sets the flex basis to zero, resulting in an item that receives the specified proportion of the remaining space.

>If all items in the flex container use this pattern, their sizes will be proportional to the specified flex factor.

Now anything inside the `.column` class will respond to `display: flex;` and we can use flex properties. Take a look at the rest of my CSS which dictates the layout of the card's contents:

```css
.info {
  margin-top: .5rem;
  margin-left: 1rem;
}

h1 {
  align-self: center;
  font-family: 'Bangers', cursive;
  font-weight: lighter;
  font-size: 3rem;
  color: rgb(20, 20, 20);
}

h4 {
  text-align: left;
  color: rgba(255, 255, 255, 0.8);
  margin-top: -.5rem;
}

p {
  text-align: left;
  color: rgba(255, 255, 255, 0.5);
  margin-top: -.5rem;
}

ul {
  margin-top: -.5rem;
}

li {
  text-align: left;
  color: rgba(255, 255, 255, 0.8);
  font-weight: bold;
}

img {
  align-self: flex-start;
  border-radius: 2rem;
  object-fit: cover;
  height: 8rem;
    width: 8rem;
}
```

You will notice that each HTML element (h1, h4, li, p and img) is utilizing a flex property, `text-align` or `align-self`. Because they are inside the `.column` class, they are responding to the `display: flex` property.

And finally my full `App.js` component.

```javascript
import React from "react";
import "./styles.css";
import "./responsive.css"
import PersonData from './data/personData'

export default function App() {
  return (
    <div className="App">
      <h1>Powerful People</h1>
        <div className="wrapper">
          {PersonData.map(person => {
            return (
              <div className="card" key={person.id}>
                <div className="row">
                  <div className="column">    
                      <img src={person.url} alt={person.name} />  
                  </div>
                  <div className="column">
                    <div className="info">
                      <p>Full name</p>
                      <h4>{person.name}</h4>
                      <p>Profession</p>
                      <h4>{person.role}</h4>
                      <p>Hobbies</p>
                      <ul>
                        {person.hobbies.map((hobby, i) => { 
                          return(     
                            <li key={i}>{hobby}</li>
                          )
                        })}
                      </ul>
                    </div>
                  </div>
              </div>
            </div>
          )
        })}
      </div>
    </div>
  )
}
```

Notice that the information about each person is an extra class called `.info` in order to add some extra alignment and spacing between my two columns.

## Wrapping Up

Thank you for reading my breakdown of Flexbox and I hope that you walk away feeling a little more confident about how to use flex properties to improve your CSS layout and design skills! 

As always, I would love feedback and constructive criticism. I am sure there are tons of things I can still learn and improve. If you see anything I can do or explain better, let me know in the comments!

Thanks again and HAPPY CODING!