๐Ÿ’๐Ÿปโ€โ™€๏ธ ์„œ๋ก 

์บ๋Ÿฌ์…€์€ ์ด๋ฏธ์ง€ ์ปฌ๋ ‰์…˜์ด๋‚˜ ๊ธฐํƒ€ ์ฝ˜ํ…์ธ ๋ฅผ ์Šฌ๋ผ์ด๋“œ์‡ผ ํ˜•์‹์œผ๋กœ ํ‘œ์‹œํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ์ธ๊ธฐ ์žˆ๋Š” ์›น ๋””์ž์ธ ์š”์†Œ์ž…๋‹ˆ๋‹ค.
HTML, CSS ๋ฐ JavaScript๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ„๋‹จํ•œ ์บ๋Ÿฌ์…€์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

โถ HTML

์บ๋Ÿฌ์…€์˜ HTML ๊ตฌ์กฐ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

<div class="carousel-container">
  <div class="carousel-slide">
    <img src="https://picsum.photos/id/870/536/354" alt="Dummy Image">
    <img src="https://picsum.photos/id/537/536/354" alt="Dummy Image">
    <img src="https://picsum.photos/id/1060/536/354" alt="Dummy Image">
  </div>
  <button class="carousel-prev">prev</button>
  <button class="carousel-next">next</button>
</div>

์ด ์ฝ”๋“œ๋Š” ์„ธ ๊ฐœ์˜ ์ด๋ฏธ์ง€๋ฅผ ํ‘œ์‹œํ•˜๋Š” ๊ธฐ๋ณธ ์บ๋Ÿฌ์…€ ๋˜๋Š” ์ด๋ฏธ์ง€ ์Šฌ๋ผ์ด๋”์šฉ์ž…๋‹ˆ๋‹ค.

  1. carousel-container ํด๋ž˜์Šค๊ฐ€ ์žˆ๋Š” ์ปจํ…Œ์ด๋„ˆ div๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
    ์ด ์ปจํ…Œ์ด๋„ˆ ๋‚ด์—๋Š” ํ‘œ์‹œ๋  ์ด๋ฏธ์ง€๋ฅผ ํฌํ•จํ•˜๋Š” carousel-slide ํด๋ž˜์Šค๊ฐ€ ์žˆ๋Š” div๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ๊ฐ๊ฐ ์›น์‚ฌ์ดํŠธ ์ด๋ฏธ์ง€ ์†Œ์Šค URL์ด ์žˆ๋Š” 3๊ฐœ์˜ img ์š”์†Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
  3. ์ด๋ฏธ์ง€ div ๋’ค์— carousel-prev ๋ฐ carousel-next ํด๋ž˜์Šค๊ฐ€ ์žˆ๋Š” ๋‘ ๊ฐœ์˜ ๋ฒ„ํŠผ ์š”์†Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
    ์ด ๋ฒ„ํŠผ์„ ์‚ฌ์šฉํ•˜๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์บ๋Ÿฌ์…€ ์ด๋ฏธ์ง€๋ฅผ ์•ž, ๋’ค๋กœ ํƒ์ƒ‰ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โท CSS

์ด์ œ HTML ๊ตฌ์กฐ๋ฅผ ๊ฐ–์ถ”์—ˆ์œผ๋ฏ€๋กœ ๋ช‡ ๊ฐ€์ง€ ๊ธฐ๋ณธ CSS๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์บ๋Ÿฌ์…€์˜ ์Šคํƒ€์ผ์„ ์ง€์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

.carousel-container {
  position: relative;
  width: 536px;
  height: 354px;
  overflow: hidden;
}

.carousel-slide {
  display: flex;
  height: 100%;
}

.carousel-slide img {
  width: 536px;
  height: 354px;
  object-fit: cover;
}

.carousel-prev,
.carousel-next {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 50px;
  height: 50px;
  background-color: skyblue;
  color: white;
  border: none;
  border-radius: 30%;
  outline: none;
  cursor: pointer;
}

.carousel-prev {
  left: 0;
}

.carousel-next {
  right: 0;
}

