๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Effect/Parallax Effect

[Parallax Effect] ํŒจ๋Ÿด๋Ÿญ์Šค ์ดํŽ™ํŠธ 03 - ๋ฉ”๋‰ด๋ฐ” ์ˆจ๊ฒผ๋‹ค ๋‚˜ํƒ€๋‚˜๊ฒŒ ํ•˜๊ธฐ & TOP ๋ฒ„ํŠผ

by ์ฝ”๋”ฉ๊ณต์ฑ… 2022. 9. 9.
๋ฐ˜์‘ํ˜•

ํŒจ๋Ÿด๋Ÿญ์Šค ์ดํŽ™ํŠธ 03

์ด๋ฒˆ ์‹œ๊ฐ„์—๋Š” ๊ทธ ๋™์•ˆ ๋ฐฐ์› ๋˜ JavaScript๋ฅผ ์ด์šฉํ•˜์—ฌ ํŒจ๋Ÿด๋Ÿญ์Šค(parallax, ํŒจ๋Ÿด๋ž™์Šค) ์ดํŽ™ํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋จผ์ € parallax๋ž€, '์‹œ์ฐจ(่ฆ–ๅทฎ)'๋ผ๋Š” ์˜๋ฏธ๋ฅผ ๊ฐ€์ง„ ์ฒœ๋ฌธํ•™ ์šฉ์–ด์ด๋ฉฐ, ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ ๋‚ด๋น„๊ฒŒ์ด์…˜ ๋ฐ”์—์„œ ํŠน์ • ์„น์…˜์œผ๋กœ ๊ฐ€๋Š” ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ํ•ด๋‹น ์„น์…˜์œผ๋กœ ์‹œ์ฐจ๋ฅผ ๋‘๊ณ  ์Šค๋ฌด์Šคํ•˜๊ฒŒ ์ด๋™์‹œ์ผœ ์ฃผ๋Š” ํšจ๊ณผ๋ฅผ ๋งŒ๋“ค์–ด๋ณด๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

์ง€๋‚œ ํŒจ๋Ÿด๋Ÿญ์Šค 01 ํฌ์ŠคํŒ…์—์„œ ๋งŒ๋“  ํ‹€์„ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•œ ์ฑ„ ๋ฉ”๋‰ด ๋ฐ”๋ฅผ ์ˆจ๊ฒผ๋‹ค ๋‚˜ํƒ€๋‚˜๊ฒŒ ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ํŽ˜์ด์ง€ ์ตœํ•˜๋‹จ์œผ๋กœ ๋‚ด๋ ค๊ฐ€๋ฉด TOP ๋ฒ„ํŠผ์ด ๋‚˜ํƒ€๋‚˜๊ณ , TOP ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ํŽ˜์ด์ง€ ์ตœ์ƒ๋‹จ์œผ๋กœ ์˜ฌ๋ผ๊ฐ€๊ฒŒ ํ•˜๋Š” ์ดํŽ™ํŠธ๋„ ์ถ”๊ฐ€ํ•ด๋ณด๋„๋ก ํ•ฉ์‹œ๋‹ค.


HTML ์†Œ์Šค

header, parallax__dot(dot ๋‚ด๋น„๊ฒŒ์ด์…˜), main(parallax__cont(๋ช…์–ธ ๋ชจ์Œ)), aside(parallax__info(์Šคํฌ๋กคํƒ‘๊ฐ’)), footer(๋ชจ๋‹ฌ ๋ฐ•์Šค)๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.

