λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
μ΄νŽ™νŠΈ

패럴럭슀 μ΄νŽ™νŠΈ - 02. μ‚¬μ΄λ“œ 메뉴

by Youcodein 2022. 9. 13.
728x90
λ°˜μ‘ν˜•

νŒ¨λŸ΄λž™μŠ€ μ΄νŽ™νŠΈ 2 - μ‚¬μ΄λ“œ 메뉴

>

νŒ¨λŸ΄λ ‰μŠ€ μ΄νŽ™νŠΈ μ‚¬μ΄λ“œ 메뉴

μŠ€ν¬λ‘€μ„ μ›€μ§μ˜€μ„ λ•Œ μ‚¬μ΄λ“œμ— μžˆλŠ” 점 λͺ¨μ–‘μ˜ 메뉴에 λ³€ν™”κ°€ μƒκΉλ‹ˆλ‹€. 슀크둀의 μœ„μΉ˜κ°€ ν•΄λ‹Ή μ„Ήμ…˜μ— μœ„μΉ˜/μ‚¬μ΄λ“œ λ©”λ‰΄μ˜ 점을 ν΄λ¦­ν•˜λ©΄ ν•΄λ‹Ή μ„Ήμ…˜μ— λŒ€μ‘ν•˜λŠ” μ‚¬μ΄λ“œ λ©”λ‰΄μ˜ 점이 ν™œμ„±ν™”λ©λ‹ˆλ‹€.

html μ†ŒμŠ€μž…λ‹ˆλ‹€

<nav id="parallax__dot">
    <ul>
        <li class="active"><a href="#section01"><span>메뉴1</span></a></li>
        <li><a href="#section02"><span>메뉴2</span></a></li>
        <li><a href="#section03"><span>메뉴3</span></a></li>
        <li><a href="#section04"><span>메뉴4</span></a></li>
        <li><a href="#section05"><span>메뉴5</span></a></li>
        <li><a href="#section06"><span>메뉴6</span></a></li>
        <li><a href="#section07"><span>메뉴7</span></a></li>
        <li><a href="#section08"><span>메뉴8</span></a></li>
        <li><a href="#section09"><span>메뉴9</span></a></li>
    </ul>
