TailwindCSSのレスポンシブデザイン

#背景と実施したこと

TailwindCSSを使用してPCレイアウトのWebサイトのレスポンシブ対応を実装しました。
今回は静的コンテンツの配置を横並びから縦並びに変えるという内容のみ実施しています。

CSSは少し苦手意識があったのですが、TailwindCSSを使うとかなりローコストかつシンプルに記述できたので
そのノウハウを主に初心者の方向けに記述していきたいと思います。

#目次

1. 概要
1. 前提とやりたいことの整理
1. 考え方の整理
1. 実際のコード例
1. 補足とまとめ

##概要
+ TailwindCSSを使ったレスポンシブ対応の実際のコード例と考え方を初心者向けに記載するよ。
+ 画面表示上、横並びだったものをスマホレイアウトにすると縦並びにする、という例で説明するよ。
+ メディアクエリの使い方とはもちろんだけど、HTMLタグの記載の順番を意識することがポイントだよ。


##前提とやりたいことの整理

【前提】
+ TailwindCSSは3.0を使用
+ アプリのフレームワークはNext.jsを使用
+ HTMLの基本的な構造は学習済みの人向け

【やりたいこと】
PC用レイアウトで作ったデザインをスマホなどの縦レイアウトにも対応できるようにCSSを調整する。
（以下の様なイメージ）

■before
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635205/ea774ee4-d154-20d3-be53-7edb58dd4c85.png)

■after
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635205/7970eb5d-087e-94d7-dc08-557f6e6a67cc.png)


## 考え方の整理

### HTMLのおさらい
HTMLのタグはブロックとインラインの2つの種類があります。
いろいろと違いはあるのですが、「レイアウト」という観点だとブロックは改行が入り（つまり縦に並んでいく）、インラインは改行が入らない（つまり横に並んでいく）という点が重要です。

ブロックを単純に並べていくだけだと、縦（上から下）に並ぶだけなので、ブロック同士を横に並べたい場合は、少し工夫が必要です。
いろんなやり方があるのですが、ここではflex-boxを使います。

TailwindCSSのfflex-boxは以下の様にして使えます(公式ドキュメントより抜粋)