<body class="img10">
    <header id="header">
        <h1>JAVASCRIPT PARALLAX EFFECT 03</h1>
        <p>ํŒจ๋Ÿด๋Ÿญ์Šค ์ดํŽ™ํŠธ</p>
        <ul>
            <li><a href="parallaxEffect01.html">01</a></li>
            <li><a href="parallaxEffect02.html">02</a></li>
            <li class="active"><a href="parallaxEffect03.html">03</a></li>
            <li><a href="parallaxEffect04.html">04</a></li>
            <li><a href="parallaxEffect05.html">05</a></li>
            <li><a href="parallaxEffect06.html">06</a></li>
            <li><a href="parallaxEffect07.html">07</a></li>
        </ul>
    </header>
    <!-- //header -->

    <nav id="parallax__nav">
        <ul>
            <li class="active"><a href="#section1">๋ฉ”๋‰ด1</a></li>
            <li><a href="#section2"><span>๋ฉ”๋‰ด2</span></a></li>
            <li><a href="#section3"><span>๋ฉ”๋‰ด3</span></a></li>
            <li><a href="#section4"><span>๋ฉ”๋‰ด4</span></a></li>
            <li><a href="#section5"><span>๋ฉ”๋‰ด5</span></a></li>
            <li><a href="#section6"><span>๋ฉ”๋‰ด6</span></a></li>
            <li><a href="#section7"><span>๋ฉ”๋‰ด7</span></a></li>
            <li><a href="#section8"><span>๋ฉ”๋‰ด8</span></a></li>
            <li><a href="#section9"><span>๋ฉ”๋‰ด9</span></a></li>
        </ul>
    </nav>
    <!-- //parallax__nav -->

    <div id="parallax__top">
        Top
    </div>
    <!-- //parallax__top -->

    <main id="parallax__cont">
        <div id="contents">
            <section id="section1" class="content__item">
                <span class="content__item__num">01</span>
                <h2 class="content__item__title">section1</h2>
                <figure class="content__item__imgWrap">
                    <div class="content__item__img"></div>
                </figure>
                <p class="content__item__desc">๊ฒฐ๊ณผ๋„ ์ค‘์š”ํ•˜์ง€๋งŒ, ๊ณผ์ •์„ ๋” ์ค‘์š”ํ•˜๊ฒŒ ์ƒ๊ฐํ•œ๋‹ค.</p>
            </section>
            <!-- //section1 -->

            <section id="section2" class="content__item">
                <span class="content__item__num">02</span>
                <h2 class="content__item__title">section2</h2>
                <figure class="content__item__imgWrap">
                    <div class="content__item__img"></div>
                </figure>
                <p class="content__item__desc">์ธ์ƒ์—์„œ ๋งŽ์€ ํŒจ๋ฐฐ์— ์ง๋ฉดํ•˜๊ฒ ์ง€๋งŒ ๊ฒฐ์ฝ” ํŒจ๋ฐฐํ•˜์ง€ ๋ง๋ผ.</p>
            </section>
            <!-- //section2 -->

            <section id="section3" class="content__item">
                <span class="content__item__num">03</span>
                <h2 class="content__item__title">section3</h2>
                <figure class="content__item__imgWrap">
                    <div class="content__item__img"></div>
                </figure>
                <p class="content__item__desc">โ€œ๋‚ด ๋„ˆ ๊ทธ๋Ÿด ์ค„ ์•Œ์•˜๋‹คโ€ ์•Œ์•˜์œผ๋ฉด ์ œ๋ฐœ ๋ฏธ๋ฆฌ ๋ง ํ•ด์ค˜๋ผ.</p>
            </section>
            <!-- //section3 -->

            <section id="section4" class="content__item">
                <span class="content__item__num">04</span>
                <h2 class="content__item__title">section4</h2>
                <figure class="content__item__imgWrap">
                    <div class="content__item__img"></div>
                </figure>
                <p class="content__item__desc">๋Šฆ์—ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•  ๋•Œ๊ฐ€ ์ง„์งœ ๋„ˆ๋ฌด ๋Šฆ์—ˆ๋‹ค.</p>
            </section>
            <!-- //section4 -->

            <section id="section5" class="content__item">
                <span class="content__item__num">05</span>
                <h2 class="content__item__title">section5</h2>
                <figure class="content__item__imgWrap">
                    <div class="content__item__img"></div>
                </figure>
                <p class="content__item__desc">์ฆ๊ธธ ์ˆ˜ ์—†์œผ๋ฉด ํ”ผํ•˜๋ผ.</p>
            </section>
            <!-- //section5 -->

            <section id="section6" class="content__item">
                <span class="content__item__num">06</span>
                <h2 class="content__item__title">section6</h2>
                <figure class="content__item__imgWrap">
                    <div class="content__item__img"></div>
                </figure>
                <p class="content__item__desc">์ƒํ™œ์€ ๊ณผ๊ฐํ•œ ๋ชจํ—˜์ด๊ฑฐ๋‚˜ ์•„๋‹ˆ๋ฉด ์•„๋ฌด๊ฒƒ๋„ ์•„๋‹ˆ๋‹ค.</p>
            </section>
            <!-- //section6 -->

            <section id="section7" class="content__item">
                <span class="content__item__num">07</span>
                <h2 class="content__item__title">section7</h2>
                <figure class="content__item__imgWrap">
                    <div class="content__item__img"></div>
                </figure>
                <p class="content__item__desc">์–ด๋ ค์šด ๊ธธ์€ ๊ธธ์ด ์•„๋‹ˆ๋‹ค.</p>
            </section>
            <!-- //section7 -->

            <section id="section8" class="content__item">
                <span class="content__item__num">08</span>
                <h2 class="content__item__title">section8</h2>
                <figure class="content__item__imgWrap">
                    <div class="content__item__img"></div>
                </figure>
                <p class="content__item__desc">์ž ์„ ์ž๋„ ํ”ผ๋กœ๊ฐ€ ์•ˆ ํ’€๋ฆฌ๋ƒ.</p>
            </section>
            <!-- //section8 -->

            <section id="section9" class="content__item">
                <span class="content__item__num">09</span>
                <h2 class="content__item__title">section9</h2>
                <figure class="content__item__imgWrap">
                    <div class="content__item__img"></div>
                </figure>
                <p class="content__item__desc">์ธ์ƒ์€ ์œ„๋Œ€ํ•œ ๋ชจํ—˜์ด๊ฑฐ๋‚˜ ์•„๋‹ˆ๋ฉด ์•„๋ฌด๊ฒƒ๋„ ์•„๋‹ˆ๋‹ค.</p>
            </section>
            <!-- //section9 -->
        </div>
    </main>
    <!-- //main -->

    <aside id="parallax__info">
        <div class="scroll">scrollTop : <span>0</span>px</div>
    </aside>
    <!-- //parallax__info -->

    <footer id="footer">
        <div class="modal__wrap">
        </div>
    </footer>
    <!-- //footer -->