</nav>
<!-- parallax nav -->
<main id="parallax__cont">
    <div id="contents">
        <section id="section01" 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>
        <!-- section01 -->
        <section id="section02" class="content__item">
            <span class="content__item__num">02</span>
            <h2 class="content__item__title">section02</h2>
            <figure class="content__item__imgWrap">
                <div class="content__item__img"></div>
            </figure>
            <p class="content__item__desc">
                비둝 내일 μ§€κ΅¬μ˜ 쒅말이 μ˜¨λ‹€ ν•˜λ”λΌλ„ λ‚˜λŠ” 였늘 ν•œ 그루의 μ‚¬κ³Όλ‚˜λ¬΄λ₯Ό 심겠닀.
            </p>
        </section>
        <!-- section02 -->
        <section id="section03" class="content__item">
            <span class="content__item__num">03</span>
            <h2 class="content__item__title">section03</h2>
            <figure class="content__item__imgWrap">
                <div class="content__item__img"></div>
            </figure>
            <p class="content__item__desc">그듀이 μ£½μŒμ„ λ‘λ €μ›Œν•˜λŠ” 것이 μ΄μƒν•©λ‹ˆλ‹€. 삢이 μ£½μŒλ³΄λ‹€ 훨씬 더 μ•„ν”„λ‹€.</p>
        </section>
        <!-- section03 -->
        <section id="section04" class="content__item">
            <span class="content__item__num">04</span>
            <h2 class="content__item__title">section04</h2>
            <figure class="content__item__imgWrap">
                <div class="content__item__img"></div>
            </figure>
            <p class="content__item__desc">
                λͺ¨λ“  것이 λ³€ν•œλ‹€λŠ” 것을 κΉ¨λ‹¬μœΌλ©΄ λΆ™μž‘μœΌλ € ν•  것이 μ—†λ‹€.
            </p>
        </section>
        <!-- section04 -->
        <section id="section05" class="content__item">
            <span class="content__item__num">05</span>
            <h2 class="content__item__title">section05</h2>
            <figure class="content__item__imgWrap">
                <div class="content__item__img"></div>
            </figure>
            <p class="content__item__desc">
                μ–΄λ–€ 생각을 받아듀이지 μ•Šκ³  즐겁게 ν•  수 μžˆλŠ” 것은 ꡐ양 μžˆλŠ” μ •μ‹ μ˜ ν‘œμ§•μ΄λ‹€.
            </p>
        </section>
        <!-- section05 -->
        <section id="section06" class="content__item">
            <span class="content__item__num">06</span>
            <h2 class="content__item__title">section06</h2>
            <figure class="content__item__imgWrap">
                <div class="content__item__img"></div>
            </figure>
            <p class="content__item__desc">
                철학은 μ–Έμ œλ‚˜ 우리 눈 μ•žμ— 놓여 μžˆλŠ” κ·Έ μœ„λŒ€ν•œ 책에 κΈ°λ‘λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. 즉, 우주λ₯Ό μ˜λ―Έν•©λ‹ˆλ‹€.
            </p>
        </section>
        <!-- section06 -->
        <section id="section07" class="content__item">
            <span class="content__item__num">07</span>
            <h2 class="content__item__title">section07</h2>
            <figure class="content__item__imgWrap">
                <div class="content__item__img"></div>
            </figure>
            <p class="content__item__desc">
                행볡은 힘이 μ¦κ°€ν•˜κ³  저항이 극볡되고 μžˆλ‹€λŠ” λŠλ‚Œμž…λ‹ˆλ‹€.
            </p>
        </section>
        <!-- section07 -->
        <section id="section08" class="content__item">
            <span class="content__item__num">08</span>
            <h2 class="content__item__title">section08</h2>
            <figure class="content__item__imgWrap">
                <div class="content__item__img"></div>
            </figure>
            <p class="content__item__desc">μ‚¬λž‘μ˜ κ΄‘κΈ°λŠ” ν•˜λŠ˜μ˜ 좕볡 쀑 κ°€μž₯ 큰 κ²ƒμž…λ‹ˆλ‹€.</p>
        </section>
        <!-- section08 -->
        <section id="section09" class="content__item">
            <span class="content__item__num">09</span>
            <h2 class="content__item__title">section09</h2>
            <figure class="content__item__imgWrap">
                <div class="content__item__img"></div>
            </figure>
            <p class="content__item__desc">감히 μ•Œκ³ ! λ‹Ήμ‹ μ˜ 지λŠ₯을 μ‚¬μš©ν•  용기λ₯Ό κ°€μ§€μ‹­μ‹œμ˜€.</p>
        </section>
        <!-- section09 -->
    </div>
</main>
<!-- //main -->

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

css μ†ŒμŠ€μž…λ‹ˆλ‹€

