See the Pen marquee by Oh Ikmyeong (@dpffpself) on CodePen.
대체 몇번쨰 marquee인지.. 이번엔 requestAnimationFrame으로 구현해보았습니다.
참고 사이트는 나의 경기도 웹진

requestAnimationFrame으로 했을시 장점 및 유의할점
- 반응형 대응이 쉽다
- 마퀴 너비1/2이 분기점이라 flex를 먹이되 gap을 주는것보단 개체 오른쪽으로 padding을 주는게 낫다
- 마퀴의 width는 max-content가 되도록
- 속도 조절이 가능(CURR-- 부분)하긴 하나 경우에 따라 이상하게 튈수도 있다..! 특히 주사율이 높은 디스플레이에선 엄청나게 빨리 뛸 수 있음.
- 그래서 codepen에 올린것과 달리 하단에선 보간한걸로 ...
HTML
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>marquee</title>
<link rel="stylesheet" href="./style.css">
<script src="./main.js" type="module"></script>
</head>
<body>
<section class="mq-wrap">
<div class="mq"></div>
</section>
</body>
</html>
|
cs |
CSS
|
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
46
47
48
49
50
51
52
53
54
55
56
|
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
min-height: 100vh;
}
body {
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
}
.mq-wrap {
position: relative;
overflow: hidden;
width: 100%;
max-width: 1200px;
border: 1px solid black;
}
.mq {
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: flex-start;
position: relative;
width: max-content;
will-change: transform;
/* transition: transform 10s linear; */
}
.mq.noTransition {
transition: none;
}
.mq-link {
flex: none;
display: inline-block;
position: relative;
padding-right: 1.5em;
font-size: clamp(18px, 4.2vw, 40px);
font-weight: bold;
color: #000;
white-space: nowrap;
text-decoration: none;
}
.mq-link:hover {
color: red;
}
|
cs |
JS
|
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
const $mq = document.querySelector(".mq");
let CURR = 0;
let MIN = null;
let MOVING = false;
const SPEED = 100; //초당 100px 이동
let lastTime = 0;
init_marquee([
"00 Hello World",
"01 requestAnimationFrame",
"02 marquee",
"03 반응형 대응도 자동으로 되겠군요",
]);
$mq.addEventListener("mouseenter", () => {
MOVING = false;
});
$mq.addEventListener("mouseleave", () => {
MOVING = true;
requestAnimationFrame(move_marquee2);
});
/* ======================================= */
/**
*
* @param {*} arr
*/
function init_marquee(arr = []) {
make_marquee({ arr, isHidden: false });
make_marquee({ arr, isHidden: true });
MOVING = true;
requestAnimationFrame(move_marquee2);
//옛날방식
// requestAnimationFrame(() => {
// move_marquee();
// });
}//init_marquee
/**
*
* @param {*} param0
*/
function make_marquee({ arr = [], isHidden = false }) {
arr.forEach(item => {
const $a = document.createElement("A");
$a.classList.add(`mq-link`);
$a.target = "_blank";
$a.href = "#";
$a.textContent = `#${item}`;
if (isHidden) {
$a.classList.add(`cloned`);
$a.setAttribute("aria-hidden", "true");
$a.setAttribute("tabindex", -1);
}
$mq.appendChild($a);
});
}//make_marquee
/**
*
* @returns
*/
function move_marquee2(timestamp) {
if (!MOVING) {
lastTime = 0;
return;
}
if (!lastTime) {
lastTime = timestamp;
}
/* 프레임 간 시간 간격 계산(초단위) */
const deltaTime = (timestamp - lastTime) / 1000;
lastTime = timestamp;
/* 최소값 정해주고 */
if (!MIN || MIN !== ($mq.offsetWidth / 2) * -1) {
MIN = ($mq.offsetWidth / 2) * -1;
}
/* 시간 간격에 따라 이동거리 계산 */
CURR -= SPEED * deltaTime;
/* 최소값보다 적으면 처음으로 돌아가고 */
if (CURR < MIN) { CURR = 0; }
/* 움직이고 */
$mq.style.transform = `translate3d(${CURR}px,0,0)`;
/* 반복 */
requestAnimationFrame(move_marquee2);
}//move_marquee2
/**
* 옛날방식...실시간 윈도우창 너비 변경시 대응 안됨
* @deprecated
*/
function move_marquee() {
const wid = $mq.offsetWidth;
const ani = $mq.animate([
{
transform: `translate3d(0,0,0)`
},
{
transform: `translate3d(-${wid / 2}px,0,0)`
}
], {
duration: 10000,
fill: "forwards",
easing: "linear"
});
ani.addEventListener("finish", () => {
const ani2 = $mq.animate([
{
transform: `translate3d(0,0,0)`
}
], {
duration: 1,
fill: "forwards",
easing: "steps(1,end)"
});
ani2.addEventListener("finish", () => {
move_marquee();
});
}, { once: true });
}
|
cs |
'CSS&JS > 👀Study from Copying' 카테고리의 다른 글
| [JS]관람차 캐러셀 슬라이드 ferris wheel carousel (0) | 2026.04.23 |
|---|---|
| [CSS]Stacking Cards (position:sticky) (0) | 2026.03.16 |
| [JS]canvas로 오디오 파형 그리기 (0) | 2026.03.12 |
| [JS] canvas로 오디오 스펙트럼 그리기 (0) | 2026.03.12 |
| [CSS] linear-gradient와 mask를 이용한 점박이 무늬(패턴) 배경 (0) | 2025.09.18 |