TL;DR
scroll-behavior便利ですね。
・・・とかいいつつ、うまくスムーススクロールが動かなかった(おそらく自分の実装が悪い気もする)ので、
バニラでスムーススクロールを実装しました。
よくあるサンプル、動きが直線的で気持ち悪いですよね。
なんでイージングつけました。
ソースコード
適当にコピペしてimportしたら使えるかと思います。
ソース説明
メインのソースはよくあるSmoothScrollと一緒です。
// clickイベント取得して、aタグのハッシュを取得する用。
export const smoothScroll = (event) => {
event.preventDefault()
smoothScrollWithHash(event?.target?.hash ?? "html")
}
// 直で”#id”と指定する用
export const smoothScrollWithHash = (hash) => {
const el = document.querySelectorAll(hash)[0]
// 目的地と開始地の座標取得
const targetPosition = el.offsetTop
const startPosition = document.scrollingElement.scrollTop
let currentPosition = startPosition
// 上スクロールか下スクロールか
const goDown = currentPosition < targetPosition
const interval = setInterval(function() {
// Sin関数でイージングをつけた移動量を計算する
const mp = movingPosition(startPosition, targetPosition, currentPosition)
// mpの返り値が0だと無限ループになるので、最低限移動する値を加減算する
currentPosition += goDown ? mp + 5 : - mp - 5
if (goDown && currentPosition > targetPosition
|| !goDown && currentPosition < targetPosition) {
clearInterval(interval);
document.scrollingElement.scrollTop = targetPosition
}
document.scrollingElement.scrollTop = currentPosition
}, 10);
}
今回イージングを実現するために、Sin関数で移動量を計算しています。
Math.sin(Math.PI)
の時は移動速度が上がって下がる。
Math.sin(Math.PI/2)
の時は移動速度がギュインと上がります。
const movingPosition = (start, target, current) => {
const sin = Math.sin((current - target) / (start - target) * Math.PI)
return sin * 50
}
(current - target) / (start - target)
は開始時は1で、
currentがtargetに近づくにつれ0に近づきます。
ですので、画像x軸のπの位置から0の位置まで移動量を変化させながらスクロールされるイメージです。
まとめ
はとくにないよ。