/* parallax__cont */
    #parallax__cont {
        max-width: 1600px;
        /* background-color: rgba(255,255,255,0.1); */
        width: 98%;
        margin: 0 auto;
    }
    
    .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: 10vw;
    }
    
    .content__item:nth-child(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 {
        right: -5vw;
        left: auto;
    }
    
    .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;
        width: 110%;
        height: 110%;
        left: -5px;
        top: -5px;
        background-image: url(img/effect_bg02.jpg);
        background-repeat: no-repeat;
        background-position: center center;
        background-size: cover;
        filter: saturate(0%);
        transition: all 1s;
    }
    
    .content__item:nth-child(2) .content__item__img {
        background-image: url(img/effect_bg09.jpg);
    }
    
    .content__item:nth-child(3) .content__item__img {
        background-image: url(img/effect_bg09.jpg);
    }
    
    .content__item:nth-child(4) .content__item__img {
        background-image: url(img/effect_bg09.jpg);
    }
    
    .content__item:nth-child(5) .content__item__img {
        background-image: url(img/effect_bg09.jpg);
    }
    
    .content__item:nth-child(6) .content__item__img {
        background-image: url(img/effect_bg09.jpg);
    }
    
    .content__item:nth-child(7) .content__item__img {
        background-image: url(img/effect_bg09.jpg);
    }
    
    .content__item:nth-child(8) .content__item__img {
        background-image: url(img/effect_bg09.jpg);
    }
    
    .content__item:nth-child(9) .content__item__img {
        background-image: url(img/effect_bg09.jpg);
    }
    
    .content__item__desc {
        font-size: 3vw;
        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;
    }
    
    #parllax__nav li.active a {
        border-radius: 5px;
    }
    
    #parallax__info {
        position: fixed;
        left: 20px;
        bottom: 20px;
        z-index: 2000;
        background-color: rgba(0, 0, 0, 0.6);
        color: #fff;
        padding: 20px;
        border-radius: 10px;
    }
    
    #parallax__info li,
    .scrollTop {
        line-height: 1.4;
    }
    
    #parallax__info li.active a {
        border-radius: 5px;
    }
    
    @media (max-width: 800px) {
        #parallax__cont {
            margin-top: 70vw;
        }
        #parallax__info {
            left: 10;
            bottom: 10px;
        }
    
    }
    
    #parallax__dot {
        position: fixed;
        right: 20px;
        top: 50%;
        transform: translateY(-50%);
        z-index: 10000;
        background: rgba(0,0,0,0.4);
        padding: 20px 10px;
        border-radius: 30px;
    }
    #parallax__dot li {
        position: relative;
        width: 20px;
        height: 20px;
        border-radius: 50%;
        margin: 12px 8px;
        box-shadow: 0 0 0 2px rgba(255,255,255,0);
        transition: box-shadow 0.2s ease;
    }
    #parallax__dot li a {
        background: #fff;
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0;
        left: 0;
        border-radius: 50%;
        transition: transform 0.2s ease;
    }
    #parallax__dot li.active {
        box-shadow: 0 0 0 2px rgba(255,255,2551);
    }
    #parallax__dot li.active a {
        transform: scale(0.4);
    }
    #parallax__dot li span {
        display: none;
    }

javascript μ†ŒμŠ€μž…λ‹ˆλ‹€

document.querySelectorAll("#parallax__dot a").forEach( el => {
    el.addEventListener("click", e => {
        e.preventDefault();

        document.querySelector(el.getAttribute("href")).scrollIntoView({behavior:"smooth"})
    })
});

window.addEventListener("scroll", () => {
    let scrollTop = window.pageYOffset || window.scrollY || document.documentElement.scrollTop;

    document.querySelector("#parallax__info span").innerText = Math.floor(scrollTop);
    document.querySelectorAll(".content__item").forEach((e,i) => {
        if(scrollTop >= e.offsetTop - 10){
            document.querySelectorAll("#parallax__dot li").forEach(li =>{
                li.classList.remove("active")
            });
            document.querySelector("#parallax__dot li:nth-child("+(i+1)+")").classList.add("active");
        }
    })
});

점을 ν΄λ¦­ν–ˆμ„ λ•Œ 슀크둀 μ΄λ™μ‹œν‚€κΈ°

1. μ‚¬μ΄λ“œ λ©”λ‰΄μ˜ 점 정보 κ°€μ Έμ˜€κΈ°

- λ©”λ‰΄μ˜ a νƒœκ·ΈμΈ 점을 querySelectorAll을 μ΄μš©ν•΄ λͺ¨λ‘ μ„ νƒν•˜μ—¬ forEach문을 μž‘μ„±ν•©λ‹ˆλ‹€. μ—¬κΈ°μ„œ el은 각각의 점을 μ˜λ―Έν•©λ‹ˆλ‹€.