์•ž์„œ ๋ณด์—ฌ๋“œ๋ฆฐ ์บ๋Ÿฌ์…€ ์ฝ”๋“œ์˜ CSS ์Šคํƒ€์ผ์ž…๋‹ˆ๋‹ค.

  1. .carousel-container ํด๋ž˜์Šค์—๋Š” ์ƒ๋Œ€ ์œ„์น˜๊ฐ€ ์ง€์ •๋˜์–ด ๋ฐฐ์น˜๋œ ํ•˜์œ„ ์š”์†Œ๊ฐ€ ์ด ์ปจํ…Œ์ด๋„ˆ์™€ ๊ด€๋ จํ•˜์—ฌ ๋ฐฐ์น˜๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ์บ๋Ÿฌ์…€์˜ ํฌ๊ธฐ๋ฅผ ์ œํ•œํ•˜๊ธฐ ์œ„ํ•ด ๋„ˆ๋น„์™€ ๋†’์ด๊ฐ€ ๊ณ ์ •๋˜์–ด ์žˆ์œผ๋ฉฐ overflow: hidden์€ ์ปจํ…Œ์ด๋„ˆ ํฌ๊ธฐ๋ฅผ ์ดˆ๊ณผํ•˜๋Š” ์ฝ˜ํ…์ธ ๋ฅผ ์ˆจ๊ธฐ๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  3. .carousel-slide ํด๋ž˜์Šค๋Š” ์ด๋ฏธ์ง€๊ฐ€ ์ผ๋ ฌ๋กœ ํ‘œ์‹œ๋˜๋„๋ก flex, ์ปจํ…Œ์ด๋„ˆ ๋†’์ด๋ฅผ ์ฑ„์šฐ๋„๋ก height 100%๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.
  4. .carousel-slide img ํด๋ž˜์Šค๋Š” ๋ชจ๋“  ์ด๋ฏธ์ง€๊ฐ€ ๋™์ผํ•œ ํฌ๊ธฐ๋ฅผ ๊ฐ–๋„๋ก ๊ณ ์ •๋œ ๋„ˆ๋น„์™€ ๋†’์ด๊ฐ€ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. object-fit: cover๋Š” ์ด๋ฏธ์ง€๊ฐ€ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์™„์ „ํžˆ ๋ฎ๋„๋ก ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  5. .carousel-prev ๋ฐ .carousel-next ํด๋ž˜์Šค๋Š” carousel ์ปจํ…Œ์ด๋„ˆ์— ์ƒ๋Œ€์ ์œผ๋กœ ๋ฐฐ์น˜๋˜๋„๋ก position: absolute๋กœ ์Šคํƒ€์ผ์ด ์ง€์ •๋ฉ๋‹ˆ๋‹ค.
  6. ์ƒ๋‹จ์€ 50%๋กœ ์„ค์ •๋˜๊ณ  transform: translateY(-50%)๋Š” ๋ฒ„ํŠผ์„ ์ˆ˜์ง์œผ๋กœ ์ค‘์•™์— ๋ฐฐ์น˜ํ•ฉ๋‹ˆ๋‹ค.

โธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ

์ด์ œ ์บ๋Ÿฌ์…€์ด ์ž‘๋™ํ•˜๋„๋ก ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

const carouselSlide = document.querySelector(".carousel-slide");
const carouselImages = document.querySelectorAll(".carousel-slide img");

const prevButton = document.querySelector(".carousel-prev");
const nextButton = document.querySelector(".carousel-next");

let counter = 1;
const size = 536;

carouselSlide.style.transform = `translateX(${-size}px)`;

nextButton.addEventListener("click", () => {
  if (counter >= carouselImages.length - 1) return;
  carouselSlide.style.transition = "transform 0.4s ease-in-out";
  counter++;
  carouselSlide.style.transform = `translateX(${-size * counter}px)`;
});

prevButton.addEventListener("click", () => {
  if (counter <= 0) return;
  carouselSlide.style.transition = "transform 0.4s ease-in-out";
  counter--;
  carouselSlide.style.transform = `translateX(${-size * counter}px)`;
});

carouselSlide.addEventListener("transitionend", () => {
  if (carouselImages[counter].id === "lastClone") {
    carouselSlide.style.transition = "none";
    counter = carouselImages.length - 2;
    carouselSlide.style.transform = `translateX(${-size * counter}px)`;
  }

  if (carouselImages[counter].id === "firstClone") {
    carouselSlide.style.transition = "none";
    counter = carouselImages.length - counter;
    carouselSlide.style.transform = `translateX(${-size * counter}px)`;
  }
});

