Quantcast
Channel: CSSタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8664

React + SimpleBar: スクロールバーのスタイルをカスタマイズする

$
0
0

SimpleBarはスクロールバーをカスタマイズするライブラリです。スクロールバーを独自につくるのではなく、CSSのスタイルを割り当てるので、おかしな挙動は起こらず、ネイティブなスクロールのパフォーマンスが保たれます。あくまで、スクロールバーの見栄えを変えるだけです。

SimpleBar logo

デザインはCSSで定める

SimpleBarは純粋なCSSでスクロールバーのスタイルを定めます。CSSで与えられるスタイルでさえあれば、自由にカスタマイズできるということです。また、macOSとWindowsで同じ見た目になるのも大きな魅力といえます。

軽量なライブラリ

6KBのとても軽いライブラリです。JavaScriptはスクロールの動きそのものには触れません。ネイティブな動きとパフォーマンスが得られます。

モダンブラウザをサポート

ChromeとFirefox、Safariなどのモダンブラウザに加え、Internet Explorer 11をサポートします。

ライブラリの概要はドキュメントデモページでお確かめください。本稿と同じタイトルの「JavaScript + SimpleBar: スクロールバーのスタイルをカスタマイズする」でつくったつぎの作例は、標準のJavaScriptコードでSimpleBarのスタイルを割り当てました。「Left Column」にマウスポインタを重ねると、グラデーションのスクロールバーが現れます。今回のお題は、React用のSimplebarReactで同じサンプルをつくることです。

See the Pen JavaScript + SimpleBar: Customizing scrollbar style by Fumio Nonaka (@FumioNonaka) on CodePen.

本稿の作例は、Create React Appのひな形アプリケーションをもとにつくります。ひな形のつくり方については「Reactアプリケーションのひな形をつくる」をお読みください。

インストール

まず、SimpleBarをインストールします(「Installation」)。SimplebarReactもSimpleBarのCSSを使うからです。npmまたはyarnでインストールしてください。

npm install simplebar --save
yarn add simplebar

つぎに、SimplebarReactのインストールです。やはり、npmまたはyarnで行います(「Installation」)。

npm install simplebar-react --save
yarn add simplebar-react

基本となるページの組み立て

ページを構成する要素は大きく3つ、ヘッダと左カラム、そしてメインコンテンツです(図001)。また、Bootstrap 4.5を用いました。ただし、本稿ではCSSの説明は基本的に省き、SimpleBarの扱いに関わる定めだけ解説することにします。確かめたい方は、最後に掲げるCodeSandboxのサンプルまたはGithubのソースをご覧ください。

図001■ヘッダと左カラムにメインコンテンツで組み立てられたページ

2007001_002.png

以下のコードは、アプリケーション(src/App.js)に、それぞれヘッダ(src/components/Header.js)と左カラム(src/components/LeftColumn.js)およびメインコンテンツ(src/components/MainContents.js)を静的にレイアウトしたモジュールの中身です。src/App.jssimplebar/dist/simplebar.min.cssを読み込んでいます。

SimplebarReactのJavaScriptライブラリをimportするのは、スクロールバーをカスタマイズする左カラムのモジュール(src/components/LeftColumn.js)です。なお、リストの連番項目は、メソッドArray.from()Array.prototype.map()でつくりました。興味のある方は「ECMAScript 6のArrayに関わる構文を試す」をお読みください。

src/App.js
importReactfrom"react";import"bootstrap/dist/css/bootstrap.min.css";import"simplebar/dist/simplebar.min.css";import"./App.css";importHeaderfrom"./components/Header";importMainContentsfrom"./components/MainContents";importLeftColumnfrom"./components/LeftColumn";functionApp(){return(<divclassName="App"><Header/><divclassName="container-fluid d-flex px-0"><LeftColumn/><MainContents/></div></div>);}exportdefaultApp;
src/components/Header.js
importReactfrom"react";constHeader=()=>{return(<headerid="header"className="text-white bg-primary w-100 p-2 d-flex"><h1>Header</h1></header>);};exportdefaultHeader;
src/components/LeftColumn.js
importReactfrom"react";constLeftColumn=()=>{return(<divid="left-column"className="bg-light p-2"><h3>Left column</h3><ulid="list"className="pl-4">{Array.from(newArray(20),(_,index)=>(<likey={index}>item {String(index+1).padStart(2,0)}</li>))}</ul></div>);};exportdefaultLeftColumn;
src/components/MainContents.js
importReactfrom"react";constMainContents=()=>{return(<mainclassName="px-4 py-2"><h2>Main contents</h2><p><!--[中略]--></p></main>
  );
};