document.querySelectorAll("#parallax__dot a").forEach(el => {});

2. μ‚¬μ΄λ“œ λ©”λ‰΄μ˜ 점을 ν΄λ¦­ν–ˆμ„λ•Œ 슀크둀 μ΄λ™μ‹œν‚€κΈ°

- el(각 점/ a νƒœκ·Έ)λ₯Ό λŒ€μƒμœΌλ‘œ addEventListener() λ©”μ„œλ“œλ‘œ "click" 이벀트λ₯Ό λ°œμƒμ‹œν‚΅λ‹ˆλ‹€.
- getAttribute("href")을 μ΄μš©ν•΄ href 속성을 λΆˆλŸ¬μ™€ μ„ νƒν•©λ‹ˆλ‹€.
- scrollIntoView()λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ 점을 ν΄λ¦­ν•˜μ˜€μ„ λ•Œ μŠ€ν¬λ‘€μ„ μ΄λ™μ‹œν‚€κ²Œ ν•©λ‹ˆλ‹€. - scrollIntoView()의 behavior: "smooth" 속성을 μ‚¬μš©ν•˜λ©΄ 슀크둀 λ˜μ–΄ 화면이 이동할 λ•Œ, 화면이 λΆ€λ“œλŸ½κ²Œ μ›€μ§μž…λ‹ˆλ‹€.

β€» preventDefault

a νƒœκ·Έλ‚˜ submit νƒœκ·ΈλŠ” λˆ„λ₯΄κ²Œ 되면 href λ₯Ό 톡해 μ΄λ™ν•˜κ±°λ‚˜ 창이 μƒˆλ‘œκ³ μΉ¨ν•˜μ—¬ μ‹€ν–‰λ©λ‹ˆλ‹€.
preventDefault λ₯Ό μ‚¬μš©ν•˜λ©΄ μ΄λŸ¬ν•œ λ™μž‘μ„ 막아쀄 수 μžˆμŠ΅λ‹ˆλ‹€.
el.addEventListener("click", e => {
    e.preventDefault();

    document.querySelector(el.getAttribute("href")).scrollIntoView({behavior: "smooth"});
});

μŠ€ν¬λ‘€μ„ ν–ˆμ„ λ•Œ ν•΄λ‹Ή μ„Ήμ…˜μ— λŒ€μ‘ν•˜λŠ” λ©”λ‰΄μ˜ 점 ν™œμ„±ν™”μ‹œν‚€κΈ°

1. 슀크둀 ν–ˆμ„ λ•Œ 이벀트 λ°œμƒμ‹œν‚€κΈ°

- μ°½(window)λ₯Ό λŒ€μƒμœΌλ‘œ scroll 이벀트λ₯Ό λ°œμƒμ‹œν‚΅λ‹ˆλ‹€.

window.addEventListener("scroll", () => {});

2. λ³€μˆ˜ 생성

- 슀크둀 값을 κ΅¬ν•˜κΈ° μœ„ν•œ λ³€μˆ˜λ₯Ό μƒμ„±μ‹œν‚€κ³  λ³€μˆ˜ μ•ˆμ— 슀크둀 값을 μ €μž₯ν•©λ‹ˆλ‹€.

β€» λ³€μˆ˜μ— 세가지 값을 λͺ¨λ‘ μ €μž₯ν•˜λŠ” 이유

νŠΉμ • λΈŒλΌμš°μ €μ—μ„œ ν˜Έν™˜μ„±μ˜ 문제둜 μ•žμ˜ 값을 λΆˆλŸ¬μ˜€μ§€ λͺ»ν•  λ•Œλ₯Ό λŒ€λΉ„ν•˜μ—¬ λŒ€μ•ˆμœΌλ‘œ λ’€μ˜ 값을 뢈러였기 μœ„ν•¨μž…λ‹ˆλ‹€.
let scrollTop = window.pageYOffset || window.scrollY || document.documentElement.scrollTop;

3. scrollTop의 κ°’ 보여주기

