
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>
)
}
📌원본 이미지 사용: 이미지의 원본을 사용하여 이미지 크기가 크고 용량이 컸습니다.(원본 이미지를 써서 이미지 가로세로 크기가 너무 큼..)
📌압축률이 낮은 포맷: 이미지를 압축률이 낮은 포맷으로 사용하여 용량이 컸습니다.
📌백그라운드 처리: 이미지를 백그라운드 이미지로 처리했기 때문에, 전환될 이미지가 로드되어 있지 않아 최초 전환 시 깜빡임이 발생했습니다.
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 방식으로 로드합니다. 이는 사용자가 이미지를 필요로 할 때만 로드되므로 초기 페이지 로딩 속도를 향상시키고 사용자 경험을 개선합니다.
- 사전로드: 여러 이미지를 사전으로 로드하여 전환 시 딜레이를 최소화합니다. 이를 통해 사용자가 이미지를 전환할 때 빠른 속도를 유지할 수 있습니다.
손실압축으로 압축률이 높아 용량이 작은 편.
사진 및 복잡한 이미지에 적합.
알파 채널(투명도)을 지원하지 않음.
무손실 압축으로 투명도를 지원.
불투명한 배경이 있는 이미지에 적합.
용량이 크고, JPEG보다 선명한 이미지 제공.
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에서 제공하는 이미지 최적화 컴포넌트.
자동으로 이미지 리사이징&압축 및 지연로드를 지원하여 성능을 최적화함.
손쉬운 사용법과 간편한 설정으로 개발 생산성을 향상시킴.
페이지 스크롤 등의 이벤트에 따라 이미지를 동적으로 로드함.
초기 로딩 시 모든 이미지를 로드하지 않고 필요한 이미지만 로드하여 초기 로딩 속도를 향상시킴.
특정한 시점에 필요할 이미지를 미리 로드함.
사용자 인터렉션 시점에 이미지 로딩 시간을 줄여 부드러운 사용자 경험을 제공함.
요소의 가시성 변화를 감지하여 콜백 함수를 실행함.
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);