[codereview] 트랜지션 이미지 최적화(리사이징+용량압축)+지연로드(+사전로드)

Suji Kang·2024년 2월 8일

codereview

목록 보기
3/5

🐾 배너 트랜지션 이미지 최적화(리사이징+용량압축)+지연로드(+사전로드)

AS-IS (기존 코드):

const IMAGES = {
  SkinTightening: { src: Image1.src, alt: 'SkinTightening' },
  AcneTreatment: { src: Image2.src, alt: 'AcneTreatment' },
  Pigmentation: { src: Image3.src, alt: 'Pigmentation' },
  Pores: { src: Image4.src, alt: 'Pores' },
}

export default function Portfolio() {
  const languageList = useContext(UserContext)

  const [hover, setHover] = useState(null)
  const [selected, setSelected] = useState(null)
  useEffect(() => setSelected(null), [hover])
  const handleMouseOver = (type) => setHover(type)
  const handleMouseClick = (type) => setSelected(type)
  const handleMouseLeave = () => setHover(null)
  
   return (
    <div className={styles.container}>
      <div
        className={styles.background}
        style={{
          backgroundImage: hover
            ? `url(${IMAGES[hover].src})`
            : `url(${CoverImage.src})`,
        }}
        onMouseLeave={handleMouseLeave}
      >
        </div>
  )
}

AS-IS (기존 코드)

📌원본 이미지 사용: 이미지의 원본을 사용하여 이미지 크기가 크고 용량이 컸습니다.(원본 이미지를 써서 이미지 가로세로 크기가 너무 큼..)
📌압축률이 낮은 포맷: 이미지를 압축률이 낮은 포맷으로 사용하여 용량이 컸습니다.
📌백그라운드 처리: 이미지를 백그라운드 이미지로 처리했기 때문에, 전환될 이미지가 로드되어 있지 않아 최초 전환 시 깜빡임이 발생했습니다.

TO-BE (개선된 코드):

const IMAGES = [
  { src: CoverImage.src, key: 'Portfolio' },
  { src: Image1.src, key: 'SkinTightening' },
  { src: Image2.src, key: 'AcneTreatment' },
  { src: Image3.src, key: 'Pigmentation' },
  { src: Image4.src, key: 'Pores' },
]

export default function Portfolio() {
  const languageList = useContext(UserContext)

  const [hover, setHover] = useState('Portfolio')
  const [selected, setSelected] = useState(null)
  useEffect(() => setSelected(null), [hover])
  const handleMouseOver = (type) => setHover(type)
  const handleMouseClick = (type) => setSelected(type)
  const handleMouseLeave = () => setHover('Portfolio')

  const backgroundImage = ({ src, key }) => (
    <Image
      key={key}
      src={src}
      alt={key}
      fill
      style={{
        objectFit: 'cover',
        opacity: hover === key ? 1 : 0,
        transition: 'opacity 0.5s ease-in-out',
      }}
    />
  )
  
    return (
    <div className={styles.container}>
      {IMAGES.map(backgroundImage)}
      <div className={styles.background} onMouseLeave={handleMouseLeave}>
 </div>
  )
}

📌Next.js의 Image 컴포넌트 사용: Next.js의 Image 컴포넌트를 사용하여 이미지를 처리했습니다. 이를 통해 이미지를 쉽게 조작하고 최적화할 수 있습니다.
📌다양한 사이즈 및 Webp 포맷 사용: 다양한 사이즈로 리사이징된 이미지를 사용하여 브라우저가 적합한 사이즈의 이미지를 로드할 수 있도록 했습니다. 또한, Webp 포맷을 사용하여 이미지의 용량을 최적화했습니다.(next Imgage component)
📌이미지 전환 효과 및 로딩 속도 최적화: 이미지 전환 효과를 위해 opacity 값을 조절하고, 이미지를 겹쳐놓아 전환 시 자연스러운 효과를 제공했습니다. 또한, loading="lazy" 속성을 사용하여 이미지를 지연로드하고 lazy loading을 적용하여 초기 로딩 시간을 단축시켰습니다.


🐾기존 코드 분석:

📌1.IMAGES 객체는 각 이미지의 정보를 담고 있습니다. 객체의 형태로 관리되어 특정 이미지를 호출하긴 용이하지만, 열거하기엔 적합하지 않습니다.
📌2.배경 이미지가 특별한 처리 없이 backgroundImage 속성으로 설정되어 있습니다. 이는 이미지가 브라우저에서 최초 로드될 때 깜빡임을 유발할 수 있습니다.

🐾개선된 코드 설명:

📌1.IMAGES 배열은 이미지 정보를 객체로 관리하는 대신 배열로 관리합니다. 이렇게 함으로써 열거하기에 용이합니다.
📌2.상태값 hover의 초기값을 'Portfolio'로 설정하여 커버 이미지가 기본적으로 표시되도록 합니다.
const [hover, setHover] = useState('Portfolio')
📌3.useEffect 훅을 사용하여 hover 상태값이 변경될 때마다 selected 상태값을 초기화합니다.
useEffect(() => setSelected(null), [hover])
📌각 이미지를 Image 컴포넌트로 렌더링하며, hover 상태값에 따라 이미지의 투명도를 조절하여 마우스 오버 시 부드러운 전환 효과를 제공합니다.
배경 이미지를 backgroundImage 속성이 아닌 별도의 Image 컴포넌트로 렌더링하여 loading="lazy" 지연로드 시점에 한꺼번에 사전로드될 수 있도록 하고, 효과적인 이미지 로딩을 위해 Next.js의 Image 컴포넌트를 활용합니다.

