# Scrolling
window 나 scrollable elements 의 스크롤링에 반응하는 이벤트
현재 스크롤을 보여주는 함수
window.addEventListener('scroll', function() {
document.getElementById('showScroll')
.innerHTML = window.pageYOffset + 'px';
});
1
2
3
4
2
3
4
스크롤의 활용
- 문서에서 사용자가 있는 위치에 따라 추가 컨트롤 또는 정보를 표시하거나 숨기는 기능
- 사용자가 페이지 아래끝으로 스크롤하면 더 많은 데이터를 로드하는 기능
# scrolling 방지 방법
- 스크롤 이벤트가 일어 난후
onscroll
리스너에event.preventDefault()
를 한다. - CSS
overflow
속성을 이용
# Endless page
# 스크롤의 두가지 중요한 특징
elastic 탄력적
- 일부 브라우저/디바이스 에서는, document 의 시작 또는 끝을 약간 넘어서 스크롤 할 수 있다.
- 빈 공간이 표시가 되고 document 가 자동으로 bounces back 된다.
imprecise 부정확성
- 페이지의 끝으로 스크롤 하였을 때, 실제 document 의 하단에서 0-50px 정도의 오차가 존재한다.
# Element.getBoundingClientRect()
DOMRect 요소의 크기 및 뷰포트를 기준으로 한 위치에 대한 정보를 제공 하는 객체를 반환합니다 .
- 브라우저 용어에서, 현재 창 (또는 문서를 전체 화면 모드로 보는 경우 화면)에 표시되는 현재보고있는 문서의 부분을 나타냅니다.
- 뷰포트 외부의 콘텐츠는 스크롤 할 때까지 화면에 표시되지 않습니다.
페이지가 아래로 스크롤 되는 것을 감지하는 방법
- window 의 상대 좌표를 사용함
document.documentElement.getBoundingClientRect()
- 전체 문서의 window 기준 좌표를 가져옴
전체 HTML document 의 높이가 2000px 일 때,
// 페이지의 top 에 있을 때
// window-relative top = 0
document.documentElement.getBoundingClientRect().top = 0
// window-relative bottom = 2000
// the document is long, so that is probably far beyond the window bottom
document.documentElement.getBoundingClientRect().bottom = 2000
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
500px 아래로 스크롤하면
// document top is above the window 500px
document.documentElement.getBoundingClientRect().top = -500
// document bottom is 500px closer
document.documentElement.getBoundingClientRect().bottom = 1500
1
2
3
4
5
2
3
4
5
창 높이
를 600px 로 가정하고 끝까지 스크롤 할 때
// document top is above the window 1400px
document.documentElement.getBoundingClientRect().top = -1400
// document bottom is below the window 600px
document.documentElement.getBoundingClientRect().bottom = 600
1
2
3
4
5
2
3
4
5
bottom 프로퍼티는 절대 0 이 되지 않는다.
- bottom 이 window 의 top 의 위치에 올 수 없기 때문
bottom 의 최소값이 되었을 때
- 값 →
창높이
- 더이상 위로 스크롤 할 수 없는 상태
창높이
- document.documentElement.clientHeight
- 가로스크롤과 테두리를 제외한 창의 높이
document bottom 이 100px 으로부터 멀어지지 않는 때를 알야야 한다.
- scroll 의 elastic 과 imprecise 특성 때문
- 높이가 600px 인 경우, 600-700px 사이 이다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<h1>Scroll me</h1>
<script>
function populate() {
while(true) {
let windowRelativeBottom = document.documentElement.getBoundingClientRect().bottom;
if (windowRelativeBottom > document.documentElement.clientHeight + 100) break;
document.body.insertAdjacentHTML("beforeend", `<p>Date: ${new Date()}</p>`);
}
}
window.addEventListener('scroll', populate);
populate(); // init document
</script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Up/down button
- 스크롤이 되고 있지 않을 때는 버튼이 나타나지 않는다.
- 스크롤이 window height 만큼 아래로 스크롤 되었을 때 버튼이 나타난다.
- 버튼이 있지만, 페이지를 2 번 상태 이전으로 스크롤 하면 버튼이 사라진다.
- 버튼을 누르면 페이지가 top 으로 스크롤 되고 벝튼이 사라진다.
<!DOCTYPE HTML>
<html>
<head>
<style>
body, html {
height: 100%; width: 100%; padding: 0; margin: 0;
}
#matrix {
width: 400px; margin: auto; overflow: auto; text-align: justify;
}
#arrowTop {
height: 9px; width: 14px; color: green;
position: fixed; top: 10px; left: 10px;
cursor: pointer;
}
#arrowTop::before {
content: '▲';
}
</style>
<meta charset="utf-8">
</head>
<body>
<div id="matrix">
<script>
for (let i = 0; i < 2000; i++) document.writeln(i)
</script>
</div>
<div id="arrowTop" hidden></div>
<script>
arrowTop.onclick = function() {
window.scrollTo(pageXOffset, 0);
// after scrollTo, there will be a "scroll" event, so the arrow will hide automatically
};
window.addEventListener('scroll', function() {
arrowTop.hidden = (pageYOffset < document.documentElement.clientHeight);
});
</script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# Load visible images
이미지를 즉시 로드하지 않고, 자리 표시자로 대체한다.
<img src="placeholder.svg" width="128" height="128" data-src="real.jpg">
1페이지가 사용자가 볼 수 있는 위치로 스크롤 하면, 변경되어 src 에 dara-src 이미지가 로드됨
예시 의 조건
- 페이지가 로드 될 때 화면에있는 이미지는 스크롤하기 전에 즉시로드되어야합니다.
- 일부 이미지는 data-src.
- 일단 이미지가 로드 되면 스크롤 인 / 아웃 할 때 더 이상 다시 로드 되지 않아야 합니다.
- 가능하다면 현재 위치보다 한 페이지 아래 / 뒤에있는 이미지를 "미리로드"하는 고급 솔루션을 만드십시오.
- 세로 스크롤 만 처리하고 가로 스크롤은 처리하지 않습니다.
요소(이미지)가 사용자에게 보이는 위치인지 검사한다.
function isVisible(elem) {
let coords = elem.getBoundingClientRect();
let windowHeight = document.documentElement.clientHeight;
// top elem edge is visible OR bottom elem edge is visible
let topVisible = coords.top > 0 && coords.top < windowHeight;
let bottomVisible = coords.bottom < windowHeight && coords.bottom > 0;
return topVisible || bottomVisible;
}
/**
A variant
function isVisible(elem) {
let coords = elem.getBoundingClientRect();
let windowHeight = document.documentElement.clientHeight;
let extendedTop = -windowHeight;
let extendedBottom = 2 * windowHeight;
// top visible || bottom visible
let topVisible = coords.top > extendedTop && coords.top < extendedBottom;
let bottomVisible = coords.bottom < extendedBottom && coords.bottom > extendedTop;
return topVisible || bottomVisible;
}
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function showVisible() {
for (let img of document.querySelectorAll('img')) {
let realSrc = img.dataset.src;
if (!realSrc) continue;
if (isVisible(img)) {
// disable caching
// this line should be removed in production code
realSrc += '?nocache=' + Math.random();
img.src = realSrc;
img.dataset.src = '';
}
}
}
window.addEventListener('scroll', showVisible);
showVisible();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20