@@ -21,15 +21,25 @@ const altfunc = (): string => {
21
21
22
22
<li class =" image-card animate__animated animate__bounceIn" >
23
23
<div >
24
- <Picture
25
- src ={ src }
26
- alt ={ altfunc ()}
27
- widths ={ [240 , 720 , 2500 ]}
28
- sizes ={ ` (max-width: 360px) 240px, (max-width: 1080px) 720px, 2500px ` }
29
- class ={ ` image skeleton ${className } ` }
30
- formats ={ [' avif' , ' webp' ]}
31
- quality ={ ' high' }
32
- />
24
+ <div class =" lazy-image" >
25
+ <Picture
26
+ src ={ src }
27
+ alt ={ altfunc ()}
28
+ width ={ 20 }
29
+ class ={ ` image skeleton placeholder ${className } ` }
30
+ formats ={ [' avif' , ' webp' ]}
31
+ quality ={ ' low' }
32
+ />
33
+ <Picture
34
+ src ={ src }
35
+ alt ={ altfunc ()}
36
+ widths ={ [240 , 720 , 2500 ]}
37
+ sizes ={ ` (max-width: 360px) 240px, (max-width: 1080px) 720px, 2500px ` }
38
+ class ={ ` image full-image ${className } ` }
39
+ formats ={ [' avif' , ' webp' ]}
40
+ quality ={ ' high' }
41
+ />
42
+ </div >
33
43
<br />
34
44
<h2 class =" title" >
35
45
{ title }
@@ -39,7 +49,24 @@ const altfunc = (): string => {
39
49
</li >
40
50
41
51
<script >
42
- import { mainAllComponents } from "@/ts/components";
52
+ import { queryAll } from '@/ts/global';
53
+ import { mainAllComponents } from '@/ts/components';
54
+
55
+ const images = queryAll(".lazy-image");
56
+
57
+ images.forEach((imageContainer: any) => {
58
+ function loaded() {
59
+ imageContainer.classList.add("loaded");
60
+ }
61
+ const img = imageContainer.querySelector("img.full-image") as HTMLImageElement;
62
+
63
+ if (img.complete) {
64
+ loaded();
65
+ } else {
66
+ img.addEventListener("load", loaded);
67
+ }
68
+ });
69
+
43
70
mainAllComponents('imghold');
44
71
</script >
45
72
@@ -86,7 +113,58 @@ const altfunc = (): string => {
86
113
margin-top: 0.5rem;
87
114
margin-bottom: 0;
88
115
}
116
+
117
+ .lazy-image {
118
+ position: relative;
119
+ overflow: hidden;
120
+ }
121
+
122
+ .lazy-image img.placeholder {
123
+ position: absolute;
124
+ inset: 0;
125
+ z-index: 1;
126
+ width: 100%;
127
+ height: 100%;
128
+ object-fit: cover;
129
+ filter: blur(10px);
130
+ transition: opacity 250ms ease-in-out;
131
+ }
132
+
133
+ .lazy-image img.full-image {
134
+ object-fit: cover;
135
+ opacity: 0;
136
+ transition: opacity 250ms ease-in-out;
137
+ }
138
+
139
+ .lazy-image.loaded img.placeholder {
140
+ opacity: 0;
141
+ }
142
+
143
+ .lazy-image.loaded img.full-image {
144
+ opacity: 1;
145
+ }
89
146
147
+ .lazy-image img.placeholder::before {
148
+ content: "";
149
+ position: absolute;
150
+ inset: 0;
151
+ opacity: 0;
152
+ animation: pulse 2.5s infinite;
153
+ background-color: white;
154
+ }
155
+
156
+ @keyframes pulse {
157
+ 0% {
158
+ opacity: 0;
159
+ }
160
+ 50% {
161
+ opacity: 0.1;
162
+ }
163
+ 100% {
164
+ opacity: 0;
165
+ }
166
+ }
167
+
90
168
/* .image-card:is(:hover, :focus-within) {
91
169
background-position: 0;
92
170
background-image: var(--accent-gradient);
0 commit comments