관리 메뉴

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

[해피CGI][cgimall] 3D느낌의 이미지 슬라이드 Voyage Slider 본문

웹프로그램밍 자료실/HTML 자료

[해피CGI][cgimall] 3D느낌의 이미지 슬라이드 Voyage Slider

해피CGI윤실장 2025. 7. 31. 09:35



슬라이드 버튼을 클릭하면 이미지와 텍스트가 변경되는 3D 느낌의 이미지 슬라이드입니다.

이미지를 변경하여 다양하게 응용 가능합니다.


HTML 구조

<div class="slider">

<button class="slider--btn slider--btn__prev">

 

<path d="m15 18-6-6 6-6" />

</svg>

</button>

 

<div class="slides__wrapper">

<div class="slides">

<!-- slide 1 -->

<div class="slide" data-current>

<div class="slide__inner">

<div class="slide--image__wrapper">

Image 1

</div>

</div>

</div>

 

 

<!-- slide 2 -->

<div class="slide" data-next>

<div class="slide__inner">

<div class="slide--image__wrapper">

<img class="slide--image" src="

https://devloop01.github.io/voyage-slider/images/machu-pichu.jpg" alt="Image 2" />

</div>

</div>

</div>

 

.
.
.

 



CSS 소스

@import url("https://api.fontshare.com/v2/css?f[]=archivo@100,200,300,400,500,750,700,800,900&f[]=clash-display@200,300,400,500,750,700&display=swap");

 

:root {

--slide-width: min(25vw, 300px);

--slide-aspect: 2 / 3;

 

--slide-transition-duration: 800ms;

--slide-transition-easing: ease;

 

--font-archivo: "Archivo", sans-serif;

--font-clash-display: "Clash Display", sans-serif;

}

 

* {

box-sizing: border-box;

margin: 0;

padding: 0;

}

 

html,

body {

width: 100%;

height: 100%;

}

 

body {

display: grid;

place-items: center;

overflow: hidden;

 

background: rgba(0, 0, 0, 0.787);

}

 

button {

border: none;

background: none;

cursor: pointer;

&:focus {

outline: none;

border: none;

}

}

 

/* ------------------------------------------------ */

/* -------------------- SLIDER -------------------- */

/* ------------------------------------------------ */

 

.slider {

width: calc(3 * var(--slide-width));

height: calc(2 * var(--slide-height));

display: flex;

align-items: center;

}

 

.slider--btn {

--size: 40px;

 

display: inline-flex;

justify-content: center;

align-items: center;

opacity: 0.7;

transition: opacity 250ms cubic-bezier(0.215, 0.61, 0.355, 1);

z-index: 999;

 

& svg {

width: var(--size);

height: var(--size);

stroke: white;

}

 

&:hover {

opacity: 1;

}

}

 

.slides__wrapper {

width: 100%;

height: 100%;

 

display: grid;

place-items: center;

 

& > * {

grid-area: 1 / -1;

}

}

.
.
.

 

JS 소스

import imagesLoaded from "https://esm.sh/imagesloaded";

 

console.clear();

 

// -------------------------------------------------

// ------------------ Utilities --------------------

// -------------------------------------------------

 

// Math utilities

const wrap = (n, max) => (n + max) % max;

const lerp = (a, b, t) => a + (b - a) * t;

 

// DOM utilities

const isHTMLElement = (el) => el instanceof HTMLElement;

 

const genId = (() => {

let count = 0;

return () => {

return (count++).toString();

};

})();

 

class Raf {

constructor() {

this.rafId = 0;

this.raf = this.raf.bind(this);

this.callbacks = [];

 

this.start();

}

 

start() {

this.raf();

}

 

stop() {

cancelAnimationFrame(this.rafId);

}

 

raf() {

this.callbacks.forEach(({ callback, id }) => callback({ id }));

this.rafId = requestAnimationFrame(this.raf);

}

 

add(callback, id) {

this.callbacks.push({ callback, id: id || genId() });

}

 

remove(id) {

this.callbacks = this.callbacks.filter((callback) => callback.id !== id);

}

}

 

class Vec2 {

constructor(x = 0, y = 0) {

this.x = x;

this.y = y;

}

 

set(x, y) {

this.x = x;

this.y = y;

}

 

lerp(v, t) {

this.x = lerp(this.x, v.x, t);

this.y = lerp(this.y, v.y, t);

}

}

 

const vec2 = (x = 0, y = 0) => new Vec2(x, y);

 

export function tilt(node, options) {

let { trigger, target } = resolveOptions(node, options);

 

let lerpAmount = 0.06;

 

const rotDeg = { current: vec2(), target: vec2() };

const bgPos = { current: vec2(), target: vec2() };

 

const update = (newOptions) => {

destroy();

({ trigger, target } = resolveOptions(node, newOptions));

init();

};

 

let rafId;

 

function ticker({ id }) {

rafId = id;

 

rotDeg.current.lerp(rotDeg.target, lerpAmount);

bgPos.current.lerp(bgPos.target, lerpAmount);

 

for (const el of target) {

el.style.setProperty("--rotX", rotDeg.current.y.toFixed(2) + "deg");

el.style.setProperty("--rotY", rotDeg.current.x.toFixed(2) + "deg");

 

el.style.setProperty("--bgPosX", bgPos.current.x.toFixed(2) + "%");

el.style.setProperty("--bgPosY", bgPos.current.y.toFixed(2) + "%");

}

}

 

.
.
.


해당 사이트로 이동해서 전체 소스를 확인하실 수 있습니다.

 

 

Comments