main.js 를 적용한 후에 show-scene-1에서 2로 넘아기질 않습니다..ㅠㅠ
291
작성한 질문수 1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;900&display=swap" rel="stylesheet">
<link rel="stylesheet" href="default.css">
<link rel="stylesheet" href="01.css">
</head>
<body>
<div class="container">
<nav class="global-nav">
<div class="global-nav-links">
<a href="#" class="global-nav-item">Rooms</a>
<a href="#" class="global-nav-item">Ideas</a>
<a href="#" class="global-nav-item">Stores</a>
<a href="#" class="global-nav-item">Contact</a>
</div>
</nav>
<nav class="local-nav">
<div class="local-nav-links">
<a href="#" class="product-name">AirMug Pro</a>
<a href="#" class="local-nav-item">개요</a>
<a href="#" class="local-nav-item">제품사양</a>
<a href="#" class="local-nav-item">구입하기</a>
</div>
</nav>
<section class="scroll-section" id="scroll-section-0">
<h1>AirMug Pro</h1>
<div class="sticky-elem main-message a">
<p>온전히 빠져들게 하는<br>최고급 세라믹</p>
</div>
<div class="sticky-elem main-message b">
<p>주변 맛을 느끼게 해주는<br>주변 맛 허용 모드</p>
</div>
<div class="sticky-elem main-message c">
<p>온종일 편안한<br>맞춤형 손잡이</p>
</div>
<div class="sticky-elem main-message d">
<p>새롭게 입가를<br>찾아온 매혹</p>
</div>
</section>
<section class="scroll-section" id="scroll-section-1">
<p class="description">
<strong >보통 스크롤 영역</strong>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Blanditiis optio quasi maxime quam dolore sequi, beatae non qui dolorum magni aspernatur. Temporibus id debitis accusantium non porro. Veritatis, magnam saepe. Lorem ipsum dolor sit, amet consectetur adipisicing elit. Nobis, debitis vero aliquam facilis soluta, facere, quis magnam ex deleniti dicta reprehenderit ad necessitatibus veritatis quas repellendus nemo tempore molestiae dignissimos.
</p>
</section>
<section class="scroll-section" id="scroll-section-2">
<div class="sticky-elem main-message a">
<p>
<small>편안한 촉감</small>
입과 하나되다
</p>
</div>
<div class="sticky-elem desc-message b">
<p>
편안한 목넘김을 완성하는 디테일한 여러 구성 요소들, 우리는 이를 하나하나 새롭게 살피고 재구성하는 과정을 거쳐 새로운 수준의 머그, AirMug Pro를 만들었습니다. 입에 뭔가 댔다는 감각은 어느새 사라지고 오롯이 당신과 음료만 남게 되죠.
</p>
<div class="pin"></div>
</div>
<div class="sticky-elem desc-message c">
<p>
디자인 앤 퀄리티 오브 스웨덴,<br>메이드 인 차이나
</p>
<div class="pin"></div>
</div>
</section>
<section class="scroll-section" id="scroll-section-3">
<p class="mid-message">
<strong>Retina 머그</strong><br>
아이디어를 광활하게 펼칠<br>
아름답고 부드러운 음료 공간.
</p>
<p class="canvas-caption">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Assumenda natus totam molestias sequi possimus ducimus nisi id. Odit, mollitia consequuntur voluptatum eius doloremque, aperiam, porro tenetur officiis ex illum nisi! Lorem ipsum dolor sit amet consectetur, adipisicing elit. Dolorum ducimus nemo harum iusto consequatur, ipsam necessitatibus nulla, tempora nobis, nam sunt nostrum accusantium atque. Itaque quas veniam eum molestiae nesciunt!
</p>
</section>
<footer class="footer">
2020, 최태호
</footer>
</div>
<script src="js/01.js"></script>
</body>
</html>
(()=> {
let yOffset = 0; //window.pageYOffset 대신 쓸 변수
let prevScrollHeight = 0; //현재 스크롤 위치(yoffset)보다 이전에 위치한 스크롤 섹션들의 스크롤 높이값의 합
let currentScene = 0; //현재 활성된(눈앞에 보고 있는)씬(scroll-section)
let enterNewScene = false; //새로운 씬이 시작된 순간 트루로 바뀔 예정
const sceneInfo = [
{
//0
type: 'sticky',
heightNum: 5, //브라우저 높이의 5배로 scrollHeight를 세팅(디바이스의 높이의 5배를 하기 위해 설정)
scrollHeight: 0,
objs: {
container: document.querySelector("#scroll-section-0"),
messageA: document.querySelector('#scroll-section-0 .main-message.a'),
messageB: document.querySelector('#scroll-section-0 .main-message.b'),
messageC: document.querySelector('#scroll-section-0 .main-message.c'),
messageD: document.querySelector('#scroll-section-0 .main-message.d'),
},
values: {
messageA_opacity_in: [0, 1, { start: 0.1, end: 0.2 }],
messageB_opacity_in: [0, 1, { start: 0.3, end: 0.4 }],
messageC_opacity_in: [0, 1, { start: 0.5, end: 0.6 }],
messageD_opacity_in: [0, 1, { start: 0.7, end: 0.8 }],
messageA_translateY_in: [20, 0, { start: 0.1, end: 0.2 }],
messageB_translateY_in: [20, 0, { start: 0.3, end: 0.4 }],
messageC_translateY_in: [20, 0, { start: 0.5, end: 0.6 }],
messageD_translateY_in: [20, 0, { start: 0.7, end: 0.8 }],
messageA_opacity_out: [1, 0, { start: 0.25, end: 0.3 }],
messageB_opacity_out: [1, 0, { start: 0.45, end: 0.5 }],
messageC_opacity_out: [1, 0, { start: 0.65, end: 0.7 }],
messageD_opacity_out: [1, 0, { start: 0.85, end: 0.9 }],
messageA_translateY_out: [0, -20, { start: 0.25, end: 0.3 }],
messageB_translateY_out: [0, -20, { start: 0.45, end: 0.5 }],
messageC_translateY_out: [0, -20, { start: 0.65, end: 0.7 }],
messageD_translateY_out: [0, -20, { start: 0.85, end: 0.9 }]
}
},
{
//1
type: 'normal',
heightNum: 5,
scrollHeight: 0,
objs: {
container: document.querySelector("#scroll-section-1"),
content: document.querySelector('#scroll-section-1 .description')
}
},
{
//2
type: 'sticky',
heightNum: 5,
scrollHeight: 0,
objs: {
container: document.querySelector('#scroll-section-2'),
messageA: document.querySelector('#scroll-section-2 .a'),
messageB: document.querySelector('#scroll-section-2 .b'),
messageC: document.querySelector('#scroll-section-2 .c'),
pinB: document.querySelector('#scroll-section-2 .b .pin'),
pinC: document.querySelector('#scroll-section-2 .c .pin')
},
values: {
messageA_translateY_in: [20, 0, { start: 0.15, end: 0.2 }],
messageB_translateY_in: [30, 0, { start: 0.6, end: 0.65 }],
messageC_translateY_in: [30, 0, { start: 0.87, end: 0.92 }],
messageA_opacity_in: [0, 1, { start: 0.25, end: 0.3 }],
messageB_opacity_in: [0, 1, { start: 0.6, end: 0.65 }],
messageC_opacity_in: [0, 1, { start: 0.87, end: 0.92 }],
messageA_translateY_out: [0, -20, { start: 0.4, end: 0.45 }],
messageB_translateY_out: [0, -20, { start: 0.68, end: 0.73 }],
messageC_translateY_out: [0, -20, { start: 0.95, end: 1 }],
messageA_opacity_out: [1, 0, { start: 0.4, end: 0.45 }],
messageB_opacity_out: [1, 0, { start: 0.68, end: 0.73 }],
messageC_opacity_out: [1, 0, { start: 0.95, end: 1 }],
pinB_scaleY: [0.5, 1, { start: 0.6, end: 0.65 }],
pinC_scaleY: [0.5, 1, { start: 0.87, end: 0.92 }]
}
},
{
//3
type: 'sticky',
heightNum: 5,
scrollHeight: 0,
objs: {
container: document.querySelector("#scroll-section-3")
}
}
];
function setLayout() {
// 각 스크롤 섹션의 높이 세팅
for (let i=0; i< sceneInfo.length; i++){
if (sceneInfo[i].type === "sticky") {
sceneInfo[i].scrollHeight = sceneInfo[i].heightNum * window.innerHeight;
} else if (sceneInfo[i].type === "normal") {
sceneInfo[i].scrollHeight = sceneInfo[i].objs.container.yOffsetHeight + window.innerHeight * 0.5;
}
sceneInfo[i].objs.container.style.height = `${sceneInfo[i].scrollHeight}px`;
}
yOffset = window.pageYOffset;
let totalScrollHeight = 0;
for (let i = 0; i < sceneInfo.length; i++) {
totalScrollHeight += sceneInfo[i].scrollHeight;
if (totalScrollHeight >= yOffset) {
currentScene = i;
break;
}
}
document.body.setAttribute('id', `show-scene-${currentScene}`);
}
function calcValues (values, currentYOffset) {
let rv;
// 현재 씬(스크롤섹션)에서 스크롤된 범위를 비율로 구하기
const scrollHeight = sceneInfo[currentScene].scrollHeight;
const scrollRatio = currentYOffset / sceneInfo[currentScene].scrollHeight;
if (values.length === 3) {
// start ~ end 사이에 애니메이션 실행
const partScrollStart = values[2].start * scrollHeight;
const partScrollEnd = values[2].end * scrollHeight;
const partScrollHeight = partScrollEnd - partScrollStart;
if (currentYOffset >= partScrollStart && currentYOffset <= partScrollEnd) {
rv = (currentYOffset - partScrollStart) / partScrollHeight * (values[1] - values[0]) + values[0];
} else if (currentYOffset < partScrollStart){
rv = values[0];
} else if (currentYOffset > partScrollEnd) {
rv = values[1];
}
} else {
rv = scrollRatio * (values[1] - values[0]) + values[0];
}
console.log(rv)
return rv;
}
function playAnimation() {
const objs = sceneInfo[currentScene].objs;
const values = sceneInfo[currentScene].values;
const currentYOffset = yOffset- prevScrollHeight;
const scrollHeight = sceneInfo[currentScene].scrollHeight;
const scrollRatio = currentYOffset / scrollHeight;
switch (currentScene) {
case 0:
if (scrollRatio <= 0.22) {
// in
objs.messageA.style.opacity = calcValues(values.messageA_opacity_in, currentYOffset);
objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_in, currentYOffset)}%, 0)`;
} else {
// out
objs.messageA.style.opacity = calcValues(values.messageA_opacity_out, currentYOffset);
objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_out, currentYOffset)}%, 0)`;
}
if (scrollRatio <= 0.42) {
// in
objs.messageB.style.opacity = calcValues(values.messageB_opacity_in, currentYOffset);
objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_in, currentYOffset)}%, 0)`;
} else {
// out
objs.messageB.style.opacity = calcValues(values.messageB_opacity_out, currentYOffset);
objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_out, currentYOffset)}%, 0)`;
}
if (scrollRatio <= 0.62) {
// in
objs.messageC.style.opacity = calcValues(values.messageC_opacity_in, currentYOffset);
objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_in, currentYOffset)}%, 0)`;
} else {
// out
objs.messageC.style.opacity = calcValues(values.messageC_opacity_out, currentYOffset);
objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_out, currentYOffset)}%, 0)`;
}
if (scrollRatio <= 0.82) {
// in
objs.messageD.style.opacity = calcValues(values.messageD_opacity_in, currentYOffset);
objs.messageD.style.transform = `translate3d(0, ${calcValues(values.messageD_translateY_in, currentYOffset)}%, 0)`;
} else {
// out
objs.messageD.style.opacity = calcValues(values.messageD_opacity_out, currentYOffset);
objs.messageD.style.transform = `translate3d(0, ${calcValues(values.messageD_translateY_out, currentYOffset)}%, 0)`;
}
break;
case 1:
// let messageA_opacity_in = calcValues(values.messageA_opacity, currentYOffset);
// objs.messageA.style.opacity = messageA_opacity_in;
break;
case 2:
// console.log("2 play");
if (scrollRatio <= 0.32) {
// in
objs.messageA.style.opacity = calcValues(values.messageA_opacity_in, currentYOffset);
objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_in, currentYOffset)}%, 0)`;
} else {
// out
objs.messageA.style.opacity = calcValues(values.messageA_opacity_out, currentYOffset);
objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_out, currentYOffset)}%, 0)`;
}
if (scrollRatio <= 0.67) {
// in
objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_in, currentYOffset)}%, 0)`;
objs.messageB.style.opacity = calcValues(values.messageB_opacity_in, currentYOffset);
objs.pinB.style.transform = `scaleY(${calcValues(values.pinB_scaleY, currentYOffset)})`;
} else {
// out
objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_out, currentYOffset)}%, 0)`;
objs.messageB.style.opacity = calcValues(values.messageB_opacity_out, currentYOffset);
objs.pinB.style.transform = `scaleY(${calcValues(values.pinB_scaleY, currentYOffset)})`;
}
if (scrollRatio <= 0.93) {
// in
objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_in, currentYOffset)}%, 0)`;
objs.messageC.style.opacity = calcValues(values.messageC_opacity_in, currentYOffset);
objs.pinC.style.transform = `scaleY(${calcValues(values.pinC_scaleY, currentYOffset)})`;
} else {
// out
objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_out, currentYOffset)}%, 0)`;
objs.messageC.style.opacity = calcValues(values.messageC_opacity_out, currentYOffset);
objs.pinC.style.transform = `scaleY(${calcValues(values.pinC_scaleY, currentYOffset)})`;
}
break;
case 3:
// console.log("3 play");
break;
}
}
function scrollLoop() {
//전체 스크롤(타임라인 합)의 누적을 막기 위해 0으로 설정
enterNewScene = false;
prevScrollHeight = 0;
for(let i=0; i <currentScene; i++){
prevScrollHeight = prevScrollHeight + sceneInfo[i].scrollHeight;
}
if (yOffset > prevScrollHeight + sceneInfo[currentScene].scrollHeight) {
enterNewScene = true;
currentScene++;
document.body.setAttribute('id', `show-scene-${currentScene}`);
}
if (yOffset < prevScrollHeight) {
enterNewScene = true;
if (currentScene === 0) return; //브라우저 바운스 효과로 인해 마이너스가 되는 것을 방지(모바일)
currentScene--;
document.body.setAttribute('id', `show-scene-${currentScene}`);
}
if (enterNewScene) return;
playAnimation();
}
window.addEventListener("scroll", () =>{
yOffset= window.pageYOffset;
scrollLoop();
});
window.addEventListener('load', setLayout);
window.addEventListener('resize', setLayout);
})();
답변 1
0
아이고, 제가 질문을 늦게 발견해서 답이 늦었네요~~^^;
function setLayout() 에서 콘텐츠 높이를 가져오는 속성 이름이 잘못 지정되어 제대로 동작을 안하고 있습니다.
위 부분에서 yOffsetHeight를 offsetHeight로 바꾸어주세요~
이미지 배경 문의
0
65
1
[크로스브라우징] safari에서 동영상 영역 미노출
0
106
1
항상 궁금했는데 크림슨 컬러 선택하셨을때 활용했던 사이트 좀 알려주세요~
0
109
2
vue강의는안하시나요?!
0
100
1
스크롤 속도에 따른 messageA_opacity_out
0
115
1
drawImage(objs.videoImages[sequence], 0, 0); error
0
88
1
선생님 캔버스 width 크기는 이미지 크기에맞게 해줘야하나요?
0
126
0
선생님 안녕하세요. 혹시 메인개발(?)분야가 뭔지 궁금합니다.
0
206
1
React에서 load 상태를 어떻게 감지할 수 있을까요?
0
678
1
[섹션7-3: 버그수정 2] tempYOffset 오류
0
194
1
스크롤할 때 캔버스로 하신 이유가 있으신가요? 그냥 성능 떄문에 캔버스로 하신건가요?
0
312
2
게속 오류떠서 글 작성해봐요....
0
505
2
Vanilla JavaScript로 SPA 만드는 자료 혹은 선택 기준을 추천해주실 수 있으신가요?
1
488
1
특정 타이밍 스크롤 애니메이션 적용하기 섹션 수강중입니다.
0
455
2
[#svg, #이미지프레임과 텍스트 싱크] 스크롤 값에 움직이는 svg path, 이미지프레임과 텍스트 싱크 맞추는 것, 2가지 질문이 있습니다.
0
451
2
페이지가 처음 로딩 되었을 때 애니메이션 처리가 되지 않는 느낌입니다
0
430
1
섹션2 번째, opacity=0 되지 않고 잔상이 남습니다.
0
533
1
원래 쿼리셀렉터에서는 띄워쓰기 하면안되나요?
0
593
2
라이브러리 질문
1
412
2
translateY대신 애플에서 사용한 것 처럼 matrix로 scale의 크기를 주려고 하는데
0
409
1
[스크롤 높이 세팅] scrollHeight값이 3990아닌 4645로만 나오는데 뭐가 문제일까요? ㅠㅠ
0
598
2
scrollLoop 함수 질문
0
476
2
도메인 웹호스팅시 이미지가 안 뜨는데 누가 좀 알려주세요ㅠㅜ
0
1235
2
load 이벤트시 첫 비디오 이미지가 뜨네요.
0
504
2





