• トップ
  • ブログ一覧
  • Next.js, TailwindCSSでscroll-behaviorを使い分ける
  • Next.js, TailwindCSSでscroll-behaviorを使い分ける

    はじめに

    スムーズスクロール対応のため、html要素にscroll-behavior: smooth;のclass(以下、TailwindCSSのscroll-smooth)を付与したい時があります。ただ、scroll-behavior: auto;を使いたいページを要求されたらどうするか心配になるものです。

    Next.js App router

    Next.js App routerでは<html>タグをroot layoutで記述する必要がありますが、Route Groupsを使い複数のroot layoutをを用いることができます。

    1app
    2├── (scroll-auto)
    3│   └── layout.tsx
    4└── (scroll-smooth)
    5    └── layout.tsx

    Next.js Pages router

    Next.js Pages routerではCustom Document<html>のclassを付与できます。 しかし、アプリで使えるCustom Documentは1つのみです。

    迂回策: クライアントでhtmlのclassを修正するコンポーネントで対応する

    クライアントでhtmlのclassを上書きすることでもよければ、以下のようなコンポーネントを対応ページに入れることで対応できます。cleanup関数にscroll-smoothを戻すことで、こちらのコンポーネントがあるページのみscroll-smoothの反映されず対応できます。

    1export const RemoveScrollSmooth = () => {
    2  useEffect(() => {
    3    document.documentElement.classList.remove("scroll-smooth");
    4
    5    return () => {
    6      document.documentElement.classList.add("scroll-smooth");
    7    };
    8  }, []);
    9
    10  return null
    11};

    番外: htmlをラッピングし、useStateとContext APIで制御する

    Next.js Pages routerでは使えないですが、App routerなどで複数のlayout対応するまでも無いのであり、直接DOM操作したく無いことであれば、htmlをラッピングし、中でscroll behaviorのclassを状態として管理することもできます。<RemoveScrollSmooth />と同様に、<ScrollAuto />scroll-autoを適用したいページに入れると<ScrollAuto />が含まれている箇所のみクライアント側でclassを更新します。

    1"use client";
    2
    3import {
    4  ComponentPropsWithoutRef,
    5  createContext,
    6  Dispatch,
    7  SetStateAction,
    8  useContext,
    9  useEffect,
    10  useState,
    11} from "react";
    12
    13export const SetScrollClassNameContext = createContext<
    14  Dispatch<SetStateAction<string>>
    15>(() => {
    16  console.warn("ScrollClassNameContext used outside of provider");
    17});
    18
    19export default function Html({
    20  children,
    21  lang,
    22}: ComponentPropsWithoutRef<"html">) {
    23  const [scrollClassName, setScrollClassName] = useState("scroll-smooth");
    24
    25  return (
    26    <SetScrollClassNameContext value={setScrollClassName}>
    27      <html lang={lang} className={scrollClassName}>
    28        {children}
    29      </html>
    30    </SetScrollClassNameContext>
    31  );
    32}
    33
    34export const ScrollAuto = () => {
    35  const setScrollClassName = useContext(SetScrollClassNameContext);
    36
    37  useEffect(() => {
    38    setScrollClassName("scroll-auto");
    39
    40    return () => {
    41      setScrollClassName("scroll-smooth");
    42    };
    43  }, [setScrollClassName]);
    44
    45  return null;
    46};

    最後まで読んでいただきありがとうございます。何か皆様の生活に役に立つところがあったら幸いです。

    ライトコードでは、エンジニアを積極採用中!

    ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。

    採用情報へ

    キムくん(エンジニア)
    キムくん(エンジニア)
    Show more...

    おすすめ記事

    エンジニア大募集中!

    ライトコードでは、エンジニアを積極採用中です。

    特に、WEBエンジニアとモバイルエンジニアは是非ご応募お待ちしております!

    また、フリーランスエンジニア様も大募集中です。

    background