概要
みなさんは、パララックス(parallax)と聞いたことがあるでしょうか?
最近のサイトは、要素がふわっとフェードインしたり、要素の移動速度が違ったり、
スクロールに応じて色々なアニメーションが発火します。
このようなアニメーションを実装するのは大変です。
そのため、多くのライブラリーが公開され、簡単に実装できるようになっています。
ただ今回は、そんなライブラリーを使わずにパララックスのアニメーションを作成し、
リッチに見えるサイトを作成しました。
↓作ったサイトはこちらです。ご覧ください。
※ Qiita Engeer Festa 2022にご参加もお願いします。
パララックス(parallax)についてとは?
まずパララックス(parallax)にて解説します。
パララックス(parallax)とは?
パララックスとは、視差効果のことで、
Webサイトにおいては、パララックスはスクロールなどの動作に応じて、
複数のレイヤー(層)にある要素を異なるスピードで動かすことで、
「立体感や奥行きの演出」、「フェード・拡大縮小・回転などの視覚的エフェクト」を演出する
アニメーションを指します。
パララックス(parallax)を使ったサイトの例
1. Instagramの公式サイト
https://about.instagram.com/ja-jp/
2. 星野リゾートの界タビ20s
https://www.hoshinoresorts.com/sp/kaitabi20s/
3. パララックスアニメーションのライブラリー
https://dixonandmoe.com/rellax/
パララックス(parallax)の作り方
1. パララックス(parallax)の基本・構造を理解する
パララックス(parallax)の基本・構造のポイントは以下の通りです。
ポイント
・ 手前にあるものは、スクロール量より早く移動する。
・ 奥にあるものは、スクロール量よりゆっくり移動する。
イメージしてください。🤔
電車に乗って窓から景色を見ている時、遠くに見える家はどのように移動して見えるでしょうか?
→ 遠くに見える家はゆっくり移動しているようにみえますよね!?
では反対に、近くに見える家はどのように移動して見えるでしょうか?
→ 近くに見える家は一瞬で移動しているようにみえますよね!?
この現象をUI上に反映させるのが、パララックス(parallax)になります。
↓ つまり...
手前にくるような画像や要素は、スクロール量より早く移動し、
奥にくるようは背景画像や要素は、スクロール量よりゆっくり移動させることで、
基本的なHTML要素と視差が起こり、パララックスを表現することができます。
2. パララックス(parallax)を作成する
パララックス(parallax)の基本・構造を理解する
で記載したように、
パララックス(parallax)を実装するためには以下の要素が必要です。
- スクロール量を取得する
- オブジェクトの変化量
targetFactor
を個別に設定できるようにする - パララックスしたいオブジェクトを操作できるようにする
- スクロールごとに、スクロール量と変化量
targetFactor
を計算する - 計算した値に位置を変更する
では早速、これをもとにパララックスを作っていきましょう。
1. スクロール量を取得する
useEffect
をつかい、document.addEventListener('scroll', onScroll)
でスクロールするごとにonScroll
を発火させ、const scrollY = window.pageYOffset
でスクロール量を取得します。
const ParallaxItem = (children:Props) => {
const onScroll = () => {
const scrollY = window.pageYOffset // スクロール量を取得する
}
useEffect(() => {
// スクロールするごとにonScrollを発火する
document.addEventListener('scroll', onScroll)
})
return (
<></>
)
}
2. オブジェクトの変化量targetFactor
を個別に設定できるようにする
propsでtargetFactor
を渡せるように ParallaxProps
を作ります。
ただ、毎回targetFactor
を渡すのは大変なので、デフォルト値を決めておきます。
interface ParallaxProps {
targetFactor?: number
}
const ParallaxItem = (props: ParallaxProps) => {
// targetFactorのデフォルト値を決めておく
const targetFactor = props.targetFactor ? props.targetFactor : 0.15
const onScroll = () => {
const scrollY = window.pageYOffset
}
useEffect(() => {
document.addEventListener('scroll', onScroll)
})
return (
<></>
)
}
3. パララックスしたいオブジェクトを操作できるようにする
パララックスしたいオブジェクトのポジションを変更させるため、
useRefを使いdomを操作できるようにしておきます。
interface ParallaxProps {
// パララックスしたいオブジェクトを個別に設定できるようにする
children: ReactNode
targetFactor?: number
}
const ParallaxItem = (props: ParallaxProps) => {
// useRefを使いdomを操作できるようにする
const domRef = useRef<HTMLDivElement>(null)
const targetFactor = props.targetFactor ? props.targetFactor : 0.15
const onScroll = () => {
// ついでにdomRef.currentがnullではなかった時にスクロール量を取得するようにする。
if (domRef.current !== null) {
const scrollY = window.pageYOffset
}
}
useEffect(() => {
document.addEventListener('scroll', onScroll)
})
return (
<div ref={domRef}>
{props.children}
</div>
)
}
4. スクロールごとに、スクロール量と変化量targetFactor
を計算する
translateYの位置をスクロールロール量に合わせて変更できるように計算する。
interface ParallaxProps {
children: ReactNode
targetFactor?: number
}
const ParallaxItem = (props: ParallaxProps) => {
const domRef = useRef<HTMLDivElement>(null)
const targetFactor = props.targetFactor ? props.targetFactor : 0.15
const [offsetY, setOffsetY] = useState(0) // 計算結果
const onScroll = () => {
if (domRef.current !== null) {
const scrollY = window.pageYOffset
setOffsetY(scrollY * targetFactor * -1)
}
}
useEffect(() => {
document.addEventListener('scroll', onScroll)
})
return (
<div ref={domRef}>
{props.children}
</div>
)
}
5. 計算した値に位置を変更する
計算した値をOffsetY
をオブジェクトのtranslateYに指定する
interface ParallaxProps {
children: ReactNode
targetFactor?: number
}
const ParallaxItem = (props: ParallaxProps) => {
const domRef = useRef<HTMLDivElement>(null)
const targetFactor = props.targetFactor ? props.targetFactor : 0.15
const [offsetY, setOffsetY] = useState(0)
const onScroll = () => {
if (domRef.current !== null) {
const scrollY = window.pageYOffset
setOffsetY(scrollY * targetFactor * -1)
}
}
useEffect(() => {
document.addEventListener('scroll', onScroll)
})
return (
<div
ref={domRef}
style={{
transform: `translateY(${offsetY}px)`,
}}
>
{props.children}
</div>
)
}
6. 完成
その他の対応1
verticalPosition
とverticalOffset
でY軸方向の基準の位置を決めます。
horizontalPosition
とhorizontalOffset
でX軸方向の基準の位置を決めます。
objectSize
オブジェクトの大きさを決める。
その他の対応2
スタイルで使わない要素を除く。
その他の対応3
interface ParallaxProps {
children: ReactNode
targetFactor?: number
// 基準の位置・大きさを決める
verticalPosition: 'top' | 'bottom'
verticalOffset: number
horizontalPosition: 'left' | 'right'
horizontalOffset: number
objectSize: number
}
// スタイルで使わない要素を除く
type ParallaxStyleType = Omit<ParallaxProps, 'children' | 'targetFactor'>
const ParallaxItem = (props: ParallaxProps) => {
const domRef = useRef<HTMLDivElement>(null)
const targetFactor = props.targetFactor ? props.targetFactor : 0.15
const [offsetY, setOffsetY] = useState(0)
const onScroll = () => {
if (domRef.current !== null) {
const scrollY = window.pageYOffset // scroll量を取得
setOffsetY(scrollY * targetFactor * -1)
}
}
useEffect(() => {
document.addEventListener('scroll', onScroll)
})
return (
<div
ref={domRef}
css={parallaxItemStyle(props)} //propsでスタイルを渡す。
style={{
transform: `translateY(${offsetY}px)`,
}}
>
{props.children}
</div>
)
}
const parallaxItemStyle = (style: ParallaxStyleType) => {
return css({
position: 'absolute',
top: style.verticalPosition === 'top' ? style.verticalOffset : '',
bottom: style.verticalPosition === 'bottom' ? style.verticalOffset : '',
left: style.horizontalPosition === 'left' ? style.horizontalOffset : '',
right: style.horizontalPosition === 'right' ? style.horizontalOffset : '',
width: style.objectSize,
height: style.objectSize,
})
}
パララックス(parallax)を使って作ったサイト
↓作ったサイトはこちらです。ご覧ください。
※ Qiita Engeer Festa 2022にご参加もお願いします。
まとめ
この記事では、パララックスの作り方と使い方について解説しました。
少しは、パララックスについての理解ができたのではないのでしょうか???
最後まで読んでくださってありがとうございます!
普段はデザインやフロントエンドを中心にQiitaに記事を投稿しているので、ぜひQiitaのフォローとX(Twitter)のフォローをお願いします。