</body>

JS ์†Œ์Šค

๋ถ€๋“œ๋Ÿฌ์šด ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ฃผ๊ธฐ ์œ„ํ•ด e.preventDefault()๋กœ ๋‚ด๋น„๊ฒŒ์ด์…˜ ๋ฐ” ์ด๋™ ๊ธฐ๋Šฅ์„ ์ž ์‹œ ๋น„ํ™œ์„ฑํ™” ์‹œํ‚จ ๋‹ค์Œ behavior: "smooth"๋กœ ์Šค๋ฌด์Šคํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ๋ฅผ ์ฃผ๋Š” ๋™์‹œ์— ์ด๋™ ๊ธฐ๋Šฅ์„ ์žฌํ™œ์„ฑํ™”์‹œํ‚จ๋‹ค.

๊ทธ ๋‹ค์Œ ์Šคํฌ๋กคํƒ‘๊ฐ’์„ let ๋ณ€์ˆ˜์— ์ €์žฅํ•˜๊ณ  ๊ทธ ๊ฐ’์„ ๋ฐ˜์˜ฌ๋ฆผํ•˜์—ฌ ํ‘œ์‹œ๋˜๋„๋ก ์„ค์ •ํ•˜๊ณ , ์Šคํฌ๋กค์ด ํ•ด๋‹น ์„น์…˜์„ ์ง€๋‚˜๊ฐ€๋Š”๊ฐ€ ์ง€๋‚˜์น˜์ง€ ์•Š์•˜๋Š”๊ฐ€ ์—ฌ๋ถ€๋ฅผ if๋ฌธ์œผ๋กœ ๊ฐ€๋ ค .active ํšจ๊ณผ๋ฅผ ์ถ”๊ฐ€ํ• ์ง€ ์ œ๊ฑฐํ• ์ง€๋ฅผ ์„ค์ •ํ•œ๋‹ค.

