css로만 만들 수 있는 marquee slider. 마우스 hover시 잠시 애니메이션이 멈춘다(animation-play-state:paused)
https://www.youtube.com/watch?v=mF9yOwlunWk
다만 매번 아이템 추가하고 지우고 변경하고 할 때 총 갯수 지정 및 이런게 귀찮으니 JS로 생성 가능하게 만들어봄
See the Pen Untitled by Oh Ikmyeong (@dpffpself) on CodePen.
HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Play and Pause in Infinite Slider with CSS Only</title>
<link rel="stylesheet" href="./style.css">
<script src="./main.js" type="module"></script>
</head>
<body>
<a href="https://www.youtube.com/watch?v=mF9yOwlunWk">Play and Pause in Infinite Slider with CSS Only</a>
</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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
@charset "utf-8";
*{margin:0;padding:0;box-sizing:border-box;}
li{list-style-type:none;}
a{
display:block;
padding:20px 10px;
background:#000;
text-align:center;color:yellow;
}
body{
background:#dedede;
}
.slider-wrap{
position:relative; overflow:hidden;
width:100%; max-width:1200px;
margin:20px auto;
border:2px solid black;
border-radius:10px;
}
.slider{
--_time:15s;
--_gap:20px;
--_wid-full:calc(var(--_wid-item) * var(--_count) - var(--_wid-item));
--_wid-gap:calc(var(--_gap) * (var(--_count) - 1));
display:flex; flex-flow:row nowrap;
justify-content:flex-start; align-items:center;
gap:var(--_gap);
position:relative;
width:100%;
height:var(--_hei-item);
background:#fff;
}
.slider-item{
--_delay-basic:calc((var(--_time) / var(--_count)) * var(--_i));
flex:none;
display:flex;flex-flow:row wrap;
justify-content:center; align-items:center;
position:relative;
width:var(--_wid-item);
height:var(--_hei-item);
background:rgba(calc(7 * var(--_i)),calc(15 * var(--_i)),calc(5 * var(--_i)),.8);
border:1px dashed rgb(32, 13, 13);
font-size:30px;font-weight:bold;
text-shadow:0px 0px 5px #fff, 0px 0px 4px #fff, 0px 0px 3px #fff, 0px 0px 2px #fff, 0px 0px 1px #fff, 0px 0px 5px #fff;
transition:all .2s;
}
.slider.on .slider-item{
position:absolute;
left:100%;
animation: slider-move var(--_time) linear infinite both;
animation-delay:calc(var(--_delay-basic) - (var(--_time) - 1s));
}
.slider-move-reverse .slider-item{
animation-direction: reverse;
}
@keyframes slider-move {
from{left:100%;}
to{left:calc(-1 * var(--_wid-item));}
}
.slider:hover .slider-item{
animation-play-state:paused;
filter:saturate(0) brightness(0.3);
opacity:.5;
}
.slider:hover .slider-item:hover{
filter:saturate(1) brightness(1);
opacity:1;
}
|
cs |
main.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
|
import { MarqueeSliderBuilder } from "./MarqueeSlider.js";
const $slider1 = new MarqueeSliderBuilder()
.set_count(10)
.set_item_width("150px")
.set_item_height("50px")
.set_item_gap("20px")
.is_move_reverse(false)
.set_time("10s")
.init();
const $slider2 = new MarqueeSliderBuilder()
.set_count(5)
.set_item_width("300px")
.set_item_height("350px")
.set_item_gap("5px")
.is_move_reverse(true)
.set_time("10s")
.init();
const $slider3 = new MarqueeSliderBuilder()
.set_count(20)
.set_item_width("100px")
.set_item_height("100px")
.set_item_gap("30px")
.is_move_reverse(true)
.set_time("10s")
.init();
document.body.appendChild($slider1);
document.body.appendChild($slider2);
document.body.appendChild($slider3);
|
cs |
MarqueeSlider.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
|
import { MarqueeSliderView } from "./MarqueeSliderView.js";
/**
* 마퀴 슬라이더
*/
class MarqueeSlider {
constructor(setting = {}) {
this.itemCount = setting?.itemCount;
this.itemWidth = setting?.itemWidth;
this.itemHeight = setting?.itemHeight;
this.isReverse = setting?.isReverse;
this.itemGap = setting?.itemGap ?? "0px";
this.time = setting?.time ?? "10s";
}//constructor
/**
* 마퀴슬라이더 만들어 배포
*/
init(){
/* wrap */
const $wrap = MarqueeSliderView.make_wrap();
/* slider */
const $slider = MarqueeSliderView.make_slider({
itemCount : this.itemCount,
itemWidth : this.itemWidth,
itemHeight : this.itemHeight,
itemGap : this.itemGap,
isReverse : this.isReverse,
time : this.time,
});
$wrap.appendChild($slider);
/* fill items */
const $$item = MarqueeSliderView.make_items(this.itemCount);
$slider.appendChild($$item);
/* 움직이기 시작 */
$slider.classList.add("on");
/* 최종 */
return $wrap;
}//init
}//class-MarqueeSlider
/**
* 마퀴 슬라이더 생성기
*/
export class MarqueeSliderBuilder {
constructor() {
this.setting = {
itemCount: 0,
itemWidth: null,
itemHeight: null,
isReverse: false,
time: "10s",
itemGap: "0px",
};
}
set_count(itemCount = 0) {
this.setting.itemCount = itemCount;
return this;
}//set_count
set_item_width(itemWidth = 0) {
this.setting.itemWidth = itemWidth;
return this;
}//set_item_width
set_item_height(itemHeight = 0) {
this.setting.itemHeight = itemHeight;
return this;
}//set_item_height
is_move_reverse(moveReverse = true) {
this.setting.isReverse = moveReverse;
return this;
}//is_move_reverse
set_time(time = "10s") {
this.setting.time = time;
return this;
}//set_time
set_item_gap(itemGap = "0px") {
this.setting.itemGap = itemGap;
return this;
}
init() {
return new MarqueeSlider(this.setting).init();
}//init
}//class-MarqueeSliderBuilder
|
cs |
MarqueeSliderView.js
DOM 생성관련만 모아둔 클래스
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
|
export class MarqueeSliderView {
/**
*
* @returns
*/
static make_wrap() {
const $wrap = document.createElement("DIV");
$wrap.classList.add("slider-wrap");
return $wrap;
}//make_wrap
/**
*
* @returns
*/
static make_slider(INFO = {}) {
const { itemCount, itemWidth, itemHeight, itemGap, isReverse, time } = INFO;
const $slider = document.createElement("UL");
$slider.classList.add("slider");
$slider.style.setProperty("--_time", time);
$slider.style.setProperty("--_gap", itemGap);
$slider.style.setProperty("--_count", itemCount);
$slider.style.setProperty("--_wid-item", itemWidth);
$slider.style.setProperty("--_hei-item", itemHeight);
const widFull = (itemCount - 1) * parseInt(itemWidth);
const widGap = (itemCount - 1) * parseInt(itemGap);
$slider.style.width = `${widFull + widGap}px`
if(isReverse){$slider.classList.add("slider-move-reverse");}
return $slider;
}//make_slider
/**
*
* @param {Number} itemCount
*/
static make_items(itemCount) {
const $frag = document.createDocumentFragment();
for (let i = 0; i < itemCount; i++) {
const $item = document.createElement("LI");
$item.classList.add("slider-item");
$item.textContent = i + 1;
$item.style.setProperty("--_i", i);
$frag.appendChild($item);
}//for
return $frag;
}//make_items
}//class-MarqueeSliderView
|
cs |
'CSS&JS > 👀Study and Copy' 카테고리의 다른 글
[CSS]inverted border-radius 안쪽으로 파인 효과 (0) | 2024.09.30 |
---|---|
[JS]Trello 스타일의 drag & drop 구현하기 (1) | 2024.09.27 |
[CSS/JS]Lun Dev 쇼핑몰 이미지 줌 효과 (1) | 2024.09.13 |
[JS]팝업창에 함수를 전달하고, 팝업창의 변수를 부모창에 전달하는 방법. (0) | 2024.04.16 |
[OnlineTutorials]링크 아이콘 자석효과 (0) | 2024.03.06 |