```jsx:sample.js
<div class="flex flex-row">
  <div class="basis-1/4">01</div>
  <div class="basis-1/4">02</div>
  <div class="basis-1/2">03</div>
</div>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635205/cb771a5c-9cbe-0ef4-6e89-5825571fd094.png)

divを横並びに1:1:2の比率で配置しています。


### 考え方
ここで再度beforeの画面レイアウトを見てみましょう。
この場合レイアウトを大きく4つに分けて考えることができます。

1. タイトルが記載されているタイトルエリア
+ 画像が載っている画像エリア
+ メインタイトル
+ サブタイトル

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635205/828f308d-443b-6d9d-1a1a-ad2aaad56782.png)

①と②が横並びで①の中の③と④が縦に並んでいます。

「①と②でをflexで並べればいいんだ！早速コードを書こう！」となると思いますが、その前にスマホレイアウトもイメージしておきましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635205/ca216ce9-7737-114b-257c-b3503476fc16.png)

①と②が縦の並び、①の中に③と④が縦に並んでいます。
このとき**「あれ？この構造はHTMLの構造とそっくりじゃね？」**と思った方は素晴らしいです。
flexなどを適用させなければブロック同士は縦に並ぶので、以下のようなコードが想像できるのではないでしょうか？

```jsx:main.js
const Main = () => {
  return (
    <div className='bg-[#6bc2c3] '>
      <div className=''>
        <h1 className=' ml-24 text-left text-4xl text-white'>メインタイトル</h1>
        <h2 className=' ml-24 text-left text-3xl text-[#008c8d]'>サブタイトル</h2>
      </div>
      <div className='text-center'>
        <Image src='/images/hero.png' alt='hero' width={400} height={400} />
      </div>
    </div>
  );
};
```

逆にいうと**PCレイアウトの場合、①と②をflexで横並びにさせて、スマホレイアウトの場合はflexを無効にすればOK**ということになります。

これがflexを使った場合の基本的な考え方です。
スマホレイアウトの場合だとどういった並びにしたいかを念頭におきつつ、HTMLのタグの記載順番考える必要がある、という点がポイントです。



## 実際のコード例

考え方がわかったところで実際にコードを記載していきます。
まずは親要素のdivにflexを指定しましょう。

```jsx:main.js
const Main = () => {
  return (
    <div className='flex flex-row bg-[#6bc2c3] '>
      <div className='basis-1/2'>
        <h1 className=' ml-24 mt-24  text-left text-4xl	text-white'>メインタイトル</h1>
        <h2 className=' ml-24 text-left text-3xl text-[#008c8d]'>サブタイトル</h2>
      </div>
      <div className='basis-1/2 text-center'>
        <Image src='/images/hero.png' alt='hero' width={400} height={400} />
      </div>
    </div>
  );
};
```

これで親要素のdivを１：１で分割してタイトルエリアと画像エリアに分けて横並びにすることができました。
ただし、これだけでは上述したスマホレイアウトの際にflexを適用しない、という動きは実現できていません。
少し変更を加えます。

```jsx:main.js
const Main = () => {
  return (
    <div className='md:flex flex-row bg-[#6bc2c3] '>
      <div className='basis-1/2'>
        <h1 className=' ml-4 md:ml-24 mt-24  text-left  text-4xl	text-white'>メインタイトル</h1>
        <h2 className=' ml-4 md:ml-24 text-left text-3xl text-[#008c8d]'>サブタイトル</h2>
      </div>
      <div className='basis-1/2 text-center'>
        <Image src='/images/hero.png' alt='hero' width={400} height={400} />
      </div>
    </div>
  );
};
```

親要素のflexに「md:」を足しました。
「え？これだけ？」って思いますよね。これだけです。TailwindCSS恐るべし。

これはTailwindcssのメディアクエリと呼ばれるものでmedium screen以上の大きさの場合にのみflexを適用する、という意味になります。
「mediumって具体的に何pxの幅やねん」と疑問に思われる方も多いでしょう。
具体的には768pxです。（デフォルトの設定がそうなっているだけで当然変更もできます）
また、この境界線となる数値をBreak pointといいます。

他にもsm、lgなどがあり、それぞれのBreak pointは以下の通りです。(こちらも公式より抜粋)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635205/f226a529-3184-bca5-04e4-5b3d3b5aaab7.png)


注意点なのが、**md:で指定するとそれより上位のlg、xlでも適用されるという点です。**
したがって、それぞれのレイアウトごとに同様の内容を指定する必要はありません。

表にすると以下のような具合です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635205/baa06828-e8c4-3bc7-ec84-19086b23115b.png)

実際には、flex以外にもmtなどを用いて余白調整を行うことが多いでしょう。
その場合でも、各Break pointに応じてCSSを指定します。


**またスマホレイアウトのときはtext-centerにしたいなーと思って以下の様に「sm:text-center」を足すのはNGです。**

```jsx:main.js
const Main = () => {
  return (
    <div className='md:flex flex-row bg-[#6bc2c3] '>
      <div className='basis-1/2'>
        <h1 className=' ml-4 md:ml-24 mt-24  sm:text-center text-4xl	text-white'>メインタイトル</h1>
        <h2 className=' ml-4 md:ml-24 text-left text-3xl text-[#008c8d]'>サブタイトル</h2>
      </div>
      <div className='basis-1/2 text-center'>
        <Image src='/images/hero.png' alt='hero' width={400} height={400} />
      </div>
    </div>
  );
};
```

正しくは以下の様に「text-center」を前提にして sm:を追記する記述になります。

```jsx:main.js
const Main = () => {
  return (
    <div className='md:flex flex-row bg-[#6bc2c3] '>
      <div className='basis-1/2'>
        <h1 className=' ml-4 md:ml-24 mt-24  text-center sm:text-left text-4xl	text-white'>
          メインタイトル
        </h1>
        <h2 className=' ml-4 md:ml-24 text-left text-3xl text-[#008c8d]'>サブタイトル</h2>
      </div>
      <div className='basis-1/2 text-center'>
        <Image src='/images/hero.png' alt='hero' width={400} height={400} />
      </div>
    </div>
  );
};
```
prefixなしのものを前提にして、そこから各Break Pointに応じたスタイルを適用する、という考え方が重要です。
したがって、まずモバイルのレイアウトを考えて、そこからPCのレイアウトを考える、という順番を公式は推奨しています。
（まさに「モバイルファースト」）


##補足とまとめ
flexを使ったレスポンシブ対応の仕方を記載してきましたが
かなり簡単に実装できることがわかったかと思います。

フロントを作る経験が乏しい人もこれなら自分でもできそうと思ってくれると幸いです。

一方でflexと同様に使用頻度が高いものにgridがあります。
こちらも同様にレスポンシブ対応を書けるのですが、個人的にはflexよりも使う場面は限定的かと思いました。（可読性、保守性などの面から）
gridの活用の仕方やメリット、デメリットの整理などは今後の課題としたいと思います。