window.addEventListener("scroll", () => {
    let scrollTop = window.pageYOffset || window.scrollY || document.documentElement.scrollTop;     // ํ˜„์žฌ ๋ธŒ๋ผ์šฐ์ € ํ™”๋ฉด ์ค‘ ์ตœ์ƒ๋‹จ ์œ„์น˜ ๊ฐ’

    // ๋ฌธ์„œ์ „์ฒด๋†’์ด - ๋ธŒ๋ผ์šฐ์ €๋†’์ด(์ฆ‰, ๋งˆ์ง€๋ง‰ ์„น์…˜์— ๋„๋‹ฌํ–ˆ์„ ๋•Œ) ==> TOP ๋ฒ„ํŠผ ๋‚˜ํƒ€๋‚˜๊ฒŒ ํ•จ
    if(scrollTop + window.innerHeight >= document.body.scrollHeight){
        document.querySelector("#parallax__top").classList.add("show");
    } else {
        document.querySelector("#parallax__top").classList.remove("show");
    }

    // top ๋ฒ„ํŠผ : ๋ˆŒ๋ €์„ ๋•Œ ํŽ˜์ด์ง€ ์ตœ์ƒ๋‹จ์œผ๋กœ ์Šค๋ฌด์Šคํ•˜๊ฒŒ ์ด๋™์‹œ์ผœ์คŒ
    document.querySelector("#parallax__top").addEventListener("click", () => {
        window.scrollTo({left:0, top:0, behavior:"smooth"});
    });
    
    document.querySelector("#parallax__info span").innerText = Math.ceil(scrollTop);
});

// ์Šคํฌ๋กค ์›€์ง์ผ ๋•Œ
// ํŠธ๋ฆฌ๊ฑฐ ๋ณ€์ˆ˜ ์ด์šฉ
let nowScroll = true;   // ํŠธ๋ฃจ์ผ๋•Œ ์‹คํ–‰
let lastScroll = 0;

function scrollProgress() {
    nowScroll = true;

    setInterval(() => {
        if(nowScroll) {
            nowScroll = false;
            hasScroll();
        }
    }, 300) // 0.3์ดˆ๋งˆ๋‹ค
}

  function hasScroll() {
    let scrollTop = window.pageYOffset || window.scrollY || document.documentElement.scrollTop;

    // scrollTop๊ฐ’์ด lastScroll๋ณด๋‹ค ์ ์œผ๋ฉด
    if(scrollTop < lastScroll) {
      document.querySelector("#parallax__nav").classList.add("show");   //๋‚ด๋น„๊ฒŒ์ด์…˜ ๋ฐ” ๋ณด์—ฌ์ฃผ๊ธฐ
    } else {
      document.querySelector("#parallax__nav").classList.remove("show");    // (์•„๋‹ ๊ฒฝ์šฐ) ์ˆจ๊ธฐ๊ธฐ
    }
    lastScroll = scrollTop;     // scrollTop๊ฐ’์„ lastScroll์— ์ €์žฅํ•จ.
  }

  window.addEventListener("scroll", scrollProgress);

CSS ์†Œ์Šค

ํŒจ๋Ÿด๋Ÿญ์Šค ํšจ๊ณผ์—๋งŒ ์ ์šฉ๋˜๋Š” CSS ์†Œ์Šค์ด๋‹ค. ๊ณตํ†ต/์ดˆ๊ธฐํ™” ๋ถ€๋ถ„ CSS๋Š” ํ•˜๋‹จ์˜ CSS ์†Œ์Šค ๋ณด๊ธฐ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ํ™•์ธํ•  ๊ฒƒ.

