parallaxEffect | 이질감 효과
오늘의 목표
👉🏻 스크롤을 내렸을때 사진은 위로, 글씨는 옆으로 이동시켜 이질감 효과 나타내보기
1. 사이트 구조 살펴보기
CSS 살펴보기
<style>
/* parallax__nav */
#parallax__nav {
position: fixed;
right: 20px;
top: 20px;
z-index: 2000;
background-color: rgba(0,0,0,0.4);
padding: 20px 30px;
border-radius: 50px;
transition: top .4s ease;
}
#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 */
#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.3); */
text-align: left;
margin-right: 0;
position: relative;
padding-top: 7vw;
}
/* even(짝수), 2n, 2n+1, 2n*8 등 입력 가능 */
.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 {
/* left값 초기화 후 right 값 설정 */
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;
width: 110%;
height: 110%;
background: url(../assets/img/effect_bg01-min.jpg);
background-repeat: no-repeat;
background-position: center center;
background-size: cover;
left: -5%;
top: -5%;
filter: saturate(0%);
transition: all 1s;
}
.content__item:nth-child(1) .content__item__img {
background-image: url(../assets/img/effect_bg01-min.jpg);
}
.content__item:nth-child(2) .content__item__img {
background-image: url(../assets/img/effect_bg02-min.jpg);
}
.content__item:nth-child(3) .content__item__img {
background-image: url(../assets/img/effect_bg03-min.jpg);
}
.content__item:nth-child(4) .content__item__img {
background-image: url(../assets/img/effect_bg04-min.jpg);
}
.content__item:nth-child(5) .content__item__img {
background-image: url(../assets/img/effect_bg05-min.jpg);
}
.content__item:nth-child(6) .content__item__img {
background-image: url(../assets/img/effect_bg06-min.jpg);
}
.content__item:nth-child(7) .content__item__img {
background-image: url(../assets/img/effect_bg07-min.jpg);
}
.content__item:nth-child(8) .content__item__img {
background-image: url(../assets/img/effect_bg08-min.jpg);
}
.content__item:nth-child(9) .content__item__img {
background-image: url(../assets/img/effect_bg09-min.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;
}
@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;
}
}
/* 한번에 나타나기 */
/* #contents > section {
opacity: 0;
transition: all 1s;
}
#contents > section.show {
opacity: 1;
} */
/* 개별적으로 나타나기 */
#contents > section .content__item__num {
opacity: 0;
transform: translateY(200px);
transition: all 1s 0.1s cubic-bezier(0, 0.5, 0.23, 1.02);
}
#contents > section .content__item__title {
opacity: 0;
transform: translateX(-100px);
transition: all 1s 0.3s cubic-bezier(0.24, 0.43, 0.3, 0.76);
}
#contents > section .content__item__imgWrap {
opacity: 0;
transform: translateY(200px) rotate(30deg) skew(20deg);
transition: all 1s 0.6s cubic-bezier(0, 0.5, 0.23, 1.02);
}
#contents > section .content__item__desc {
opacity: 0;
transform: translateX(-200px);
transition: all 1s 0.9s cubic-bezier(0, 0.5, 0.23, 1.02);
}
#contents > section.show .content__item__num {
opacity: 0.07;
transform: translateY(0);
}
#contents > section.show .content__item__title {
opacity: 1;
transform: translateX(0);
}
#contents > section.show .content__item__imgWrap {
opacity: 1;
transform: translateY(0) rotate(0) skew(0);
}
#contents > section.show .content__item__desc {
opacity: 1;
transform: translateX(0);
}
#contents > section:nth-child(even) .content__item__title {
transform: translateX(100px);
}
#contents > section:nth-child(even).show .content__item__title {
transform: translateX(0);
}
#contents > section:nth-child(even) .content__item__desc {
transform: translateX(-200px);
}
#contents > section:nth-child(even).show .content__item__desc {
transform: translateX(0);
}
</style>
HTML 살펴보기
<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>
3. script 살펴보기
🪄 이질감 효과를 주기 전 미리 이미지의 크기를 110% 정도로 늘려 효과를 주었을 떄 검은 배경이 보이지 않도록 설정해주세요 !
<script>
function scroll(){
let scrollTop = window.pageYOffset || document.documentElement.scrollTop;
// #parallax__info에 scrollTop 값 입력
document.querySelector("#parallax__info span").innerText = Math.ceil(scrollTop);
document.querySelectorAll(".content__item").forEach(item => {
// 글씨는 올라가고 사진은 내려가면서 이질감효과
const target1 = item.querySelector(".content__item__img");
const target2 = item.querySelector(".content__item__desc");
const target3 = item.querySelector(".content__item__num");
// 스크롤을 내렸을 때 스크롤탑값이 늘어나는만큼 이미지도 같이 내려감
// target1.style.transform = `translateY(${scrollTop}px)`;
// 해당 섹션마다 0으로 초기화하고 다시 값 설정(그렇지 않으면 아래에 있는건 먼저 시야를 벗어나게 됨)
// scrollTop 값과 요소의 offsetTop 값은 오차가 생길 수 밖에 없음(정확히 일치하기 어렵기 때문에 * 0.1 계산 가능)
// 스크롤 100만큼 움직일때 사진은 10만큼 움직이도록 설정
let offset1 = (scrollTop - item.offsetTop) * 0.1;
let offset2 = (scrollTop - item.offsetTop) * 0.15;
let offset3 = (scrollTop - item.offsetTop) * 0.3;
// 사진은 위아래로, 글씨는 좌우로
// target1.style.transform = `translateY(${offset1}px)`;
// target2.style.transform = `translateX(${offset2}px)`;
// gsap 효과로 적용하기
gsap.to(target1, {duration: .3, y: offset1, ease: "power4.out"});
gsap.to(target2, {duration: .3, x: offset3});
gsap.to(target3, {duration: .3, y: offset2, ease: "expo.out"});
});
requestAnimationFrame(scroll);
}
scroll();
</script>
🔍
1. 먼저 scroll 함수를 만들고 scrollTop 값부터 정의해줍니다.
2. 각 세션의 번호와 이미지, 설명에 효과를 주기 위해 변수로 만들어줍니다.
3. 각 세션에 도착할 때마다 요소의 offsetTop 값을 scrollTop 값에서 빼주어 0으로 초기화 시켜줍니다.
(그렇지 않으면 하단에 위치한 요소들은 화면에 비치기도 전에 시야에서 벗어나버리기 때문 !)
4. 0으로 초기화 시켜준다고는 했지만 오차 범위가 있기 때문에 두 값이 완전히 일치하기는 어렵습니다.
두 값을 빼서 나온 값에 0.1을 곱해 스크롤을 했을 때 이질감이 느껴지도록 해줄 수 있습니다.
이때 곱하는 값을 각각 다르게 하면 속도를 다르게 연출할 수 있습니다.
🤓 gsap를 적용해 효과를 줄 수도 있습니다.
gsap의 다양한 ease 애니메이션 효과는 여기에서 자세하게 알아볼 수 있습니다 !
'EFFECT > PARALLAX' 카테고리의 다른 글
EFFECT | PARALLAX | 리빌 효과 (0) | 2022.10.17 |
---|---|
EFFECT | PARALLAX | 텍스트 효과 (0) | 2022.10.17 |
EFFECT | PARALLAX | 스크롤에 따라 이미지 서서히 나타내기 (7) | 2022.09.19 |
EFFECT | PARALLAX | 숨김 메뉴 + Top 기능 적용하기 (2) | 2022.09.14 |
EFFECT | PARALLAX | 사이드 메뉴 적용하기 (2) | 2022.09.14 |
댓글