CSS&JS/👀Study and Copy

[JS] vanilla JS로 Masonry Layout 구현하기(2)

arancia_ 2023. 1. 25. 17:33

1탄에서 만든거는... 말단이 흉하게 나오는 문제가 있었음.
코드펜을 보니 grid 속성과 grid-row의 span 속성을 사용하여 더 이쁘게 정렬하는걸 참고하여 다시 만듦

 

See the Pen Masonry Layout-grid by Oh Ikmyeong (@dpffpself) on CodePen.

 

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Masonry Layout(final) css grid-row span 사용하기</title>
    <link rel="stylesheet" href="./style.css">
    <script src="./main.js" defer></script>
</head>
<body>
    <h1 style="text-align:center;font-size:10vmin; background:#000; color:#fff; padding:1em;">Masonry Layout</h1>
    <a href="https://codepen.io/ycw/details/LgJEor" target="_blank" style="display:block; text-align:center;"> grid-row span 속성 이용해보기</a>
    <div id="sample-wrap"></div>
    <footer style="text-align:center;font-size:10vmin;background:#ccc;">I'm Footer</footer>
</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
@charset "utf-8";
*{margin:0;padding:0;box-sizing:border-box;}
img{vertical-align:middle;}
 
/* wrap */
.msr-wrap{
    position:relative;
    width:calc(100% - 40px); max-width:1800px;
    margin:20px auto;
    gap:20px;
    display:grid;
    grid-template-columns:repeat(3,1fr);
    grid-auto-rows: 20px;
}
 
/* img */
.msr-wrap img{
    width:100%; height:100%; object-fit:cover; 
}
 
.msr-wrap img.show{
    animation: show-img .3s var(--delay) linear both;
}
 
@keyframes show-img {
    from{opacity:0; transform:translateY(25%);}
}
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
class MasonryLayoutBuilder{
    set_wrap(selector){
        if(selector){
            this.$parent = document.querySelector(selector);
        }else{
            this.$parent = document.createElement('SECTION');
            document.body.appendChild(this.$parent);
        }
        return this;
    }
 
    set_item(itemList){
        this.itemList = itemList;
        return this;
    }
 
    init(){
        new MasonryLayout(this);
    }
}//class-MasonryLayoutBuilder
 
class MasonryLayout{
    constructor(BUILDER){
        this.$parent = BUILDER?.$parent;
        this.itemList = BUILDER?.itemList;
        this.$wrap = null;
        this.init();
    }//constructor
 
    init(){
        this.make_wrap();
        this.$parent && this.$parent.appendChild(this.$wrap);
        this.fill_wrap();
        this.adjust_size();
        window.addEventListener('resize',this.adjust_size);
    }//init
 
    make_wrap(){
        this.$wrap = document.createElement('SECTION');
        this.$wrap.classList.add('msr-wrap');
    }//make_wrap
 
    adjust_size = () =>{
        this.set_img_row_span();
        this.set_wrap_col();
        const $$img = this.$wrap.querySelectorAll('img');
        $$img.forEach(this.img_animation);
    }//adjust_size
 
    fill_wrap(){
        const $frag = document.createDocumentFragment();
        
        this.itemList.forEach((src,idx) =>{
            const $img = new Image();
            $img.src= src;
            $img.title = idx;
            $img.style.setProperty('--delay', `${0.1 * idx}s`);
            $img.dataset.span = Math.round(($img.height / $img.width) * 10);
            this.img_animation($img);
            $frag.appendChild($img);
        });
        
        this.$wrap.appendChild($frag);
    }//fill_wrap
 
    set_img_row_span(){
        const $$img = this.$wrap.querySelectorAll('img');
        const wid = $$img[0].offsetWidth;
 
        $$img.forEach(($img) => {
            const span = $img.dataset.span;
            $img.style.gridRow = `auto / span ${span}`; 
        });
    }//set_img_row_span
 
    set_wrap_col(){
        const winWid = window.innerWidth;
        let COL;
        if(winWid > 1400){ 
            COL = 4;
        }else if(winWid > 1000){
            COL = 3;
        }else if(winWid > 700){
            COL = 2;
        }else{
            COL = 1;
        }
        this.$wrap.style.gridTemplateColumns = `repeat(${COL},1fr)`;
    }//set_wrap_col
 
    img_animation($img){
        $img.classList.add('show');
        $img.addEventListener('animationend',()=>{
            $img.classList.remove('show');
        });
    }//img_animation
}//class-MasonryLayout
/* ================= 실행 ================= */
const imgList = [
    "https://images.unsplash.com/photo-1674560109079-0b1cd708cc2d?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1171&q=80",
    "https://images.unsplash.com/photo-1621383569754-5a8744581af3?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=633&q=80",
    "https://images.unsplash.com/photo-1674421338840-de8c149e8c19?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1511&q=80",
    "https://images.unsplash.com/photo-1674126857818-81554b0140d8?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80",
    "https://images.unsplash.com/photo-1644152231863-e3ae720cc399?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=688&q=80",
    "https://images.unsplash.com/photo-1672661164570-d5e7e0890a69?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80",
    "https://images.unsplash.com/photo-1674503431654-885753f78ee4?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80",
    "https://images.unsplash.com/photo-1674318012388-141651b08a51?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1932&q=80",
    "https://images.unsplash.com/photo-1673993599169-32f4b7e8cbd4?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80",
    "https://images.unsplash.com/photo-1603379507360-d80df166fe4e?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=732&q=80",
    "https://images.unsplash.com/photo-1639182946622-7de9d7efa6b4?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80",
    "https://images.unsplash.com/photo-1597589827317-4c6d6e0a90bd?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1160&q=80",
    "https://plus.unsplash.com/premium_photo-1663954864809-4279479735bd?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80",
    "https://images.unsplash.com/photo-1673941733064-2445362593ce?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80",
    "https://plus.unsplash.com/premium_photo-1661603771539-faa0e3ed7ca6?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80",
];
 
new MasonryLayoutBuilder()
.set_wrap('#sample-wrap')
.set_item(imgList)
.init();
cs