export default MainContents;

ヘッダを上部に固定する

まずは、ヘッダをページ上部に固定するCSSの設定です(src/App.css)。位置はpositionプロパティにfixedを与えて固定します。具体的な置き場所は上部なのでtop: 0です。すると、<body>要素の領域に含まれなくなるので、そのままではページの上部がかぶって隠れてしまいます(図003)。

src/App.css
#header{position:fixed;top:0;}

図002■ページ上部をヘッダが覆ってしまう

2007001_003.png

<body>要素のpaddingまたはmarginは、ヘッダの高さ分下げなければならないのです。もっとも、高さはウィンドウ幅やレスポンシブの設定によって変わるかもしれません。動的に定めるべきでしょう。

要素の高さはelement.clientHeightで得られます。要素を参照するフックはuseRefです(src/App.js)。参照(header)は、プロパティでヘッダのコンポーネント(src/components/Header.js)に渡します。ただし、element.clientHeightは、読み取り専用プロパティであることにご注意ください。高さの設定には、要素(<div>)のstyle属性を用います。

src/App.js
// import React from "react";importReact,{useEffect,useRef,useState}from"react";functionApp(){const[headerHeight,setHeaderHeight]=useState(0);constheader=useRef(null);useEffect(()=>{const_header=header.current;constsetLayout=()=>{setHeaderHeight(_header.clientHeight);}window.addEventListener("resize",setLayout);setLayout();},[]);return(// <div className="App"><divclassName="App"style={{paddingTop:headerHeight}}>{/* <Header /> */}<HeaderheaderRef={header}/></div>);}
src/components/Header.js
// const Header = () => {constHeader=({headerRef})=>{return(<headerid="header"ref={headerRef}><h1>Header</h1></header>);};

SimpleBarを組み込む

SimpleBarを使う要素には、overflowプロパティにautoを与えてください(src/App.css)。そのうえで、SimpleBarを設定する要素は<SimpleBar>に置き替えます(src/components/LeftColumn.js)。

