見出し画像

Jqueryでパララックス画像を自作する方法

お疲れ様です。
パララックス画像、WEB制作学習中の自分からするとスタイリッシュで憧れます。

スクロールすると、スクロール量に応じて特定の画像だけが上向きに動く、というものになります。

色々とプラグインが出ているパララックスですが、今回はその仕組みを知るためにも1から自作してみました。

実務で1から自作することは、工数の関係上などであまりなさそうですが、学習の為にやってみました。

なかなか大変でしたが、仕組み自体はシンプルです。

仕組み

今回はbackground-imageではなく、imgタグを使います。
<div class="img">という画像エリアを表すdivタグの中にimgタグがあります。

親の画像エリアにposition: relative、はみ出た要素を隠すoverflow: hiddenを指定し。

子要素のimgは、高さが欲しいのでheight: 150%、width:autoを指定します。
さらに、position: absoluteとtop: 0、left: 50%、translate: -50% 0を指定します。

jQueryでスクロールして画面内に入ったら、「スクロール量 - 要素の位置」に指定した数値割ったものをマイナスしてやります。
.css('top', -「スクロール量 - 要素の位置 - 調整用の数値」)
といった感じです。

コードは以下です↓

<!-- index.html -->


<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="./css/style.min.css">
    <title>Document</title>
</head>

<body>
    <div class="container">
        <div class="txt-img">
            <div class="text">
                <p>
                    Lorem ipsum dolor sit amet consectetur adipisicing elit. Cum eveniet eos animi laboriosam libero! Odit iure consequatur saepe quod. Quae at, quis quidem minus fuga ipsam inventore non. Alias, magnam.
                </p>
            </div>
            <div class="img">
                <img src="./img/cabbage-gfbe0c78be_640.jpg" alt="" srcset="">
            </div>
        </div>

        <div class="txt-img reverse">
            <div class="text">
                <p>
                    Lorem ipsum dolor sit amet consectetur adipisicing elit. Cum eveniet eos animi laboriosam libero! Odit iure consequatur saepe quod. Quae at, quis quidem minus fuga ipsam inventore non. Alias, magnam.
                </p>
            </div>
            <div class="img">
                <img src="./img/kristopher-roller-zepnJQycr4U-unsplash.jpg" alt="" srcset="">
            </div>
        </div>

        <div class="txt-img">
            <div class="text">
                <p>
                    Lorem ipsum dolor sit amet consectetur adipisicing elit. Cum eveniet eos animi laboriosam libero! Odit iure consequatur saepe quod. Quae at, quis quidem minus fuga ipsam inventore non. Alias, magnam.
                </p>
            </div>
            <div class="img">
                <img src="./img/matteo-di-iorio-VD-Vjc8VmRA-unsplash.jpg" alt="" srcset="">
            </div>
        </div>

        <div class="txt-img reverse">
            <div class="text">
                <p>
                    Lorem ipsum dolor sit amet consectetur adipisicing elit. Cum eveniet eos animi laboriosam libero! Odit iure consequatur saepe quod. Quae at, quis quidem minus fuga ipsam inventore non. Alias, magnam.
                </p>
            </div>
            <div class="img">
                <img src="./img/merch-husey-H-AmuI7mu-c-unsplash.jpg" alt="" srcset="">
            </div>
        </div>

        <div class="txt-img">
            <div class="text">
                <p>
                    Lorem ipsum dolor sit amet consectetur adipisicing elit. Cum eveniet eos animi laboriosam libero! Odit iure consequatur saepe quod. Quae at, quis quidem minus fuga ipsam inventore non. Alias, magnam.
                </p>
            </div>
            <div class="img">
                <img src="./img/taylor-kiser-N7buN8Lv7uQ-unsplash.jpg" alt="" srcset="">
            </div>
        </div>
    </div>

    <script src="https://code.jquery.com/jquery-3.7.0.min.js" integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" crossorigin="anonymous"></script>
    <script src="./js/script.js"></script>
</body>

</html>

cssがコチラです(sassで書いてます。)↓


//style.scss
@charset "utf-8";
*,
*::before,
*::after {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    min-height: 400vh;
}

.container {
    width: min(1120px, 100% - 4rem);
    margin-inline: auto;
}

.txt-img {
    padding-top: 80px;
    padding-bottom: 80px;
    display: flex;
    gap: 35px;
    &:first-child {
        margin-top: 650px;
    }
    .text {
        flex: 2;
        p {
            font-size: 1.5rem;
        }
    }
    .img {
        flex: 1.5;
        aspect-ratio: 3/2;
        position: relative;
        overflow: hidden;
        img {
            height: 150%;
            width: auto;
            position: absolute;
            top: 0;
            left: 50%;
            translate: -50% 0;
        }
    }
}

.reverse {
    flex-direction: row-reverse;
}

txt-imgというクラスがついたdivタグの中に、text、imgというdivタグが入っています。
display: flex でそれぞれ横並びにし、reverseというクラスがついたものだけ左右逆に並べています。

text、imgそれぞれのdivタグに flexプロパティを指定し、幅を調整します。

txt-imgの最初の要素だけにmargin-top: 650px、bodyにはheight: 400vhを指定し、十分なスクロール量を確保しました。
ここはスペース確保のためのスタイルで、実務では必要ありません。

Jqueryがコチラです↓
スクロール量・要素の位置・cssの上書きの為に書きます

//script.js

$(function() {
    function parallaxImg() {
        let img = $('.img img');
        img.each(function() {
            let elemPos = $(this).offset().top;
            let scroll = $(window).scrollTop();
            let windowHeight = $(window).height();
            let adjust = 120;
            //要素が画面内に入ってすぐではなく、そこから120上に来たら発動するため

            let parallaxSpeed = 0.2;
            //画像を動かす量が多すぎると、はみ出してします可能性がある為。この値を大きくすれば、画像が動く量が大きくなる

            if (scroll > elemPos - windowHeight + adjust) {
                $(this).css('top', (scroll - elemPos) * parallaxSpeed + 'px');
                //スクロール量から要素の位置を引き、調整用の数値をかけ、文字列'px'を足したものをtopに代入
            }
        });
    }
    $(window).on('scroll', function() {
        parallaxImg();
       //画面をスクロールした時に、関数parallaxImgが発動する
    });
});

以上になります。
マウスホイールでスクロールすると、どうしてもカクカクするので、慣性スクロールなどと組み合わせると効果を発揮しそうです。

あと、画像の高さを十分確保することが必要なのでheight: 150%をしてしていますが。
それに合わせて、width: auto で横幅も多少広くなるはずです。

逆に縦長すぎる画像だと、横幅が狭くなり、画像の両端がスカスカになってしまうので、photoshopの「コンテンツに応じた塗りつぶし」でスペースを確保しておくといいかもしれないです。

最後まで閲覧頂きありがとうございます。

いいなと思ったら応援しよう!