🔎 이전 코드의 개선점은 다음과 같습니다:

📝이미지 관리의 편의성:

before: IMAGES 객체를 사용하여 각 이미지의 정보를 단건 렌더링에 적합하게 관리했습니다.
after: 각 이미지를 객체 대신 배열을 사용하여 일괄 렌더링에 용이해졌습니다.

📝상태 초기화와 관련된 개선:

before: hover 상태의 초기값을 null로 설정하고, 마우스가 이동할 때마다 상태를 업데이트했습니다.
after: hover 상태의 초기값을 'Portfolio'로 설정하여 기본적으로 커버 이미지가 표시되도록 했습니다.

📝이미지 로딩 및 전환 효과:

개선된 코드에서는 Image 컴포넌트를 사용하여 이미지를 렌더링하고, 마우스 오버 시에는 부드러운 전환 효과를 제공하기 위해 투명도를 조절했습니다.

  • 이미지 전환 효과: 여러 이미지를 겹쳐서 표시하고, opacity 값을 조절하여 전환 효과를 만듭니다. 이로써 부드러운 이미지 전환 효과를 구현합니다.
  • Lazy Loading: 이미지를 lazy loading 방식으로 로드합니다. 이는 사용자가 이미지를 필요로 할 때만 로드되므로 초기 페이지 로딩 속도를 향상시키고 사용자 경험을 개선합니다.
  • 사전로드: 여러 이미지를 사전으로 로드하여 전환 시 딜레이를 최소화합니다. 이를 통해 사용자가 이미지를 전환할 때 빠른 속도를 유지할 수 있습니다.

📝 추가

이미지 포맷: JPG, PNG, WEBP 등 비교

JPG (JPEG):

손실압축으로 압축률이 높아 용량이 작은 편.
사진 및 복잡한 이미지에 적합.
알파 채널(투명도)을 지원하지 않음.

PNG:

무손실 압축으로 투명도를 지원.
불투명한 배경이 있는 이미지에 적합.
용량이 크고, JPEG보다 선명한 이미지 제공.

WEBP:

Google에서 개발한 이미지 포맷.
JPG, PNG와 비교하여 웹 환경에 적합한 가장 높은 압축률과 풍부한 기능을 제공.
모든 주요 브라우저에서 지원하지만, 일부 오래된 브라우저에서는 지원하지 않을 수 있음.


이미지 리사이징 기법

이미지 리사이징 기법은 다양한 크기의 이미지를 제공하여 사용자 경험을 최적화하는 기술입니다. 이를 통해 사용자가 접속한 디바이스의 화면 크기에 맞춰 최적화된 이미지를 제공할 수 있습니다.

여러 사이즈의 이미지를 브라우저에서 srcset으로 적절히 사용하는 것은 이러한 이미지 리사이징 기법 중 하나입니다. 브라우저는 srcset 속성을 통해 제공된 이미지 중에서 디바이스의 화면 크기에 가장 적합한 이미지를 선택합니다. 각 이미지는 원본 이미지보다 작은 크기로 제공되어 대역폭을 절약하고 페이지 로딩 속도를 향상시킵니다.

예를 들어, 다음과 같이 srcset 속성을 사용하여 여러 크기의 이미지를 제공할 수 있습니다.
<img src="small.jpg" srcset="medium.jpg 1000w, large.jpg 2000w" alt="Image">
위의 예시에서는 브라우저가 1000픽셀 이하의 화면 크기에서는 medium.jpg를, 1000픽셀 이상 2000픽셀 이하의 화면 크기에서는 large.jpg를 선택하여 로드합니다. 이를 통해 사용자의 화면 크기에 따라 최적화된 이미지를 제공할 수 있습니다.


Next.js Image 컴포넌트:

Next.js에서 제공하는 이미지 최적화 컴포넌트.
자동으로 이미지 리사이징&압축 및 지연로드를 지원하여 성능을 최적화함.
손쉬운 사용법과 간편한 설정으로 개발 생산성을 향상시킴.


지연로드/사전로드 기법

지연로드 (Lazy Loading):

페이지 스크롤 등의 이벤트에 따라 이미지를 동적으로 로드함.
초기 로딩 시 모든 이미지를 로드하지 않고 필요한 이미지만 로드하여 초기 로딩 속도를 향상시킴.

사전로드 (Preloading):

특정한 시점에 필요할 이미지를 미리 로드함.
사용자 인터렉션 시점에 이미지 로딩 시간을 줄여 부드러운 사용자 경험을 제공함.


IntersectionObserver 사용 예시

요소의 가시성 변화를 감지하여 콜백 함수를 실행함.
Lazy Loading 및 사전로드와 함께 사용하여 이미지 로드를 최적화함.
브라우저의 성능을 고려하여 가시성을 감지하므로 효율적임.


const intersectionObserver = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
        if (entry.isIntersecting) {
            // 요소가 화면에 나타날 때의 처리
            console.log('요소가 화면에 나타남');
        } else {
            // 요소가 화면에서 사라질 때의 처리
            console.log('요소가 화면에서 사라짐');
        }
    });
});
// 감시할 요소 지정
const targetElement = document.querySelector('.target');
intersectionObserver.observe(targetElement);




profile
나를위한 노트필기 📒🔎📝

0개의 댓글