<style>
    /* parallax__nav */
    #parallax__nav {
        position: fixed;
        right: 20px;
        top: -200px;
        z-index: 2000;
        background-color: rgba(0,0,0,0.4);
        padding: 20px 30px;
        border-radius: 50px;
        transition: top .4s ease;
    }
    #parallax__nav.show {
            top: 20px;
        }
    #parallax__nav li {
        display: inline;
        margin: 0 5px;
    }
    
    #parallax__nav li a {
        display: inline-block;
        height: 30px;
        padding: 5px 20px;
        text-align: center;
        line-height: 30px;
    }
    #parallax__nav li.active a {
        background: #fff;
        color: #000;
        border-radius: 20px;
        box-sizing: content-box;
    }

    #parallax__cont {
        max-width: 1600px;
        width: 98%;
        margin: 0 auto;
        /* background-color: rgba(255,255,255,0.1); */
    }
    .content__item {
        width: 1000px;
        max-width: 70vw;
        margin: 30vw auto;
        /* background-color: rgba(255,255,255,0.1); */
        text-align: left;
        margin-right: 0;
        position: relative;
        padding-top: 7vw;
    }
    .content__item:nth-child(even) {  /* even == ์ง์ˆ˜๋งŒ ์„ ํƒ */
        margin-left: 0;
        text-align: right;
    }
    .content__item__num {
        font-size: 35vw;
        font-family: 'Lato';
        font-weight: 100;
        position: absolute;
        left: -5vw;
        top: -16vw;
        opacity: 0.07;
        z-index: -2;
    }
    .content__item:nth-child(even) .content__item__num {
        left: auto;
        right: -5vw;
    }
    .content__item__title {
        font-weight: 400;
        text-transform: capitalize;
    }
    .content__item__imgWrap {
        width: 100%;
        padding-bottom: 56.25%;
        background: #000;
        position: relative;
        overflow: hidden;
        z-index: -1;
    }
    .content__item__img {
        position: absolute;
        background-image: url(../assets/img/effect_bg10.jpg);
        background-repeat: no-repeat;
        background-position: center center;
        background-size: cover;
        width: 110%;
        height: 110%;
        left: -5%;
        top: -5%;
        filter: saturate(0%);
        transition: all 1s;
    }
    .content__item:nth-child(1) .content__item__img {
        background-image: url(../assets/img/effect_bg10.jpg);
    }
    .content__item:nth-child(2) .content__item__img {
        background-image: url(../assets/img/effect_bg09.jpg);
    }
    .content__item:nth-child(3) .content__item__img {
        background-image: url(../assets/img/effect_bg08.jpg);
    }
    .content__item:nth-child(4) .content__item__img {
        background-image: url(../assets/img/effect_bg07.jpg);
    }
    .content__item:nth-child(5) .content__item__img {
        background-image: url(../assets/img/effect_bg06.jpg);
    }
    .content__item:nth-child(6) .content__item__img {
        background-image: url(../assets/img/effect_bg05.jpg);
    }
    .content__item:nth-child(7) .content__item__img {
        background-image: url(../assets/img/effect_bg04.jpg);
    }
    .content__item:nth-child(8) .content__item__img {
        background-image: url(../assets/img/effect_bg03.jpg);
    }
    .content__item:nth-child(9) .content__item__img {
        background-image: url(../assets/img/effect_bg02.jpg);
    }

    .content__item__desc {
        font-size: 4vw;
        line-height: 1.4;
        margin-top: -5vw;
        margin-left: -4vw;
        word-break: keep-all;
    }
    .content__item:nth-child(even) .content__item__desc {
        margin-left: auto;
        margin-right: -4vw;
    }

    #parallax__info {
        position: fixed;
        left: 20px;
        bottom: 20px;
        z-index: 2000;
        background: rgba(0,0,0,0.4);
        color: #fff;
        padding: 20px 30px;
        border-radius: 10px;
    }
    #parallax__info li, .scrollTop {
        line-height: 1.4;
    }

    #parallax__top {
        position: fixed;
        left: 50%;
        bottom: -220px;
        z-index: 10000;
        transform: translateX(-50%);
        width: 40px;
        height: 40px;
        background: rgba(0,0,0,0.4);
        text-align: center;
        line-height: 40px;
        color: #fff;
        border-radius: 50%;
        padding: 10px;
        cursor: pointer;
        transition: all 0.3s;
    }
    #parallax__top.show {
        bottom: 20px;
    }
    #parallax__top:hover {
       background: #fff;
       color: #000;
    }

    /* ๋ฐ˜์‘ํ˜• */
    @media (max-width: 800px) {
        #parallax__cont {
            margin-top: 70vw;
        }
        #parallax__nav {
            padding: 10px;
            right: auto;
            left: 10px;
            top: 50%;
            transform: translateY(-50%);
            border-radius: 5px;
            background-color: rgba(0,0,0,0.8);
        }
        #parallax__nav li {
            display: block;
            margin: 5px;
        }
        #parallax__nav li a {
            font-size: 14px;
            padding: 5px;
            border-radius: 5px;
            height: auto;
            line-height: 1;
        }
        #parallax__nav li.active a {
            border-radius: 5px;
        }
        #parallax__info {
            left: 10px;
            bottom: 10px;
        }
    }
</style>

์ด๋ฏธ์ง€ ์„ค๋ช…์œผ๋กœ ํ•œ ๋ˆˆ์— ๋ณด๊ธฐ

๊ฒฐ๊ณผ

๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€


Reference Book

JavaScript
HTML
CSS
๊ด‘๊ณ  ์ค€๋น„์ค‘์ž…๋‹ˆ๋‹ค.