์ด ์ฝ”๋“œ๋Š” ์บ๋Ÿฌ์…€์˜ ๋™์ž‘์„ ์ œ์–ดํ•˜๊ณ  ํƒ์ƒ‰ ๋ฒ„ํŠผ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฏธ์ง€๋ฅผ ์™ผ์ชฝ์ด๋‚˜ ์˜ค๋ฅธ์ชฝ์œผ๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ์ฝ”๋“œ์˜ ์ฒ˜์Œ ๋‘ ์ค„์€ ์บ๋Ÿฌ์…€ ์Šฌ๋ผ์ด๋“œ ์ปจํ…Œ์ด๋„ˆ์™€ ๊ทธ ์•ˆ์˜ ๋ชจ๋“  ์ด๋ฏธ์ง€๋ฅผ ์„ ํƒํ•˜๊ณ  ๋ณ€์ˆ˜์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

  2. ๋‹ค์Œ ๋‘ ์ค„์€ ๊ฐ๊ฐ ์ด์ „ ๋ฒ„ํŠผ๊ณผ ๋‹ค์Œ ๋ฒ„ํŠผ์„ ์„ ํƒํ•˜์—ฌ ๋ณ€์ˆ˜์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

  3. ์นด์šดํ„ฐ ๋ณ€์ˆ˜๋Š” 1๋กœ ์ดˆ๊ธฐํ™”๋˜๊ณ  ํฌ๊ธฐ ๋ณ€์ˆ˜๋Š” ์บ๋Ÿฌ์…€ ์ปจํ…Œ์ด๋„ˆ์˜ ๋„ˆ๋น„๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.

  4. ์บ๋Ÿฌ์…€ ์Šฌ๋ผ์ด๋“œ๋Š” ํ•œ ์ด๋ฏธ์ง€ ๋„ˆ๋น„๋งŒํผ ์™ผ์ชฝ์œผ๋กœ ์ด๋™ํ•˜์—ฌ ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๊ฐ€ ์ฒ˜์Œ์— ๋ณด์ž…๋‹ˆ๋‹ค.

  5. ๋‹ค์Œ ๋ฒ„ํŠผ ํด๋ฆญ์„ ์ˆ˜์‹ ํ•˜๊ธฐ ์œ„ํ•ด nextButton ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
    ์นด์šดํ„ฐ ๋ณ€์ˆ˜๊ฐ€ ์ด๋ฏธ์ง€์˜ ๋์— ๋„๋‹ฌํ–ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ ์นด์šดํ„ฐ ๋ณ€์ˆ˜๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๊ณ  ์บ๋Ÿฌ์…€ ์Šฌ๋ผ์ด๋“œ๋ฅผ ํ•œ ์ด๋ฏธ์ง€ ๋„ˆ๋น„๋งŒํผ ์™ผ์ชฝ์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

  6. ์ด์ „ ๋ฒ„ํŠผ์˜ ํด๋ฆญ์„ ์ˆ˜์‹ ํ•˜๊ธฐ ์œ„ํ•ด prevButton ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

  7. ์นด์šดํ„ฐ ๋ณ€์ˆ˜๊ฐ€ ์ด๋ฏธ์ง€์˜ ์‹œ์ž‘ ๋ถ€๋ถ„์— ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ ์นด์šดํ„ฐ ๋ณ€์ˆ˜๋ฅผ ๊ฐ์†Œ์‹œํ‚ค๊ณ  ์บ๋Ÿฌ์…€ ์Šฌ๋ผ์ด๋“œ๋ฅผ ํ•œ ์ด๋ฏธ์ง€ ๋„ˆ๋น„๋งŒํผ ์˜ค๋ฅธ์ชฝ์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

  8. carouselSlide ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋Š” carouselSlide์˜ CSS ์ „ํ™˜์ด ์™„๋ฃŒ๋  ๋•Œ ์‹คํ–‰๋˜๋Š” transitionend ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์‹ ํ•ฉ๋‹ˆ๋‹ค.

  9. ํ˜„์žฌ ์ด๋ฏธ์ง€๊ฐ€ ๋งˆ์ง€๋ง‰ ๋ณต์ œ๋ณธ์ด๋ฉด ์ „ํ™˜์ด ์ œ๊ฑฐ๋˜๊ณ  ์นด์šดํ„ฐ๋Š” ๋งˆ์ง€๋ง‰์—์„œ ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€ ์œ„์น˜๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.

  10. ํ˜„์žฌ ์ด๋ฏธ์ง€๊ฐ€ ์ฒซ ๋ฒˆ์งธ ๋ณต์ œ๋ณธ์ด๋ฉด ์ „ํ™˜์ด ์ œ๊ฑฐ๋˜๊ณ  ์นด์šดํ„ฐ๊ฐ€ ๋งˆ์ง€๋ง‰ ์ด๋ฏธ์ง€ ์œ„์น˜๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.

