๐ ๋ค์ด๊ฐ๋ฉฐ
์ด๋ฒ ๊ธ์์๋ ํ๋ก ํธ์๋์์ ์ฑ๋ฅ ์ต์ ํ๋ฅผ ํ๊ธฐ ์ํด์๋ ์ด๋ค ๋ฐฉ๋ฒ์ด ์๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
์ฝ๋ ์์๋ React ์ฝ๋ ๊ธฐ๋ฐ์ผ๋ก ๋ณด์ฌ๋๋ฆฌ์ง๋ง, VanilaJS, ๋ค๋ฅธ ํ๋ ์์ํฌ์์๋ ํ์ฉํ ์ ์๋ ๊ธฐ๋ฒ๋ค์
๋๋ค.
ํด๋น ๊ธ์์๋ ๊ฐ ๋ฐฉ๋ฒ์ ๋ํด์ ๋์์๋ฆฌ์ ๊ฐ์ ์ด๋ก ์ ์ธ ๋ถ๋ถ์ ๋ํด์๋ ๊น๊ฒ ์ค๋ช
ํ์ง ์์ต๋๋ค!
ํฌ๊ฒ ์ด๋ค ๋ฐฉ๋ฒ๋ค์ด ์๋์ง, ์ด๋ค ๊ฐ๋
์ธ์ง, ์ด๋ป๊ฒ ํ๋ ๊ฑด์ง, ๊ทธ๋์ ์ด๋ค ์ด์ ์ด ์๋์ง ์ด ์ด 4๊ฐ์ง์ ์ง์คํ์ฌ ์ค๋ช
ํฉ๋๋ค.
๊ทธ๋์ ์ฒ์ ์๊ฒ๋ ๋ฐฉ๋ฒ์ ๋ํด์๋ "์ด๋ฐ ๊ฒ๋ ์๊ตฌ๋! ๋ฐ๋ก ํ๋ฒ ์ ์ฉํด๋ณผ๊น?"๋ผ๋ ์๊ฐ์ด ๋ค์์ผ๋ฉด ์ข๊ฒ ์ด์.๐คฃ
์ต์ ํ๋ฅผ ์งํํ๊ธฐ ์ ์๋ ๋ธ๋ผ์ฐ์ ๊ฐ๋ฐ์ ๋๊ตฌ > ์ฑ๋ฅ ํญ ๋๋ ๋คํธ์ํฌ ํญ, Lighthouse, React-Dev-Tools์ ๊ฐ์ ์ฑ๋ฅ ์ธก์ ์ ํตํด์ ์ ๊ณผ ํ ๋น๊ต๋ฅผ ํตํด์ ์ผ๋ง๋ ๊ฐ์ ์ด ๋์๋์ง ์์น๋ก ํ์ธํด๋ณด์๊ธธ ์ ๊ทน ์ถ์ฒ๋๋ฆฝ๋๋ค.
N๊ฐ์ง ์ต์ ํ ๋ฐฉ๋ฒ๋ค
๐ผ๏ธ ์ด๋ฏธ์ง ์ง์ฐ ๋ก๋ฉ(Lazy Loading)
์น ํ์ด์ง์์ ์ด๋ฏธ์ง๋ ๋ฌด๊ฑฐ์ด ๋ฆฌ์์ค ์ค ํ๋์
๋๋ค.
๋ชจ๋ ์ด๋ฏธ์ง๋ฅผ ํ ๋ฒ์ ๋ก๋ํ๋ฉด ์ด๊ธฐ ๋ก๋ฉ ์๊ฐ์ด ๊ธธ์ด์ง๊ณ ๋ถํ์ํ ๋ฐ์ดํฐ ์ฌ์ฉ์ด ๋ฐ์ํ๊ฒ ๋ฉ๋๋ค.
์ด๋ฏธ์ง ์ง์ฐ ๋ก๋ฉ์ ์นํ์ด์ง์ ๋ชจ๋ ์ด๋ฏธ์ง๋ฅผ ์ด๊ธฐ ๋ก๋ ์์ ์ ํ๊บผ๋ฒ์ ๋ค์ด๋ก๋ ํ์ง ์๊ณ , ์ฌ์ฉ์์ viewport(ํ๋ฉด์ ๋ณด์ด๋ ์์ญ)์ ์ด๋ฏธ์ง๊ฐ ๋ค์ด์ฌ ๋ ๋๋ ๋ค์ด์ค๊ธฐ ์ง์ ํด๋น ์ด๋ฏธ์ง๋ง ์ ํ์ ์ผ๋ก ๋ถ๋ฌ์ค๋ ๊ธฐ์ ์
๋๋ค.
Intersection Observer API๋ scroll event๋ฅผ ํ์ฉํ์ฌ ์ด๋ฏธ์ง์ ๊ฐ์์ฑ์ ๊ฐ์งํ์ฌ ์ด๋ฏธ์ง ๋ฆฌ์์ค๋ฅผ ์์ฒญํ๋ ๋ฐฉ๋ฒ, ๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ ์ง์ ์์ฑ์ธ loading="lazy"๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ๋ค์ด ์กด์ฌํฉ๋๋ค.
์์๋ฅผ ์์๋ณผ๊ฒ์.
์ด๋ฏธ์ง ์ฌ๋ผ์ด๋๊ฐ ํ์ํ ์ํฉ์ด๋ผ๊ณ ๊ฐ์ ํด๋ด ์๋ค.
์ ์ฉ ์
// ์ง์ฐ ๋ก๋ฉ ์ ์ฉ โ
{images.map((imageUrl, index) => (
<SwiperSlide key={index}>
<img
src={imageUrl}
alt={`${index} + ์ด๋ฏธ์ง}`}
/>
</SwiperSlide>
))}
์ด๋ฏธ์ง ์ง์ฐ๋ก๋ฉ์ ์ ์ฉํ์ง ์์ ๊ฒฝ์ฐ์๋ ๋ณด์ด์ง ์๋ ์์ญ์ ์ด๋ฏธ์ง๋ ๋ชจ๋ ๋ถ๋ฌ์ค๊ณ ์์ต๋๋ค.
์ ์ฉ ํ
// ์ง์ฐ ๋ก๋ฉ ์ ์ฉ โ
{images.map((imageUrl, index) => (
<SwiperSlide key={index}>
<img
src={imageUrl}
alt={`${index} + ์ด๋ฏธ์ง}`}
loading="lazy"
/>
</SwiperSlide>
))}
์ค์ ๋ก ํ๋ฉด ์์ญ์ ๋ณด์ผ ๋ ์ด๋ฏธ์ง ๋ฆฌ์์ค๋ฅผ ์์ฒญํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค!
ํ์ง๋ง ๋์น๊ฐ ๋น ๋ฅด์ ๋ถ๋ค์ ๋ณด์
จ๊ฒ ์ง๋ง, loading="lazy"๋ง ์ฌ์ฉํ ๊ฒฝ์ฐ ์ด๋ฏธ์ง๊ฐ ๋ก๋๋๊ธฐ ์ ๊น์ง ๋น ๊ณต๊ฐ์ด๋ ํฐ์ ์์ญ๋ง ๋ณด์ด๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค. ํนํ ๋คํธ์ํฌ๊ฐ ๋๋ฆฐ ํ๊ฒฝ์์๋ ์ด๋ฐ ๋น ๊ณต๊ฐ์ด ๋ ์ค๋ ๋
ธ์ถ๋์ด ์ฌ์ฉ์ ๊ฒฝํ์ ์ ํ์ํฌ ์ ์์ด์.
๋ธ๋ผ์ฐ์ ์์ ์์ฒด์ ์ผ๋ก ์ง์ํ๋ loading="lazy"๋ ์ฝ๋ ํ ์ค๋ก ์ ๋ง ํธ๋ฆฌํ์ง๋ง ์๊ฐ์ ํผ๋๋ฐฑ ์ธก๋ฉด์์๋ ๊ธฐ๋ฅ์ด ์ ํ์ ์
๋๋ค.
UX๋ฅผ ๊ณ ๋ คํ์๋ ๊ฐ๋ฐ์ ๋ถ๋ค์ด๋ผ๋ฉด! fallbackUI๋ฅผ ๊ณ ๋ คํด ๋ณด์ธ์.
๊ทธ ๋ฐฉ๋ฒ์ผ๋ก ๊ฐ๋จํ ๊ฒฝ์ฐ์๋ CSS์ placeholder ์ด๋ฏธ์ง๋ฅผ ์ ์ ํ๊ฒ ์กฐํฉํด์ ๋ณด์ฌ์ฃผ๊ฑฐ๋, Intersection ObserverAPI๋ฅผ ์ง์ ํ์ฉํ์ฌ ์ปค์คํ
๋ก๋ฉ ์ํ๋ฅผ ์ฒ๋ฆฌํ๊ฑฐ๋, ์ด๋ฏธ์ง ์ง์ฐ ๋ก๋ฉ ๊ด๋ จ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ณด๋ค ์ฝ๊ฒ ์ฒ๋ฆฌ๋ฅผ ์๋ํด๋ณผ ์ ์์ด์.
Trade-off
- ๋ธ๋ผ์ฐ์ ๋ค์ดํฐ๋ธ lazy ํ์ฉ โก๏ธ ์ฝ๋ ํ ์ค๋ก ๊ตฌํ ๊ฐ๋ฅ, ๋ธ๋ผ์ฐ์ ๋ด์ฅ ์ต์ ํ๋ก ์ฑ๋ฅ ์ฐ์, fallbackUI๋ ๋ณ๋ ๊ตฌํ ํ์
- Intersection Observer API ํ์ฉ โก๏ธ ์ธ๋ฐํ ์ ์ด ๊ฐ๋ฅ, ๋ค์ํ ๋ก๋ฉ ์ ๋ต ๊ตฌํ ๊ฐ๋ฅ, ์ ์ ํ ์ฑ๋ฅ, ์ฝ๋์ ์ฆ๊ฐ
- ๊ด๋ จ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ โก๏ธ ๋ก๋ฉ ์ง์ฐ๊ณผ fallbackUI ๊ธฐ๋ฅ ํตํฉ ์ ๊ณต, ๋น ๋ฅธ ๊ฐ๋ฐ ๊ฐ๋ฅ, ์์กด์ฑ ์ถ๊ฐ
๊ฐ์ ์ํฉ์ ๋ง๋ ๋ฐฉ๋ฒ์ ์ ํํ์๋ฉด ๋ ๊ฒ ๊ฐ์ต๋๋ค.
๐๏ธ ์ด๋ฏธ์ง ์์ถ ๋ฐ ์ฌ์ด์ฆ ์กฐ์
์ด๋ฏธ์ง ์์ถ ๋ฐ ์ฌ์ด์ฆ ์กฐ์ ์ ์น์ฌ์ดํธ์ ์ด๋ฏธ์ง ํ์ผ ํฌ๊ธฐ๋ฅผ ์ต์ ํํ๋ ์ข
ํฉ์ ์ธ ์ ๊ทผ ๋ฐฉ์์
๋๋ค.
์ ์ ํ ์ด๋ฏธ์ง ํ์ ์ ํ(JPEG, PNG, WebP, AVIF ๋ฑ), ํ์ง ์กฐ์ ์ ํตํ ์์ค ์์ถ ๋ฑ์ ํฌํจํ์ฃ .
ํ๋ฉด ํฌ๊ธฐ์ ํด์๋์ ๋ง๊ฒ ์ต์ ํ๋ ์ด๋ฏธ์ง๋ ์ ๊ณตํ ์ ์๊ณ , ์ฐจ์ธ๋ ์ด๋ฏธ์ง ํฌ๋งท(WebP, AVFI)์ ์ง์ํ๋ ๋ธ๋ผ์ฐ์ ์๋ ๋ ํจ์จ์ ์ธ ์์ถ๋ฅ ์ ์ ๊ณตํ๋ ํ์์ผ๋ก ์ฐ์ ์์๋ฅผ ์ ํ ์๋ ์์ด์.
์ด๋ฏธ์ง CDN์ด๋ ์๋ํ๋ ์ด๋ฏธ์ง ์ต์ ํ ๋๊ตฌ๋ฅผ ํ์ฉํ์ฌ ์๋ฒ ์ธก์์ ๋์ ์ผ๋ก ์ด๋ฏธ์ง๋ฅผ ์ต์ ํํ๋ ๋ฐฉ๋ฒ๋ ์กด์ฌํฉ๋๋ค.
์์ถ ๋ฐ ์ฌ์ด์ฆ ์กฐ์ ์
ํด๋น ์ด๋ฏธ์ง๋ 11,375 × 8,992 ์ฌ์ด์ฆ ๋ฐ ์ฝ 1MB ํฌ๊ธฐ๋ฅผ ๊ฐ์ง JPG ์ด๋ฏธ์ง์
๋๋ค.
์๋น์ค์์ 400x400 ์ฌ์ด์ฆ๋ฅผ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด์ ์ง์ width์ height๋ฅผ ์ค์ ํด ์คฌ๋ค๊ณ ๊ฐ์ ํด ๋ณผ๊ฒ์.
<img src={largeImage} alt="image" width={400} height={400} />
๋คํธ์ํฌ ํญ์ ํ์ธํด๋ณด๋ฉด ์ค์ ๋ก ์ฝ 1MB ์ ๋์ ์ด๋ฏธ์ง ๋ฆฌ์์ค๋ฅผ ์์ฒญํ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์์ถ ๋ฐ ์ฌ์ด์ฆ ์กฐ์ ํ
์ต๋ ์ฝ 98%๊น์ง ํฌ๊ธฐ๊ฐ ์ค์ด๋ ๊ฒ์ด ๋ณด์ด์๋์?
๋คํธ์ํฌํญ ๊ธฐ์ค ์ด๋ฆ ์์๋๋ก ์๋ณธ JPG > ์์ถ ๋ฐ ํฌ๊ธฐ ์กฐ์ JPG > ์์ถ ๋ฐ ํฌ๊ธฐ ์กฐ์ webp > ์์ถ ๋ฐ ํฌ๊ธฐ ์กฐ์ avif ์์์
๋๋ค.
์ค์ ํ์ํ ํฌ๊ธฐ(400x400)๋งํผ ํฌ๊ธฐ๋ฅผ ์กฐ์ ํ๊ณ ์์ถ์ ์งํํ์ ๋ฟ์ด์์.
์ฃผ์ํ ์ ์ ๋ธ๋ผ์ฐ์ ์ง์์ ๋ฐ๋ผ์ ์ต์ ํฌ๋งท(AVIF, WebP)์ ์ฐ์ ์ ์ผ๋ก ์ ๊ณตํ๊ณ ์ง์ํ์ง ์๋ ๊ฒฝ์ฐ ์ด ์ธ ํฌ๋งท์ ํด๋ฐฑ ํ๋ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํ๋ ๊ฒ์ ์ถ์ฒํฉ๋๋ค.
<picture>
{/* AVIF ์ง์ ๋ธ๋ผ์ฐ์ ์ฉ */}
<source srcSet={largeImageAvif} type="image/avif" />
{/* WebP ์ง์ ๋ธ๋ผ์ฐ์ ์ฉ */}
<source srcSet={largeImageWebp} type="image/webp" />
{/* ๋ ๋ค ์ง์ํ์ง ์๋ ๋ธ๋ผ์ฐ์ ์ฉ ํด๋ฐฑ */}
<img src={largeImage2} alt="์ต์ ํ ์ด๋ฏธ์ง" width={400} height={400} />
</picture>
์ด๋ฐ ์์ผ๋ก ๋ง์ด์ฃ .
๊ทธ๋ผ ๋ง์ฝ AVIF๋ฅผ ์ง์ํ๋ ๋ธ๋ผ์ฐ์ ์์๋ AVIF ์ด๋ฏธ์ง๋ง ์์ฒญํ์ฌ ๋ธ๋ผ์ฐ์ ์ ๋ณด์ด๊ฒ ๋ฉ๋๋ค.
์์ถ ๋ฐ ์ฌ์ด์ฆ ์กฐ์ ์ ์งํํจ์ผ๋ก์จ ๋์ญํญ ์ฌ์ฉ๋ ๊ฐ์ ๋ฐ ํ์ด์ง ๋ก๋ ์๊ฐ์ ์ค์ผ ์ ์๋ ์ด์ ์ ๊ธฐ๋ํ ์ ์์ต๋๋ค.
์ด๋ฏธ์ง ํฌ๊ธฐ ์กฐ์ ๋ฐ ์์ถ ์ฌ์ดํธ๋ ์ฌ๋ฌ ์๋น์ค๊ฐ ์กด์ฌํด์.
์ ๋ ์๋ ์๋น์ค๋ฅผ ์ฃผ๋ก ์ฌ์ฉํ๊ณ ์์ด์.
https://squoosh.app/
Squoosh
Simple Open your image, inspect the differences, then save instantly. Feeling adventurous? Adjust the settings for even smaller files.
squoosh.app
๐ฌ ๋์์ ํ์ผ ์ต์ ํ
๋์์ ๋ํ ํ์ผ ํฌ๊ธฐ๋ฅผ ์์ถํ๊ณ ํจ์จ์ ์ธ ์ฝ๋ฑ(WebM)์ ์ฌ์ฉํด์ ๋ธ๋ผ์ฐ์ ํธํ์ฑ์ ๊ณ ๋ คํ ์์ค ์ฐ์ ์์๋ฅผ ์ง์ ํ๋ ๋ฐฉ๋ฒ์ผ๋ก ์ด๋ฏธ์ง ์ต์ ํ ๋ฐฉ์๊ณผ ๋์ผํ๊ฒ ํ์ฉ์ด ๊ฐ๋ฅํฉ๋๋ค.
์ค์ ๋ก ํ์ํ ๊ธธ์ด๋ง ์ฌ์ฉํ๊ณ , ํจ์จ์ ์ธ ์ฝ๋ฑ์ผ๋ก ๋ณํ, ์์ถ์ ์งํํ๋ ๋ฐฉ์์ด์ฃ .
์ฐจ์ด ์์ ์ด๋ฏธ์ง ๋ฐ ์ฝ๋๋ ์ ์ด๋ฏธ์ง ์์ถ ๋ฐ ์ฌ์ด์ฆ ์กฐ์ ์น์
๊ณผ ๋์ผํ๊ธฐ ๋๋ฌธ์ ์์๋ฅผ ์ฒจ๋ถํ์ง๋ ์๊ฒ ์ต๋๋ค.
๊ฐ๋จํ๊ฒ๋ง ๋ณด์ฌ๋๋ฆฌ์๋ฉด,
<video controls preload="none" poster="thumbnail.jpg" width="640" height="360">
<!-- WebM์ด ์ง์๋๋ฉด ๋จผ์ ์ฌ์ฉ (๋ ํจ์จ์ ์ธ ์ฝ๋ฑ) -->
<source src="video.webm" type="video/webm">
<!-- ๋์ฒด ํฌ๋งท์ผ๋ก MP4 ์ ๊ณต -->
<source src="video.mp4" type="video/mp4">
</video>
๋์์๋ source ํ๊ทธ๋ฅผ ์ง์ ํ์ฌ ์ฐ์ ์์๋ฅผ ์ง์ ํ ์ ์์ด์.
๋์์ ์์ถ ์๋น์ค๋ media.io ์๋น์ค๋ฅผ ์์ฃผ ์ด์ฉํ๊ณ ์์ต๋๋ค.
์์ถ
https://www.media.io/apps/compressor/
Online Video, Audio and Image Compressor - Reduce Large Files Size Online
www.media.io
์ฝ๋ฑ ๋ณํ
https://www.media.io/apps/converter/
Online Video, Audio, and Image Converter with Batch Processing | Media.io Converter
www.media.io
๐ค ํฐํธ ์ต์ ํ
ํฐํธ ์ต์ ํ๋ ์น ํฐํธ ๋ฆฌ์์ค ๋ก๋ฉ ๋ฐ ๋ ๋๋ง ๋ฐฉ์์ ๊ฐ์ ํ์ฌ ์น ์ฑ๋ฅ๊ณผ UX๋ฅผ ํฅ์์ํค๋ ๊ธฐ์ ์
๋๋ค.
์น ํฐํธ๋ ๋์์ธ์ ์ค์ํ ์์์ง๋ง, ์ต์ ํํ์ง ์์ผ๋ฉด ๋ก๋ฉ ์๊ฐ ์ฆ๊ฐ, ํ
์คํธ ๊น๋นก์, Reflow ๋ฑ์ ๋ฌธ์ ๋ฅผ ์ผ์ผํฌ ์ ์์ต๋๋ค.
FOIT(Flash of Invisible Text)
ํฐํธ๋ฅผ ๋ค์ด๋ก๋๋ ๋๊น์ง ํ ์คํธ๊ฐ ๋ ธ์ถ๋์ง ์๋ ํ์
FOUT(Flash of Unstyled Text)
ํฐํธ๊ฐ ๋ค์ด๋ก๋๋๊ธฐ ์ ๊ธฐ๋ณธ ํฐํธ๋ฅผ ๋ ธ์ถํ๊ณ ๋ค์ด๋ก๋ ํ์ ํด๋น ํฐํธ๋ก ๊ต์ฒด๋๋ ํ์
ํฐํธ ์ต์ ํ ๊ธฐ๋ฒ์๋ ์ฌ๋ฌ ๊ฐ์ง๊ฐ ์กด์ฌํฉ๋๋ค.
์๋์์ ์๊ฐํด๋๋ฆฌ๋ ๊ธฐ๋ฒ๋ค์ ์ํฉ์ ๋ง๊ฒ ์ ์ฉํ์ฌ ์ต์ ํ๋ฅผ ์งํํด ๋ณด์ธ์!
font-display ์์ฑ ํ์ฉ
font-display ์์ฑ์ ํฐํธ ๋ก๋ฉ ์ค ํ ์คํธ๋ฅผ ์ด๋ป๊ฒ ํ์ํ ์ง ์ ์ดํฉ๋๋ค.
@font-face {
font-family: 'MyWebFont';
src: url('myfont.woff2') format('woff2'),
url('myfont.woff') format('woff');
font-display: swap; /* ํต์ฌ ์์ฑ */
font-weight: normal;
font-style: normal;
}
- swap: ํฐํธ ๋ก๋ ์ ๊น์ง ์์คํ ํฐํธ๋ก ํ์ (FOUT, ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ๋จ)
- block: ํฐํธ ๋ก๋ ๋ ๋๊น์ง ํ ์คํธ ์จ๊น, 3์ด ์ฐจ๋จ ๊ธฐ๊ฐ ํ ์์คํ ํฐํธ ํ์ (FOIT)
- fallback: ๋งค์ฐ ์งง์ FOIT ํ ์์คํ ํฐํธ ํ์, 3์ด ๋ด ๋ก๋๋๋ฉด ์นํฐํธ๋ก ์ ํ (FOIT)
- optional: fallback๊ณผ ์ ์ฌ. ๋ธ๋ผ์ฐ์ ๊ฐ ๋คํธ์ํฌ ์ํ์ ๋ฐ๋ผ ๊ฒฐ์ , ๋ณดํต ํ ๋ฒ๋ง ์๋ํ๊ณ ์บ์ (FOIT)
- auto: ๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ๊ฐ
ํฐํธ ํ๋ฆฌ๋ก๋ฉ
์ค์ํ ํฐํธ๋ ํ๋ฆฌ๋ก๋ฉํ์ฌ ํ์ด์ง ๋ก๋ ์ด๊ธฐ์ ์์ฒญํ ์ ์์ด์.
<link rel="preload" href="fonts/myfont.woff2" as="font" type="font/woff2" crossorigin>
"๋ธ๋ผ์ฐ์ ์๊ฒ ์ด ๋ฆฌ์์ค๊ฐ ์ค์ํ๋ ๋จผ์ ๊ฐ์ ธ์!"๋ผ๊ณ ์๋ ค์ฃผ๋ ๊ฒ์ด์ฃ .
ํต์ฌ ํ
์คํธ์ ์ฌ์ฉ๋๋ ํฐํธ์๋ง ์ฌ์ฉํ๊ณ , ๋จ์ฉํ๋ฉด ์คํ๋ ค ์ฑ๋ฅ์ด ์ ํ๋ฉ๋๋ค.
ํจ์จ์ ์ธ ํฐํธ ํฌ๋งท ์ฌ์ฉ
ํฐํธ์๋ ์ฌ๋ฌ ํฌ๋งท์ด ์กด์ฌํฉ๋๋ค.
- WOFF2: ์ต์ ํฌ๋งท, ์ต๊ณ ์ ์์ถ๋ฅ (์๋ณธ ๋๋น 30% ์ด์ ๊ฐ์), ์ต์ ๋ธ๋ผ์ฐ์ ์์ ์ง์
- WOFF: ๋๋ถ๋ถ์ ๋ธ๋ผ์ฐ์ ์์ ์ง์, ์ ์ ํ ์์ถ๋ฅ
- TTF/OTF: ๋ ๊ฑฐ์ ์ง์์ฉ, ์์ถ๋ฅ ๋ฎ์
- EOT: ์ค๋๋ IE ์ง์์ฉ, ๊ฑฐ์ ์ฌ์ฉ ์ ํจ
WOFF2 -> WOFF -> TTF/OTF -> EOT ์์ผ๋ก ํฌ๊ธฐ๊ฐ ์ปค์ง๋๋ค.
์ต์ ํฌ๋งท์ ์ต์ ๋ธ๋ผ์ฐ์ ์์๋ง ์ง์ํ๊ธฐ ๋๋ฌธ์ ์ง์ํ๋ ๋ธ๋ผ์ฐ์ ์ ๋ง๋ ํฌ๋งท์ ์์ฐจ์ ์ผ๋ก ์ ๊ณตํ ์ ์์ด์.
@font-face {
font-family: 'MyWebFont';
src: url('myfont.woff2') format('woff2'),
url('myfont.woff') format('woff'),
url('myfont.ttf') format('truetype');
font-display: swap;
}
ํฐํธ ํฌ๋งท ๋ณํ ์ฌ์ดํธ์์ ์ฝ๊ฒ ํ๋์ ํฐํธ๋ก ์ฌ๋ฌ ํฌ๋งท์ ๋ํ ํฐํธ ํ์ผ์ ๋ณํํ ์ ์์ต๋๋ค!
์๋ธ์ ํฐํธ ์ฌ์ฉ
์๋ธ์ ํฐํธ(Subset Font)๋ ํ์ํ ๋ฌธ์๋ง ๋ค์ด๋ก๋ํด์ ํฐํธ ํฌ๊ธฐ๋ฅผ ์ต์ํ ํ ํฐํธ์ ๋๋ค.
์๋ฅผ ๋ค์ด, ํ๊ธ ๊ฐ์ ๊ฒฝ์ฐ ๊ถณ, ๋, ์ป ๋ฑ๋ฑ ์ด๋ฐ ์ฌ์ฉํ์ง ์๋ ๋ฌธ์๋ค์ ๊ณผ๊ฐํ ๋ฒ๋ฆฌ๊ณ ์ ๋ง ์ฌ์ฉํ ๊ธ์๋ง ํฐํธ์ ํฌํจ์ํค๋ ๊ฒ์ด์ฃ .
์๋ธ์ ์น ํฐํธ๋ก ๋ณํํ๋ ์ฌ์ดํธ์์ ๋ณํ์ ํด์ ํฌ๊ธฐ๊ฐ ์์ ์๋ก์ด ํฐํธ ํ์ผ์ ์์ฑํ ์ ์์ต๋๋ค.
ํฐํธ๋ฅผ ์ ๋ก๋ํ๊ณ ๋ณํ๋ง ํด์ฃผ๋ฉด ๊ฐ๋จํ๊ฒ ๋ณํ์ด ๋๋๋ฐ์.
ํด๋น ์ฌ์ดํธ๋ ํ๊ธ์ ์ง์ํ์ง ์๊ธฐ ๋๋ฌธ์ ์ง์ ์ฌ์ฉํ ๋ฌธ์๋ค์ ๋ฃ์ด์ค์ผ ํฉ๋๋ค.
๊ตฌ๊ธ์ "ํ๊ธ ์๋ธ์ ๋ฆฌ์คํธ"๋ผ๊ณ ๊ฒ์ํ์๋ฉด ์ฝ๊ฒ ์ฐพ์ ์ ์์ต๋๋ค.
unicode-range ์์ฑ ์ฌ์ฉ
์๋ธ์ ํฐํธ์ ๊ฐ์ด ์กฐํฉํด์ ์ฌ์ฉํ๋ฉด ์ต์ ํ๋ฅผ ๊ทน๋ํํ ์ ์์ต๋๋ค!
์ด ๋ฐฉ๋ฒ์ ๋์ผํ ํฐํธ ํ์ผ์ ์ฌ์ฉํ๋, CSS์์ ๊ฐ ํฐํธ ์ ์ธ์ด ์ด๋ค ๋ฌธ์์ ์ ์ฉ๋ ์ง ์ง์ ํ๋ ๊ฒ์ ๋๋ค.
/* ๋ผํด ๋ฌธ์์ฉ ํฐํธ ์ ์ธ */
@font-face {
font-family: 'MyFont';
src: url('myfont.woff2') format('woff2');
unicode-range: U+0000-00FF; /* ๋ผํด ๋ฌธ์ ๋ฒ์ */
font-display: swap;
}
/* ํ๊ธ์ฉ ํฐํธ ์ ์ธ */
@font-face {
font-family: 'MyFont';
src: url('myfont.woff2') format('woff2');
unicode-range: U+AC00-D7AF; /* ํ๊ธ ๋ฒ์ */
font-display: swap;
}
์๋ณธ ํฐํธ ํ์ผ์ ๊ทธ๋๋ก ์ฌ์ฉํ๊ณ , ํน์ ํฐํธ ์ ์ธ์ด ์ ์ฉ๋ ์ ๋์ฝ๋ ๋ฒ์๋ฅผ ์ง์ ํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋ธ๋ผ์ฐ์ ๊ฐ ํ์ด์ง์ ํด๋น ๋ฒ์์ ๋ฌธ์๊ฐ ์์ ๋๋ง ํฐํธ๋ฅผ ๋ค์ด๋ก๋ํ๊ฒ ๋์ฃ .
์ด๋ ๊ฒ ํ๋ฉด ํฐํธ ํ์ผ ํฌ๊ธฐ๋ ์์์ง๊ณ , ํ์ํ ๊ฒฝ์ฐ์๋ง ๋ค์ด๋ก๋๋๋ ์ต์ ์ ํฐํธ ์ ๋ต์ ๊ตฌํํ ์ ์์ต๋๋ค.
๐ CDN ์ฌ์ฉ
์๋ฒ์ ์ฌ์ฉ์ ๊ฐ์ ๋ฌผ๋ฆฌ์ ๊ฑฐ๋ฆฌ๊ฐ ๋ฉ์๋ก ๋ฐ์ดํฐ ์ ์ก ์๊ฐ์ด ๊ธธ์ด์ง๊ณ , ๋จ์ผ ์๋ฒ๋ ํธ๋ํฝ ์ฆ๊ฐ ์ ๋ณ๋ชฉ ํ์์ด ๋ฐ์ํ ์ ์์ด์.
CDN(Content Delivery Network)์ ์ ์ธ๊ณ ์ฌ๋ฌ ์๋ฒ์ ์ฝํ ์ธ ๋ฅผ ๋ถ์ฐ ์ ์ฅํ์ฌ ์ฌ์ฉ์์ ๊ฐ๊น์ด ์์น์์ ์ปจํ ์ธ ๋ฅผ ์ ๊ณตํ๋ ์๋น์ค์ ๋๋ค.
์ ์ ์์ฐ(์ด๋ฏธ์ง, CSS, JavaScript, ๋น๋์ค ๋ฑ)๋ฟ๋ง ์๋๋ผ ๋์ ์ฝํ
์ธ ๊น์ง ์ฒ๋ฆฌํ ์ ์๊ณ , ๊ณ ๊ธ ๊ธฐ๋ฅ์ผ๋ก ์๋ ํ์ผ ์์ถ, ์ด๋ฏธ์ง ์ต์ ํ์ ๊ฐ์ ์ถ๊ฐ์ ์ธ ๊ฒ๋ค๊น์ง ์ฒ๋ฆฌํ ์ ์์ด์.
CDN ์๋น์ค ์ค์๋ Cloudinary, Cloudflare, AWS CloudFront, Vercel, Netlify ๋ฑ์ด ์กด์ฌํฉ๋๋ค.
CDN์ ์ด๋ฏธ์ง๋ฅผ ํ์ฉํ๋ค๊ณ ๊ฐ์ ํ์ ๋ ์๋์ ๊ฐ์ด ์ฌ์ฉํ ์ ์์ด์.
function OptimizedProductImage({ productId, alt }) {
const baseUrl = "https://res.cloudinary.com/your-cloud-name/image/upload"; // ์
๋ก๋ ๋ uri
const transformations = "f_auto,q_auto,w_800,c_fill"; // ์ด๋ฏธ์ง ํฌ๊ธฐ ๋์ ์ผ๋ก ๋ฐ๊ธฐ
const imagePath = `products/${productId}.jpg`;
return (
<img
src={`${baseUrl}/${transformations}/${imagePath}`}
alt={alt}
loading="lazy"
/>
);
}
CDN์ ํ์ฉํ์ ๋ ์ด์ ์ ๋ค์๊ณผ ๊ฐ์์.
- ๋ก๋ฉ ์๋ ํฅ์: ์ฌ์ฉ์์ ๊ฐ๊น์ด ์๋ฒ์์ ์ฝํ ์ธ ์ ๊ณต
- ์๋ฒ ๋ถํ ๋ถ์ฐ: ์๋ณธ ์๋ฒ์ ๋ถ๋ด ๊ฐ์
- ๊ฐ์ฉ์ฑ ํฅ์: ์ผ๋ถ ์๋ฒ์ ์ฅ์ ๊ฐ ๋ฐ์ํด๋ ์๋น์ค ์ ์ง
- ๋ณด์ ๊ฐํ: DDos ๋ฐฉ์ด, WAF ๋ฑ ๋ณด์ ๊ธฐ๋ฅ ์ ๊ณต
๐ ๋๋์ ๋ฐ์ดํฐ ๋ฆฌ์คํธ์ ๊ฐ์ํ ์ ์ฉ
๊ฐ์ํ๋ ๋๋์ ๋ฐ์ดํฐ๋ฅผ ํจ์จ์ ์ผ๋ก ํ์ํ๊ธฐ ์ํ ๋ ๋๋ง ์ต์ ํ ๊ธฐ์ ๋ก, ์ค์ ๋ก ํ๋ฉด์ ๋ณด์ด๋ ์์์ ๊ทธ ์ฃผ๋ณ์ ์ผ๋ถ๋ง ์ค์ DOM ๋
ธ๋๋ก ๋ ๋๋ง ํ๊ณ , ํ๋ฉด ๋ฐ์ ์์๋ ๋ฐ์ดํฐ๋ง ๋ฉ๋ชจ๋ฆฌ์ ์ ์งํ ์ฑ DOM ์์ฑ์ ์ง์ฐ์ํค๋ ๋ฐฉ์์
๋๋ค.
์ ์ฉํ๊ธฐ ์ข์ ์ํฉ์ ๊ธด ๋ชฉ๋ก ๋ฐ์ดํฐ ์ฆ, ์ํ ํ์ด์ง, ์์
๋ฏธ๋์ด ํผ๋, ์ฑํ
๋ฉ์์ง ๋ชฉ๋ก๋ฑ ๋๋์ ๋ฐ์ดํฐ๋ฅผ ๋ณด์ฌ์ค์ผ ํ๋ ์ํฉ์์ ์ ํฉํด์. ๊ทธ๋ฆฌ๊ณ ๋ฌดํ ์คํฌ๋กค๊ณผ ๊ฒฐํฉํ์ฌ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ ๋ง์ต๋๋ค.
๊ฐ์ํ๋ฅผ ์ง์ ๊ตฌํํ ์ ์์ง๋ง ๊ฐ์ํ๋ฅผ ์ง์ํ๋ react-window, react-virtualized, react-virtuoso ๋ฑ ์ ๋ง๋ค์ด์ง ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค๋ ์กด์ฌํฉ๋๋ค.
์ ๋ ์์์์ react-virtuoso๋ฅผ ์ฌ์ฉํ ๊ฑฐ์์.
๊ฐ์ํ ์ ์ฉ ์
์์๋ก, 1๋ง ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ์๊ณ , ์ด ๋ฐ์ดํฐ๋ฅผ ๋ฆฌ์คํธ๋ก ๋ณด์ฌ์ค์ผ ํ๋ ์ํฉ์ ๊ฐ์ ํด ๋ณผ๊ฒ์.
function Test() {
// ๋๋์ ๋ฐ์ดํฐ (์: 10,000๊ฐ ํญ๋ชฉ)
const data = Array.from({ length: 10000 }).map((_, index) => ({
id: index,
text: `ํญ๋ชฉ ${index + 1}`,
}));
return (
<div style={{ height: '400px', width: '100%', overflowY: 'auto' }}>
{data.map((item) => (
<div
key={item.id}
style={{ padding: '12px', borderBottom: '1px solid #eee' }}
>
{item.text}
</div>
))}
</div>
);
}
export default Test;
ํ๋ฉด์ด ๋ ๋๋ง ๋ ๋ 1๋ง ๊ฐ์ DOM ๋
ธ๋๋ฅผ ์ถ๊ฐํ์ฌ ๋ ๋๋ง ํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์ฆ, ํ์ฌ ๋ณด์ด์ง ์๋ ์์ญ์ ๋ฐ์ดํฐ๊น์ง DOM ๋
ธ๋์ ์ถ๊ฐ๋ ์ํฉ์ด์ฃ .
์ด๊ธฐ์ ๋๋์ ๋ฐ์ดํฐ๋ฅผ ๋ชจ๋ ๋ถ๋ฌ์์ DOM ๋ ธ๋์ ์ถ๊ฐํ์ฌ ๋ ๋๋ง ํ๊ธฐ ๋๋ฌธ์ ์ด๊ธฐ ๋ก๋ฉ ์๋ ๋ํ ๋น์ฐํ ๋๋ฆด ๊ฒ์ ๋๋ค.
๊ฐ์ํ ์ ์ฉ ํ
import { Virtuoso } from 'react-virtuoso';
function Test2() {
// ๋๋์ ๋ฐ์ดํฐ (์: 10,000๊ฐ ํญ๋ชฉ)
const data = Array.from({ length: 10000 }).map((_, index) => ({
id: index,
text: `ํญ๋ชฉ ${index + 1}`,
}));
return (
<Virtuoso
style={{ height: '400px', width: '100%' }}
totalCount={data.length}
itemContent={(index) => (
<div style={{ padding: '12px', borderBottom: '1px solid #eee' }}>
{data[index].text}
</div>
)}
/>
);
}
export default Test2;
์ค์ ํ๋ฉด์ ๋ณด์ด๋ ์์ ๋ฐ ์ฃผ๋ณ ์ผ๋ถ๋ง DOM ๋
ธ๋์ ์ถ๊ฐ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์ฃผ์ํ ์ ์ผ๋ก๋ ์ค์ DOM์ ๊ทธ๋ ค์ง๊ธฐ ์ ์ ์คํฌ๋กค์ ๋น ๋ฅด๊ฒ ๋ด๋ฆฌ๋ฉด ํฐ ํ๋ฉด์ด ์ ๊น ๋ณด์ผ ์ ์์ด์.
์ด๋ UX๋ฅผ ์ ํ์ํค๊ธฐ ๋๋ฌธ์ ์ค์ผ๋ ํค ๋ก๋ฉ๊ณผ ๊ฐ์ fallbackUI๋ฅผ ์ถ๊ฐํ์๊ธธ ์ถ์ฒ๋๋ฆฝ๋๋ค.
๊ฐ ๊ฐ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ณ๋ก fallbackUI ์ฒ๋ฆฌ๋ฅผ ์ํด ์ง์ํ๋ ์ต์
๋ค์ด ์กด์ฌํ๋ ํ๋ฒ ํ์ธํด๋ณด์ธ์.
์ด์ ์ ์ ๋ฆฌํ๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ์ค์ DOM ๋ ธ๋ ์๋ฅผ ํฌ๊ฒ ์ค์ฌ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ์ต์ ํ
- ์ด๊ธฐ ๋ ๋๋ง ๋ฐ ์คํฌ๋กค ์ฑ๋ฅ ํฅ์ (๋ ๋๋ง ์ฐ์ฐ ์ต์ํ)
- ์์ฒ, ์๋ง ๊ฐ์ ํญ๋ชฉ๋ ๋ถ๋๋ฝ๊ฒ ์คํฌ๋กค ๊ฐ๋ฅ
โก ์ ๋๋ฉ์ด์ ์ requestAnimationFrame(rAF)๋ฅผ ํ์ฉํด๋ณด๊ธฐ
requestAnimationFrame(rAF)์ ๋ธ๋ผ์ฐ์ ์ ๋ฆฌํ์ธํธ ์ฃผ๊ธฐ์ ๋ง์ถฐ ์ ๋๋ฉ์ด์ ์ด๋ ์๊ฐ์ ์ ๋ฐ์ดํธ๋ฅผ ์คํํ๋ Javascript API์ ๋๋ค.
๋ธ๋ผ์ฐ์ ์ ๋ ๋๋ง ์์ง๊ณผ ๋๊ธฐํ๋์ด ์๋ํ๋ฏ๋ก, ์ผ๋ฐ์ ์ผ๋ก ์ด๋น 60 ํ๋ ์(60 fps, ์ฝ 16.7ms)์ ์๋๋ก ์คํ๋ฉ๋๋ค.
์ ์์ ๋ setInterval๊ณผ rAF๋ฅผ ์ฌ์ฉํ์ฌ width๋ฅผ ์ฆ๊ฐ์ํค๋ ์์ ์
๋๋ค.
"์์" ๋ฒํผ์ ๋๋ฌ๋ณด๋ฉด rAF๋ ๋ถ๋๋ฝ๊ฒ ์ฆ๊ฐ๋๋ ๋ฐ๋ฉด, setInterval์ ์ค๊ฐ์ค๊ฐ ๋๊ธฐ๋ ๋๋์ด ์กด์ฌํฉ๋๋ค.
๊ฐ๋จํ๊ฒ ์ฐจ์ด์ ์ ์์๋ณผ๊ฒ์.
ํน์ฑ | setTimeout/setInterval | requestAnimationFrame |
ํ์ด๋ฐ | ์ง์ ๋ ์๊ฐ ํ ์คํ | ๋ธ๋ผ์ฐ์ ๋ฆฌํ์ธํธ ์ง์ ์ ์คํ |
ํ๋ ์ ๋ ์ดํธ | ๊ณ ์ ๊ฐ๊ฒฉ (๋ถ๊ท์นํ ์ ์์) | ํ๋ฉด ์ฃผ์ฌ์จ์ ์ต์ ํ (๋ณดํต 60fps) |
๋ฐฑ๊ทธ๋ผ์ด๋ ๋์ | ๊ณ์ ์คํ (์ ํ๋ ์ ์์) | ๋นํ์ฑ ํญ์์ ์ผ์ ์ค์ง (๋ฆฌ์์ค ์ ์ฝ) |
์ ํ์ฑ | ๋ธ๋ผ์ฐ์ ์ ํ ์์ (์ต์ 4ms) | ๋ ๋๋ง ํ์ดํ๋ผ์ธ๊ณผ ์ ํํ ๋๊ธฐํ |
rAF๋ ํนํ ์ ๋๋ฉ์ด์ , ์คํฌ๋กค ์ด๋ฒคํธ ์ฒ๋ฆฌ, ์บ๋ฒ์ค ๊ทธ๋ฆฌ๊ธฐ, ๋ฐ์ดํฐ ์๊ฐํ ๋ฑ ๋ถ๋๋ฌ์ด ์๊ฐ์ ์ ๋ฐ์ดํธ๊ฐ ํ์ํ ์ํฉ์์ ์ต๊ณ ์ ์ฑ๋ฅ์ ๋ฐํํด์.
๐ฆ React ์ฝ๋ ์คํ๋ฆฌํ ๊ณผ ์ง์ฐ ๋ก๋ฉ (Lazy Loading)
์ฌ๋ฌ ๊ฐ์ ์์ ์ฒญํฌ(chunk)๋ก ๋ถํ ํ๊ณ , ํ์ํ ์์ ์ ํด๋น ์ฒญํฌ๋ง ๋์ ์ผ๋ก ๋ก๋ํ๋ ์ต์ ํ ๊ธฐ๋ฒ์ ๋๋ค.
์ด๊ธฐ ๋ก๋ฉ ์ ํ์ํ ์ฝ๋๋ง ๋ค์ด๋ก๋ํ๊ณ , ๋๋จธ์ง๋ ์ฌ์ฉ์๊ฐ ํด๋น ๊ธฐ๋ฅ์ด๋ ํ์ด์ง๋ฅผ ์์ฒญํ ๋ ๋ก๋ํ ์ ์์ด์.
React๋ React.lazy()์ Suspense ์ปดํฌ๋ํธ๋ฅผ ํตํด ์ฝ๋ ์คํ๋ฆฌํ ๊ณผ ์ง์ฐ๋ก๋ฉ์ ์ฝ๊ฒ ๊ตฌํํ ์ ์๋๋ก ์ง์ํฉ๋๋ค!
import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Navbar from './components/Navbar';
// ํ์ด์ง ์ปดํฌ๋ํธ ์ง์ฐ ๋ก๋ฉ
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const Dashboard = lazy(() => import('./pages/Dashboard'));
const UserProfile = lazy(() => import('./pages/UserProfile'));
function App() {
return (
<Router>
<Navbar />
<Suspense fallback={<div className="page-loader">ํ์ด์ง ๋ก๋ฉ ์ค...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/profile/:userId" element={<UserProfile />} />
</Routes>
</Suspense>
</Router>
);
}
export default App;
์์ ๊ฐ์ด ์์ฝ๊ฒ ์ ์ฉํ ์ ์์ต๋๋ค.
ํ์ด์ง๋ฅผ ๊ธฐ์ค์ผ๋ก lazy loading์ ์ ์ฉํ์ด์.
๋ฆฌ์กํธ ํ๋ก์ ํธ๋ฅผ ๋น๋ํ๊ณ ์ฒซ ํ์ด์ง์ ์ง์ ํ์ ๋์ ์์๋ฅผ ํ๋ฒ ๋ณผ๊น์?
์ ์ฉ ์
์ ์ฉ ์ ์ ๋น๋ ๊ฒฐ๊ณผ๋ฌผ ์ค์ js ํ์ผ์ ํ๋์ jsํ์ผ๋ก ๋ชจ๋ ์ฝ๋๊ฐ ํฉ์ณ์ง ๊ฒ์ ํ์ธํ ์ ์์ด์.
์ด jsํ์ผ์ ์ฒซ ํ์ด์ง ์์ ๋ชจ๋ ๋ถ๋ฌ์ค๋ ์ํฉ์
๋๋ค.
์ฑ ํฌ๊ธฐ๊ฐ ์ปค์ง์๋ก ๋จ์ผ ๋ฒ๋ค์ ํฌ๊ธฐ๊ฐ ์ผ์ ธ์ ์ด๊ธฐ ๋ก๋ฉ ์๊ฐ์ด ์ฆ๊ฐํ๊ณ , ๋ชจ๋ฐ์ผ ํ๊ฒฝ์ด๋ ๋๋ฆฐ ๋คํธ์ํฌ ํ๊ฒฝ์์๋ ํนํ ๋ ๋๋ฆด ์๊ฐ ์์ด์.
์ ์ฉ ํ
lazy loading์ ์ ์ฉํ ๊ฒฐ๊ณผ ๊ฐ ํ์ด์ง, ์ปดํฌ๋ํธ ๋ณ๋ก js๊ฐ ๋ถ๋ฆฌ๋์์ด์!
์ฆ, ์ ๋ง ํ์ํ jsํ์ผ๋ง ์์ฒญํ ์ ์๊ฒ ๋์์ต๋๋ค.
์ด๋ ๊ฒ ํ์ ๋ ์ด์ ๋ค์ ๋ญ๊น์?
- FCP(First Contentful Paint), TTI(Time to Interaction) ๊ฐ์
- Core Web Vitals ์ ์ ํฅ์์ผ๋ก SEO์๋ ๐
- ํน์ ๊ธฐ๋ฅ๋ง ์ ๋ฐ์ดํธ ์ ํด๋น ์ฒญํฌ๋ง ๋ค์ ๋ค์ด๋ก๋
- ์ฌ์ฉ์๊ฐ ์ค์ ๋ก ํ์๋ก ํ๋ ์ฝ๋๋ง ๋ค์ด๋ก๋ํ์ฌ ๋์ญํญ ์ ์ฝ
์ฌ์ฉ์ ๊ฒฝํ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ต๋๋ค!
์กฐ๊ธ ๋ ๊น๊ฒ ๋ค์ด๊ฐ๋ฉด ์กฐ๊ฑด๋ถ ์ฝ๋ ์คํ๋ฆฌํ , ํ๋ฆฌ๋ก๋ฉ ํ์ฉ, ์ฒญํฌ ํฌ๊ธฐ ์ต์ ํ๊น์ง ๊ณ ๋ คํด ๋ณผ ์ ์์ด์.
๐ ๋ง์น๋ฉฐ
ํ๋ก ํธ์๋์์ ๋น์ฅ ์ ์ฉํ ์ ์๋ ์ต์ ํ ๋ฐฉ๋ฒ๋ค์ ์ดํด๋ณด์์ต๋๋ค.
์ ๊ฐ ์๊ฐํ ์ต์ ํ ๊ธฐ๋ฒ๋ค์ ์์์ ๋ถ๊ณผํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
์ฐ๊ตฌ์ ๋ฐ๋ฅด๋ฉด ํ์ด์ง ๋ก๋ฉ ์๊ฐ์ด 3์ด๋ฅผ ๋์ด๊ฐ ๋๋ง๋ค ์ดํ๋ฅ ์ด 32% ์ฆ๊ฐํ๋ค๊ณ ํ๋ค์.๐ฅถ
์ฌ๋ฌ๋ถ์ ์๋น์ค์์ ์ฌ์ฉ์ ๊ฒฝํ์ ์ค์ง์ ์ผ๋ก ๊ฐ์ ํ๊ณ ๋น์ฆ๋์ค ๋ชฉํ๊น์ง ๋ฌ์ฑํ๋ ๋ฐ ๋์์ด ๋์์ผ๋ฉด ์ข๊ฒ ์ด์.
๊ฐ์ฌํฉ๋๋ค.