웹솔루션개발 26년 노하우! 해피CGI의 모든것

[해피CGI][cgimall] 이미지가 자연스럽게 전환되는 갤러리 본문

웹프로그램밍 자료실/기타 자료

[해피CGI][cgimall] 이미지가 자연스럽게 전환되는 갤러리

해피CGI윤실장 2026. 10. 28. 09:06

React 기반으로 제작된 이미지 갤러리 예제로, 이미지 간 전환 과정에 시각적인 모프 효과를 적용한 것이 특징입니다.

화면 좌우의 이전·다음 버튼을 통해 이미지를 순차적으로 전환할 수 있으며, 하단 썸네일을 선택해 원하는 이미지로 바로 이동할 수도 있습니다.
모바일 화면에서는 썸네일 영역을 숨기고 좌우 탐색 버튼을 유지하는 방식으로 반응형 처리되어 있습니다.
포트폴리오, 제품 이미지, 사진 전시 등 이미지 중심의 웹페이지에서 활용하기 좋은 갤러리 입니다.

HTML 구조

<div id="root"></div>



CSS 소스

.root {

  width: 100%;

  height: 100dvh;

  overflow: hidden;

}

 

.root > div {

  width: 100%;

  height: 100%;

}

 

.stage {

  position: relative;

  width: 100%;

  height: 100%;

}

 

.stage::after {

  content: "";

  position: absolute;

  inset: auto 0 0;

  height: 220px;

  background: linear-gradient(to bottom, transparent, rgb(0 0 0 / 65%));

  pointer-events: none;

  z-index: 5;

}

 

.canvas {

  position: absolute;

  inset: 0;

  display: block;

  width: 100%;

  height: 100%;

}

 

.navPrev,

.navNext {

  backdrop-filter: contrast(2) brightness(0.7) blur(10px);

  position: absolute;

  top: 50%;

  transform: translateY(-50%);

  width: 44px;

  height: 44px;

  border-radius: 50%;

  background: rgb(255 255 255 / 12%);

  border: 1px solid rgb(255 255 255 / 18%);

  color: #fff;

  display: flex;

  align-items: center;

  justify-content: center;

  cursor: pointer;

  z-index: 10;

  transition:

    background 0.2s ease,

    opacity 0.2s ease;

}

 

.navPrev:hover,

.navNext:hover {

  background: rgb(255 255 255 / 22%);

}

 

.navPrev:disabled,

.navNext:disabled {

  opacity: 0.25;

  pointer-events: none;

}

 

.navPrev {

  left: 2rem;

}

 

.navNext {

  right: 2rem;

}

 

.thumbs {

  position: absolute;

  bottom: 2rem;

  left: 0;

  right: 0;

  margin: 0 auto;

  

  width: max-content;

  max-width: calc(100% - 2rem); 

  

  display: flex;

  gap: 8px;

  list-style: none;

  padding: 0 0 10px 0;

  z-index: 10;

  

  overflow-x: auto;

  scroll-behavior: smooth;

}

.thumbs::-webkit-scrollbar {

  height: 6px;

}

.thumbs::-webkit-scrollbar-track {

  background: rgb(255 255 255 / 10%);

  border-radius: 4px;

}

.thumbs::-webkit-scrollbar-thumb {

  background: rgb(255 255 255 / 30%);

  border-radius: 4px;

}

.thumbItem {

  list-style: none;

  flex-shrink: 0; 

}

 

.thumbButton {

  display: block;

  padding: 0;

  border: 2px solid transparent;

  border-radius: 4px;

  cursor: pointer;

  overflow: hidden;

  background: none;

  transition:

    border-color 0.2s ease,

    opacity 0.2s ease;

  opacity: 0.55;

}

 

.thumbButton[aria-current="true"] {

  border-color: #fff;

  opacity: 1;

}

 

.thumbButton:hover {

  opacity: 0.85;

}

 

.thumbButton img {

  display: block;

  width: 80px;

  height: 50px;

  object-fit: cover;

}

 

.srOnly {

  position: absolute;

  width: 1px;

  height: 1px;

  padding: 0;

  margin: -1px;

  overflow: hidden;

  clip: rect(0, 0, 0, 0);

  white-space: nowrap;

  border-width: 0;

}

@media (max-width: 600px) {

  .thumbs {

    display: none;

  }

  

  

  

.navPrev {

  left: 1rem;

}

 

.navNext {

  right: 1rem;

}

 

  

  }



JS 소스

 import React, { useState, useRef, useEffect } from "https://esm.sh/react";

import { createRoot }from "https://esm.sh/react-dom/client";

import {

  Gallery,

  GalleryNav,

  GalleryPagination,

  GalleryPaginationItem,

  useGallery,

} from "https://esm.sh/@wethegit/react-gallery@4.0.2";

console.clear();

 

const ITEMS = [

  {

    id: 1,

    image:

      "https://images.unsplash.com/photo-1500534314209-a25ddb2bd429?auto=format&fit=crop&w=1200&h=700&q=80",

    thumb:

      "https://images.unsplash.com/photo-1500534314209-a25ddb2bd429?auto=format&fit=crop&w=200&h=120&q=60",

    alt: "Sun rays through a forest",

  },

  {

    id: 2,

    image:

      "https://images.unsplash.com/photo-1519681393784-d120267933ba?auto=format&fit=crop&w=1200&h=700&q=80",

    thumb:

      "https://images.unsplash.com/photo-1519681393784-d120267933ba?auto=format&fit=crop&w=200&h=120&q=60",

    alt: "Snow-capped mountain peak at night",

  },

  {

    id: 3,

    image:

      "https://images.unsplash.com/photo-1506905925346-21bda4d32df4?auto=format&fit=crop&w=1200&h=700&q=80",

    thumb:

      "https://images.unsplash.com/photo-1506905925346-21bda4d32df4?auto=format&fit=crop&w=200&h=120&q=60",

    alt: "Mountain reflected in a still lake",

  },

  {

    id: 4,

    image:

      "https://images.unsplash.com/photo-1501854140801-50d01698950b?auto=format&fit=crop&w=1200&h=700&q=80",

    thumb:

      "https://images.unsplash.com/photo-1501854140801-50d01698950b?auto=format&fit=crop&w=200&h=120&q=60",

    alt: "Aerial view of green hills",

  },

  {

    id: 5,

    image:

      "https://images.unsplash.com/photo-1465146344425-f00d5f5c8f07?auto=format&fit=crop&w=1200&h=700&q=80",

    thumb:

      "https://images.unsplash.com/photo-1465146344425-f00d5f5c8f07?auto=format&fit=crop&w=200&h=120&q=60",

    alt: "Orange wildflower field",

  },

  {

    id: 6,

    image:

      "https://images.unsplash.com/photo-1547234935-80c7145ec969?auto=format&fit=crop&w=1200&h=700&q=80",

    thumb:

      "https://images.unsplash.com/photo-1547234935-80c7145ec969?auto=format&fit=crop&w=200&h=120&q=60",

    alt: "Tropical beach with clear water",

  },

]
...이하생략  소스다운로드 참조

 

Comments