src/App.css
#left-column{overflow:auto;}
src/components/LeftColumn.js
importSimpleBarfrom"simplebar-react";constLeftColumn=()=>{return(// <div id="left-column" className="bg-light p-2"><SimpleBarid="left-column"className="bg-light p-2">{/* </div> */}</SimpleBar>);};

そして、スクロールバーを表示するには、要素に高さを定めなければなりません。

src/App.css
#left-column{overflow:auto;height:400px;/* 高さを定める */}

とはいえ、高さを決め打ちは避けたいところです。すでに、ヘッダの高さはとれるのですから、ブラウザウィンドウのビューポートの高さ(window.innerHeight)から差し引けば、左カラムの高さ(leftColumnHeight)は求まります。

src/App.js
functionApp(){const[leftColumnHeight,setLeftColumnHeight]=useState(0);useEffect(()=>{constsetLayout=()=>{setLeftColumnHeight(window.innerHeight-_header.clientHeight);};},[]);return(<divclassName="App"style={{paddingTop:headerHeight}}><divclassName="container-fluid d-flex px-0">{/* <LeftColumn /> */}<LeftColumnleftColumnHeight={leftColumnHeight}/></div></div>);}
src/components/LeftColumn.js
// const LeftColumn = () => {constLeftColumn=({leftColumnHeight})=>{return(// <div id="left-column" className="bg-light p-2"><SimpleBarid="left-column"className="bg-light p-2"style={{height:leftColumnHeight,}}>{/* </div> */}</SimpleBar>);};

これで、ウィンドウに合わせて左カラムの高さが定まり、スクロールバーは自動表示されるようになりました(図003)。

図003■SimpleBarのスクロールバーが自動表示される

2008002_001.png

ページ全体をスクロールしたときの不具合を直す

まだ少し、不具合が残っています。ページ全体を下にスクロールしたとき、左カラムがせり上がって、ヘッダにかぶってしまうことです(図004)。

図004■ページを下にスクロールすると左カラムがヘッダにかぶる

2008002_002.png

左カラム(src/components/LeftColumn.js)の垂直位置は固定しなければなりません。やり方は、前述「ヘッダを上部に固定する」と同じです。ただ、CSS(src/App.css)でなく、style属性で定めることにしました。

src/App.js
functionApp(){return(<divclassName="App"style={{paddingTop:headerHeight}}><divclassName="container-fluid d-flex px-0"><LeftColumnheaderHeight={headerHeight}/></div></div>);}
src/components/LeftColumn.js
// const LeftColumn = ({ leftColumnHeight }) => {constLeftColumn=({headerHeight,leftColumnHeight})=>{return(<SimpleBarstyle={{position:"fixed",top:headerHeight,}}></SimpleBar>);};

もちろん、前述「ヘッダを上部に固定する」と同じように、左カラムがメインコンテンツにかぶってしまいます(図005)。

図005■メインコンテンツが左カラムに隠れてしまう

2008002_003.png

「ヘッダを上部に固定する」と同じ考え方で、メインコンテンツの左端をカラムの幅だけ右に寄せればよいはずです。けれど、つぎのコードではメインコンテンツの位置がまったく動きません。

src/App.js
functionApp(){const[leftColumnWidth,setLeftColumnWidth]=useState(0);constleftColumn=useRef(null);useEffect(()=>{const_leftColumn=leftColumn.current;constsetLayout=()=>{setLeftColumnWidth(_leftColumn.clientWidth);};},[leftColumn]);return(<divclassName="App"style={{paddingTop:headerHeight}}><divclassName="container-fluid d-flex px-0"><LeftColumnleftColumnRef={leftColumn}/>{/* <MainContents /> */}<MainContentsleftColumnWidth={leftColumnWidth}/></div></div>);}
src/components/MainContents.js
// const MainContents = () => {constMainContents=({leftColumnWidth})=>{return(// <main className="px-4 py-2"><mainclassName="px-4 py-2"style={{marginLeft:leftColumnWidth}}></main>);};
src/components/LeftColumn.js
// const LeftColumn = ({ headerHeight, leftColumnHeight }) => {constLeftColumn=({headerHeight,leftColumnHeight,leftColumnRef})=>{return(<SimpleBarref={leftColumnRef}></SimpleBar>);};

SimpleBarコンポーネントをラップする

調べてみると、SimpleBarコンポーネントのclientWidthプロパティ値が0です。SimpleBarは、あくまでスクロールバーのスタイルを整えるためのラッパーだからでしょう。

そこで、Simplebarコンポーネントをつぎのように<div>要素で包み、スクロールバーに用いる以外の属性はすべてこの要素に移します。こうすることで、カラムの要素の幅(clientWidth)が正しく得られるのです。メインコンテンツの左端は、カラムの右端に揃います。

src/components/LeftColumn.js
constLeftColumn=({headerHeight,leftColumnHeight,leftColumnRef})=>{return(<divid="left-column"ref={leftColumnRef}className="bg-light p-2"style={{position:"fixed",top:headerHeight,}}><SimpleBar/* id="left-column"
        ref={leftColumnRef}
        className="bg-light p-2" */style={{/* position: "fixed",
          top: headerHeight, */height:leftColumnHeight,}}></SimpleBar></div>);};

CSSでスクロールバーのスタイルを変える

SimpleBarのスクロールバーのスタイルは、CSSにより定められています。つまり、見栄えがCSSで変えられるということです。ここでは、スクロールさせるスライダのカラーを、つぎのCSSでグラデーションにしてみましょう(図006)。

src/App.css
.simplebar-scrollbar::before{background:linear-gradient(darkblue,skyblue);}

図006■メインコンテンツの位置が正しく定まってスライダはグラデーションになった

2008002_004.png
>> CodeSandboxへ

冒頭の標準JavaScriptのサンプルと同じページをSimplebarReactでつくり、CodeSandboxに掲げました。また、Githubでもソースをご覧いただけます。

 


Viewing all articles
Browse latest Browse all 8664

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>