2020, Nov 03

【Gatsby/React】Scroll to Top機能を実装する

Gatsby.jsのスマホ画面右下にTopボタンを表示して、トップに遷移できるようにします。

よくある機能の実装です。やりたいことはこちら。

  • スマホ画面でちょっとスクロールダウンしたら右下にボタンが表示される
  • ボタンを押すと、画面の一番上まで戻れる

Gatsby は React なので、useStateuseEffectをメインで使って、あと CSS で実装していきます。

このブログの Scroll to Top でもデザイン以外は全く同じものが使われていますので、スマホの人は動きが見れていると思います。

CSS でボタンを作る

今回 layout.js 配下にスクロールアップボタンコンポーネントを配置して全画面で使えるようにします。

なので、CSS は layout.js で読んでいるところに追加してください。

/* base.css  */
#scrollBtn {
  display: none; /* Hidden by default */
}

@media only screen and (max-width: 580px) {
  #scrollBtn {
    display: block;
    position: fixed;
    bottom: 20px;
    right: 30px;
    z-index: 99;
    border: none;
    outline: none;
    background-color: blue;
    color: white;
    cursor: pointer;
    padding: 15px;
    border-radius: 10px;
    font-size: 18px;
    animation: fadeIn 1.5s ease 0s 1 normal;
  }
  #scrollBtn:hover {
    background-color: #555;
  }
}
@keyframes fadeIn {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}
@-webkit-keyframes fadeIn {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

スマホのみに表示させたいので、PC 画面ではhiddenにしています。

重要なところはz-indexposition: fixed、それから位置を決めるbottomrightくらいでしょうか。

ボタンのデザインは適宜変更してください。

また、animationを使ってフェードインするようにしています。

コンポーネント追加

今回は、Scrollコンポーネントという名前で作ってみたいと思います。

// components/scroll.js
import React, { useState, useEffect } from 'react'

const Scroll = ({ showBelow }) => {
  const [show, setShow] = useState(showBelow ? false : true)

  const handleScroll = () => {
    if (window.pageYOffset > showBelow) {
      if (!show) setShow(true)
    } else {
      if (show) setShow(false)
    }
  }

  const handleClick = () => {
    window[`scrollTo`]({ top: 0, behavior: `smooth` })
  }

  useEffect(() => {
    if (showBelow) {
      window.addEventListener(`scroll`, handleScroll)
      return () => window.removeEventListener(`scroll`, handleScroll)
    }
  })

  return (
    <div>
      {show && (
        <button onClick={handleClick} id="scrollBtn" aria-label="to top">
          Top
        </button>
      )}
    </div>
  )
}
export default Scroll

useEffectでスクロール位置を監視して、引数で渡したshowBelowの値よりも下に行ったら表示されるようになっています。

layout.js に組み込む

layout.jsの適当な場所にScrollコンポーネントを配置します。

// layout.js

// 他のインポートは省略
import Scroll from './scroll'

const DefaultLayout = ({ children }) => (
  <StaticQuery
    query={graphql`
      query SiteTitleQuery {
        site {
          siteMetadata {
            title
            author
            description
          }
        }
      }
    `}
    render={data => (
      <div className="">
        <Header siteMetadata={data.site.siteMetadata} />
        <div>{children}</div>
        <Footer />
        <Scroll showBelow={250} /> // この部分を追加
      </div>
    )}
  />
)

DefaultLayout.propTypes = {
  children: PropTypes.node.isRequired,
}

export default DefaultLayout

引数は適宜変えて使ってください。

完成!

これでバッチリ動いているでしょうか。

ボタンの中身をアイコンに変えたり、CSS 変えたりカスタマイズ色々出来ると思います。

誰かの参考になれば幸いです。

参考にさせていただいたサイトはこちら。Scroll to Top - React & Gatsby