- μ €μž₯ν•œ scrollTop 값을 보여쀄 수 μžˆλ„λ‘, λ§Œλ“€μ–΄ λ‘” span νƒœκ·Έ μ•ˆμ— innerTextλ₯Ό μ΄μš©ν•΄ μž‘μ„±ν•΄ μ€λ‹ˆλ‹€.

β€» Math.floor()

μˆ˜ν•™ 계산을 ν•΄μ£ΌλŠ” Math μ†μ„±μ˜ floor() λ©”μ„œλ“œλŠ” 값을 μ˜¬λ¦Όν•΄ μ€λ‹ˆλ‹€.
document.querySelector("#parallax__info span").innerText = Math.floor(scrollTop);

4. 각 μ„Ήμ…˜ 선택

- 각 μ„Ήμ…˜μ˜ 곡톡 μš”μ†ŒμΈ content__item 클래슀λ₯Ό μ΄μš©ν•΄, 각각의 μ„Ήμ…˜μ„ λͺ¨λ‘ 선택해 μ€λ‹ˆλ‹€.
- μ΄λŠ” 각 μ„Ήμ…˜μ˜ offsetTop κ°’κ³Ό scrollTop 값을 비ꡐ해 λ²„νŠΌμ„ ν™œμ„±ν™”ν•˜κΈ° μœ„ν•¨μž…λ‹ˆλ‹€.

document.querySelectorAll(".content__item").forEach((e, i) => {});

5. 메뉴 ν™œμ„±ν™” / λΉ„ν™œμ„±ν™”

- if문을 μ‚¬μš©ν•΄ 메뉴λ₯Ό ν™œμ„±ν™” ν•˜λŠ” 쑰건문을 μž‘μ„±ν•΄ μ€λ‹ˆλ‹€.
- scrollTop 값이 e(각 μ„Ήμ…˜)의 offsetTop 값보닀 ν¬κ±°λ‚˜ κ°™λ‹€λŠ” 것은 화면에 κ·Έ μ„Ήμ…˜μ΄ μœ„μΉ˜ν–ˆλ‹€λŠ” μ˜λ―Έμž…λ‹ˆλ‹€.
<μ€‘μš”>
- querySelectorAllλ₯Ό μ΄μš©ν•΄ λͺ¨λ“  메뉴λ₯Ό 선택해 μ€€ ν›„, forEach문을 μž‘μ„±ν•΄, λͺ¨λ“  λ©”λ‰΄μ˜ active 클래슀λ₯Ό μ œκ±°ν•©λ‹ˆλ‹€.
- μ΄λŠ” 이미 μ§€λ‚˜κ°€λ²„λ¦° μ„Ήμ…˜μ„ λ‚˜νƒ€λ‚΄λŠ” λ©”λ‰΄λŠ” ν™œμ„±ν™” λ˜μ§€ μ•Šλ„λ‘ ν•˜κΈ° μœ„ν•¨μž…λ‹ˆλ‹€.

- querySelectorλ₯Ό μ΄μš©ν•΄ i+1 번째 메뉴(ν˜„μž¬ λ„λ‹¬ν•œ μ„Ήμ…˜μ„ λ‚˜νƒ€λ‚΄λŠ” 메뉴)λ₯Ό 선택해 μ€€ ν›„, active 클래슀λ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€.
- ν˜„μž¬ λ„λ‹¬ν•œ μ„Ήμ…˜μ„ λ‚˜νƒ€λ‚΄λŠ” 메뉴λ₯Ό ν™œμ„±ν™” ν•˜κΈ° μœ„ν•¨μž…λ‹ˆλ‹€.

if(scrollTop >= e.offsetTop -10){
    document.querySelectorAll("#parallax__dot li").forEach(li => {
        li.classList.remove("active");
    });
    document.querySelector("#parallax__dot li:nth-child("+ (i+1) +")").classList.add("active");
}
728x90
λ°˜μ‘ν˜•

λŒ“κΈ€