์œ„ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ๋‹ค์–‘ํ•œ ๋””์ž์ธ์˜ ๋‹ค๋ฅธ ์บ๋Ÿฌ์…€์„ ์ œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โœ… ๊ฒฐ๊ณผ๋ฌผ

profile
#UXUI #์ฝ”๋ฆฐ์ด

1๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2023๋…„ 4์›” 11์ผ

์•ˆ๋…•ํ•˜์„ธ์š”, ์ œ๋กœ๋ฒ ์ด์Šค ํ”„๋ก ํŠธ์—”๋“œ์Šค์ฟจ ๋ฉ˜ํ† ์ž…๋‹ˆ๋‹ค. ์ž‘์„ฑํ•ด์ฃผ์‹  ๊ธ€ ์ž˜ ์ฝ์—ˆ์Šต๋‹ˆ๋‹ค!

  • ๊ตฌํ˜„ ๋กœ์ง์„ ๋‹จ๊ณ„๋ณ„๋กœ ์ž์„ธํ•˜๊ฒŒ ์„ค๋ช…ํ•ด์ฃผ์‹  ์ ์ด ์ข‹์•˜์Šต๋‹ˆ๋‹ค.
  • ํ—› ์ œ๊ฐ€ ๋ดค์„๋•Œ๋Š” ๊ฒฐ๊ณผ๋ฌผ์ด ๊นŒ๋งŒ ํ™”๋ฉด์œผ๋กœ ์•„๋ฌด๊ฒƒ๋„ ์•ˆ๋ณด์ด๋Š” ๊ฒƒ ๊ฐ™์€๋ฐ์š”..!ใ…Žใ…Ž ๊ฒฐ๊ณผ๋ฌผ ๋ณด๊ณ ์‹ถ์—ˆ๋Š”๋ฐ ์•„์‰ฝ๋„ค์š”... ํ•œ๋ฒˆ ๋” ํ™•์ธํ•ด๋ณด์‹œ๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค!
  • ์บ๋Ÿฌ์…€์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์ •๋ง ๋‹ค์–‘ํ•˜๊ณ , ๊ตฌ๊ธ€๋ง์„ ํ•ด๋ณด๋ฉด ๋‹ค์–‘ํ•œ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์ด ๋‚˜์˜ค๋Š”๋ฐ์š”, ์ฐธ๊ณ ํ•˜์‹  ์•„์ด๋””์–ด๊ฐ€ ์žˆ์„ ๊ฒƒ ๊ฐ™๊ณ , ์ฐธ๊ณ ํ•˜์‹  ์ž๋ฃŒ๊ฐ€ ์žˆ๋‹ค๋ฉด ์ฐธ๊ณ ์ž๋ฃŒ๋ฅผ ๋ช…์‹œํ•ด์„œ ์ฃผ๋„์ ์œผ๋กœ ํ•™์Šตํ•˜๊ณ  ๊ณ ๋ฏผํ•˜์‹  ๋ถ€๋ถ„์ด ๋“œ๋Ÿฌ๋‚˜๋„๋ก ์ž‘์„ฑํ•ด์ฃผ๋Š” ๊ฒƒ๋„ ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
  • ํ˜น์‹œ ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด, ์ด๋Ÿฌํ•œ ์ฝ”๋“œ์™€ ๊ตฌํ˜„ ์œ„์ฃผ์˜ ๊ธ€์—์„œ๋„ ์ž‘์„ฑ์ž๋ถ„์˜ ์ƒ๊ฐ์ด๋‚˜ ๋Š๋‚€์ , ์˜๊ฒฌ์ด ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์‚ฌ์‹ค ์ด๋ฏธ ์•Œ๋ ค์ง„ ์•„์ด๋””์–ด๋“ค์ด ๋งŽ๊ธฐ ๋•Œ๋ฌธ์—, ์ž‘์„ฑ์ž๋ถ„๊ป˜์„œ ์ด๋ฅผ ์ •๋ง ๋ณธ์ธ์˜ ๊ฒƒ์œผ๋กœ ๋งŒ๋“ค๊ณ  ์ง์ ‘ ์ฝ”๋“œ๋ฅผ ์งœ๋ฉด์„œ ํ•™์Šตํ•˜์‹  ๊ทธ ๊ณผ์ •์ด ์กฐ๊ธˆ ๋” ๋Š๊ปด์ง€๋„๋ก ์ž‘์„ฑ๋˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์–ด์„œ์š”..!)

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค :)

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