TailwindCSSでのスムーススクロールの実装

#背景と実施したこと

Webサイトを構築する際にヘッダーメニューは必ずあると思いますが、今回は同ページの中でスクロールするような動きを実装してみました。
※以下のようなイメージ

![chrome-capture.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635205/513944d4-3f23-4259-aee1-6cb0cf9d8f07.gif)

使用しているフレームワークなどの情報は以下の通り

+ next: 12.0.7
+ react: 17.0.2
+ TailwindCSS: 3.01

この挙動は「スムーススクロール」と呼ばれるようで、ググる場合はこれがキーワードになると思います。
実装方法としては、これ用のライブラリをインストールすることなくCSSでのみ実装していきます。
（というかそこまで複雑な挙動・実装ではないのでそれで十分）

#目次

1. 概要
1. スムーススクロールの実装(ヘッダーメニューとリンク先)
1. スムーススクロールの実装(CSS)
1. まとめ

##概要
今回のサマリーとしては以下の3点がポイントになります。

+ ヘッダーメニューをクリックしたときに同じページの下部分にスクロールで遷移する挙動を「スムーススクロール」と呼ぶよ。
+ スムーススクロールはTailwindCSSで超簡単に実装できるよ。
+ htmlタグにクラスを指定する際は「pages\_document.js」を追加する必要があるよ。


##スムーススクロールの実装(ヘッダーメニューとリンク先)

まず基本的なこととしてスクロールせずに、ただリンクのように飛ばす場合の動きを確認してみてみます。
aタグを活用して以下のように記述することで同ページ内での遷移を実現します。

```html:メニュー(リンク元)
<a href="#about">about</a>
```

```html:リンク先
<h2 id='about' className=' text-[#384359] text-center font-bold text-xl p-16 '>私について</h2>
```
ハッシュ(#)の後に飛ばしたリンク先のIDを指定することで紐づきができます。
next.jsなのでJSXを活用して実際のコードを書くと以下のようになるイメージです。
map関数の使い方に関しては、以下の記事も合わせて参照いただくとよいかもです。

[next.jsにおけるmapの使い方と「Each child in a list should have a unique "key" prop」の対応](https://qiita.com/senju797/items/df5dbb94b5b2f630e36b "mapの使い方")


```jsx:header.js
export default function Layouut() {
  const menuList = [
    { name: 'about', link: '#about' },
    {
      name: 'skills',
      link: '#skills',
    },
    {
      name: 'values',
      link: '#values',
    },
    {
      name: 'future',
      link: '#future',
    },
  ];

  return (
    <>
      <Header list={menuList}></Header>
      <main>
        <Main />
        <About />
        <Skill />
        <Values />
        <Future />
      </main>
      <Footer />
    </>
  );
}
```


```jsx:header.js

export default function Header(props) {
  const [openMenu, setOpenMenu] = useState(false);
  console.log(openMenu);
  const data = props.list;
  console.log(data);

  const menuFunction = () => {
    setOpenMenu(!openMenu);
  };

 return (
    <nav className='flex'>
      <div className='flex-none  sm:flex-1 md:flex-1 lg:flex-1 xl:flex-1'>
        <Link href='/'>
          <a>
            <Image src='/images/logo.png' alt='logo' width={200} height={100} />
          </a>
        </Link>
      </div>
      {openMenu ? (
        <div className='flex flex-row absolute z-10 top-0 right-0  min-h-full min-w-full '>
          <div className='basis-1/2 bg-gray-400/50'></div>

          <div className='basis-1/2 bg-white'>
            <ul className=' text-center'>
              <li className='p-2 '>
                <button onClick={menuFunction} className='font-bold'>
                  close
                </button>
              </li>
              {data.map((value, index) => (
                <li key={index} className='p-2 '>
                  <a href={value.link} onClick={menuFunction}>
                    {value.name}
                  </a>
                </li>
              ))}
            </ul>
          </div>
        </div>
      ) : undefined}
      <div className='flex-initial text-[#abc5c5] font-bold m-5 '>
        <ul className='md:flex  hidden flex-initial text-left'>
          {data.map((value, index) => (
            <li key={index} className='p-4'>
              <a href={value.link}>{value.name} </a>
            </li>
          ))}
        </ul>
      </div>
      <button onClick={menuFunction} className='flex-initial absolute top-0 right-1 md:hidden'>
        <Image src='/images/menu.png' alt='logo' width={50} height={50} />
      </button>
    </nav>
  );
}
```


##スムーススクロールの実装(CSS)

次に、いよいよスクロールの動きを実装していきます。
**といってもこれはTailwindCSSでは「scroll-smooth」として標準で用意されているので、これをHTMLの最上位である
htmlタグに適用してあげるだけです。**
※TailwindCSSの導入に関しては以下を参照ください。
[TailwindCSS ver3.0の導入について](https://qiita.com/senju797/items/fb8ba37ac8da23bc13d9"TailwindCSS ver3.0の導入について")

**ただし、気を付けなければいけないのが、htmlタグやbodyタグのようなすべての要素に対して普遍的に影響があるタグの場合は
「custom Document」と呼ばれる別のファイルを生成する必要があるという点です。**

詳細は以下を参照
[custom Documentとは](https://nextjs-ja-translation-docs.vercel.app/docs/advanced-features/custom-document "custom Document")

ということで、pages配下に「_document.js」を作成します。
さらにその中のHtmlコンポーネントにクラスとして「scroll-smooth」を指定します。

```jsx:src\pages\_document.js
import Document, { Html, Head, Main, NextScript } from 'next/document';

class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx);
    return { ...initialProps };
  }

  render() {
    return (
      <Html className='scroll-smooth'>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;
```

以上で実装は完了です。
htmlタグを補強するためには_document.jsを作成するというところが私にとっては一番の学びでした。
next.jsのお作法も覚える必要がありますね。



##まとめ
あらためておさらいをすると以下がポイントです。

+ ヘッダーメニューをクリックしたときに同じページの下部分にスクロールで遷移する挙動を「スムーススクロール」と呼ぶよ。
+ スムーススクロールはTailwindCSSで超簡単に実装できるよ。
+ htmlタグにクラスを指定する際は「pages\_document.js」を追加する必要があるよ。

余談ですが、TailwindCSSの2系ではスムーススクロールは拡張機能を位置づけだったようですね。
TailwindCSSは非常に便利なので、今後のver-up、機能追加にも期待です。