UI Code Lab

πŸ“ 라이브러리 없이 슀크둀 λ“±μž₯ μ• λ‹ˆλ©”μ΄μ…˜ λ§Œλ“€κΈ° – μ‹€μ „ μ›Ή UI 예제 λ³Έλ¬Έ

μžλ°”μŠ€ν¬λ¦½νŠΈUI

πŸ“ 라이브러리 없이 슀크둀 λ“±μž₯ μ• λ‹ˆλ©”μ΄μ…˜ λ§Œλ“€κΈ° – μ‹€μ „ μ›Ή UI 예제

πŸ―κΏ€μƒμ΄πŸ 2025. 7. 17. 09:30

라이브러리 없이 슀크둀 λ“±μž₯ μ• λ‹ˆλ©”μ΄μ…˜ λ§Œλ“€κΈ° – μ‹€μ „ μ›Ή UI 예제

 

 

 

졜근 μ›Ή UIμ—μ„œ μŠ€ν¬λ‘€μ— λ°˜μ‘ν•΄ μš”μ†Œκ°€

μžμ—°μŠ€λŸ½κ²Œ λ‚˜νƒ€λ‚˜λŠ” μΈν„°λž™μ…˜μ€

μ‚¬μš©μžμ—κ²Œ 생동감을 μ€λ‹ˆλ‹€.

 

보톡 GSAP, ScrollReveal 같은 라이브러리λ₯Ό ν™œμš©ν•˜κ³€ ν•˜μ§€λ§Œ,

μ΄λ²ˆμ—” 바닐라 JS와 CSS만으둜

κ°„κ²°ν•˜κ²Œ κ΅¬ν˜„ν•˜λŠ” 방법을 μ•Œμ•„λ΄…λ‹ˆλ‹€.

 

πŸ”§ κ΅¬ν˜„ λͺ©ν‘œ

  • 슀크둀 μœ„μΉ˜μ— 따라 μš”μ†Œ λ“±μž₯
  • μžμ—°μŠ€λŸ¬μš΄ μ• λ‹ˆλ©”μ΄μ…˜ 효과
  • 라이브러리 없이 순수 HTML/CSS/JS μ‚¬μš©

 

✨ μ™„μ„±λœ UI μ‹œμ—° 이미지

(πŸ’‘μ˜ˆμ‹œ μ΄λ―Έμ§€λ‘œ 제곡 κ°€λŠ₯ – 이미지 생성이 ν•„μš”ν•œ 경우 μ•Œλ €μ£Όμ„Έμš”!)

  • μ‚¬μš©μžκ°€ 화면을 μ•„λž˜λ‘œ μŠ€ν¬λ‘€ν•˜λ©΄, 각 μ½˜ν…μΈ  블둝이 순차적으둜 λΆ€λ“œλŸ½κ²Œ λ“±μž₯ν•©λ‹ˆλ‹€.
  • ν•˜λ‹¨μœΌλ‘œ 갈수둝 μš”μ†Œκ°€ μ§€μ—° λ“±μž₯ν•˜λ©΄μ„œ 집쀑도λ₯Ό μœ λ„ν•©λ‹ˆλ‹€.

 

🧩 μ½”λ“œ κ΅¬ν˜„

 

βœ… HTML ꡬ쑰

 
<section class="section">
  <h2 class="fade-in">μ„Ήμ…˜ 제λͺ©</h2>
  <p class="fade-in">이곳에 상세 μ„€λͺ…이 λ“€μ–΄κ°‘λ‹ˆλ‹€.</p>
</section>

 

🎨 CSS μŠ€νƒ€μΌ

 
.fade-in {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}
.fade-in.visible {
  opacity: 1;
  transform: translateY(0);
}

 

🧠 μžλ°”μŠ€ν¬λ¦½νŠΈ

 
const faders = document.querySelectorAll('.fade-in');

const handleScroll = () => {
  faders.forEach(el => {
    const rect = el.getBoundingClientRect();
    if (rect.top < window.innerHeight - 100) {
      el.classList.add('visible');
    }
  });
};

window.addEventListener('scroll', handleScroll);
window.addEventListener('load', handleScroll); // λ‘œλ”© μ‹œμ—λ„ 체크

 

πŸ›  μ‹€μ „ 팁 & ν™•μž₯ 사둀

κΈ°λŠ₯ μ„€λͺ…
λ”œλ ˆμ΄ μΆ”κ°€ λ“±μž₯ μˆœμ„œ μ§€μ •ν•  λ•Œ transition-delay둜 μš”μ†Œ κ°„ μ‹œκ°„μ°¨ 쑰절
λ‹€μ–‘ν•œ λ“±μž₯ 방식 translateY λŒ€μ‹  scale, rotate, opacity, clip-path λ“± λ‹€μ–‘ν•œ CSS ν™œμš© κ°€λŠ₯
Intersection Observer둜 μ„±λŠ₯ ν–₯상 λ§Žμ€ μš”μ†Œκ°€ μžˆμ„ 경우 μ„±λŠ₯ μ €ν•˜ λ°©μ§€
λ°˜μ‘ν˜• λŒ€μ‘ λͺ¨λ°”μΌμ—μ„œ μš”μ†Œ 크기 및 λ“±μž₯ 타이밍 μ‘°μ • ν•„μš”

 

πŸš€ 싀무 적용 μ˜ˆμ‹œ

 

✳️ 포트폴리였 μ›Ήμ‚¬μ΄νŠΈ

각 ν”„λ‘œμ νŠΈ μΉ΄λ“œκ°€ 슀크둀 μ‹œ μ„œμ„œνžˆ λ“±μž₯ν•΄ 전문성이 κ°•μ‘°λ©λ‹ˆλ‹€.

 

πŸ›οΈ μ œν’ˆ 상세 νŽ˜μ΄μ§€

νŠΉμ§•, 이미지, ν›„κΈ° μ˜μ—­μ΄ 순차적으둜 λ“±μž₯ν•˜λ©΄ μ‚¬μš©μžκ°€ μ‰½κ²Œ λͺ°μž…ν•©λ‹ˆλ‹€.

 

πŸ§‘‍🏫 ꡐ윑 μ½˜ν…μΈ  ν”Œλž«νΌ

κ°•μ˜ μ†Œκ°œ, μ„Ήμ…˜ μš”μ•½ 등이 λ“±μž₯ μ• λ‹ˆλ©”μ΄μ…˜μœΌλ‘œ μ‚¬μš©μž μ‹œμ„ μ„ μ§‘μ€‘μ‹œν‚΄

 

 

 

πŸ” λ“±μž₯ μ‹œμ  νŒλ‹¨μ„ 더 μ •λ°€ν•˜κ²Œ ν•˜κΈ°

λ‹¨μˆœνžˆ getBoundingClientRect().top 만으둜 λ“±μž₯ μœ„μΉ˜λ₯Ό μ²΄ν¬ν•˜λ©΄,

μš”μ†Œκ°€ μ§€λ‚˜μΉ˜κ²Œ λΉ λ₯΄κ²Œ λ‚˜νƒ€λ‚˜κ±°λ‚˜ μ‚¬μš©μž ν™˜κ²½μ— 따라 λ°˜μ‘μ„±μ΄ λ–¨μ–΄μ§ˆ 수 μžˆμ–΄μš”.

κ·Έλž˜μ„œ λ“±μž₯ 트리거 μ‹œμ μ„ μ»€μŠ€ν„°λ§ˆμ΄μ§•ν•˜λŠ” 방식도 μ†Œκ°œν•΄λ³Όκ²Œμš”:

 

 
const triggerPoint = window.innerHeight * 0.8; // ν™”λ©΄ 80% μœ„μΉ˜ κΈ°μ€€
if (rect.top < triggerPoint) {
  el.classList.add('visible');
}

 

πŸ’‘ μ΄λ ‡κ²Œ ν•˜λ©΄ μ‚¬μš©μžκ°€ μ½˜ν…μΈ μ— 집쀑할 수 μžˆλŠ” 타이밍에 λ“±μž₯ν•˜κ²Œ 되고,

λͺ¨λ°”μΌμ—μ„œλ„ λ”μš± λΆ€λ“œλŸ¬μš΄ UXλ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€.

 

πŸŽ› CSS λ“±μž₯ 효과 닀듬기

 

기본적인 opacity + translateY 외에도 λ‹€μŒμ²˜λŸΌ

μ• λ‹ˆλ©”μ΄μ…˜μ„ λ‹€μ–‘ν™”ν•  수 μžˆμ–΄μš”:

 
.fade-in {
  clip-path: inset(0 0 100% 0);
  transition: clip-path 0.6s ease, opacity 0.6s ease;
}
.fade-in.visible {
  clip-path: inset(0 0 0% 0);
  opacity: 1;
}

 

πŸ”Ή μœ„ μ˜ˆμ œλŠ” μš”μ†Œκ°€ μŠ¬λΌμ΄λ“œλ‘œ 컀버가 열리듯이 λ“±μž₯ν•˜λŠ” λŠλ‚Œμ„ μ€λ‹ˆλ‹€.

μ‹œκ°μ μœΌλ‘œ λ”μš± μ„Έλ ¨λ˜κ²Œ 보이죠.

 

⚑ Intersection Observerλ₯Ό ν™œμš©ν•œ κ³ κΈ‰ 버전

 

μ„±λŠ₯ μ΅œμ ν™”μ™€ λ”λΆˆμ–΄ 비동기적 감지 방식을 μ“°λ©΄

수백 개의 μš”μ†Œκ°€ μžˆμ–΄λ„ λΆ€λ“œλŸ½κ²Œ μ²˜λ¦¬λ©λ‹ˆλ‹€:

 
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.classList.add('visible');
      observer.unobserve(entry.target);
    }
  });
}, { threshold: 0.3 });

document.querySelectorAll('.fade-in').forEach(el => {
  observer.observe(el);
});

 

☝ 이 방식은 μš”μ†Œκ°€ 일정 λΉ„μœ¨ 이상 보일 λ•Œλ§Œ μ²˜λ¦¬ν•˜λ―€λ‘œ,

λ¦¬μ†ŒμŠ€ λ‚­λΉ„ 없이 μ •ν™•ν•œ 타이밍에 λ“±μž₯ν•©λ‹ˆλ‹€.

 

πŸ’¬ μ‚¬μš©μž λ°˜μ‘κ³Ό ν…ŒμŠ€νŠΈ 팁

  • λ“±μž₯ μˆœμ„œλ₯Ό ν…ŒμŠ€νŠΈν•  λ•ŒλŠ” 개발자 λ„κ΅¬μ—μ„œ 슀크둀 속도 μ‘°μ ˆν•˜λ©΄μ„œ 확인
  • λͺ¨λ°”μΌμ—μ„œλŠ” 가급적 translateY λ²”μœ„λ₯Ό 쀄여야 μ• λ‹ˆλ©”μ΄μ…˜μ΄ κ³Όν•˜μ§€ μ•Šκ²Œ λ³΄μž„
  • μ½˜ν…μΈ  λΈ”λ‘λ³„λ‘œ transition-delay μ‘°μ ˆν•΄ 더 μ •λ°€ν•œ μ œμ–΄ κ°€λŠ₯

 

🧾 λ§ˆλ¬΄λ¦¬ν•˜λ©°

슀크둀 μ• λ‹ˆλ©”μ΄μ…˜μ€ λ‹¨μˆœν•œ μ‹œκ° 효과λ₯Ό λ„˜μ–΄μ„œ,

μ‚¬μš©μžμ˜ λͺ°μž…도와 μ½˜ν…μΈ  집쀑λ ₯을 λ†’μ΄λŠ” κ°•λ ₯ν•œ λ„κ΅¬μž…λ‹ˆλ‹€.

이번 κΈ€μ—μ„œλŠ” GSAPμ΄λ‚˜ μ™ΈλΆ€ 라이브러리 없이도,

바닐라 μžλ°”μŠ€ν¬λ¦½νŠΈμ™€ CSSλ§ŒμœΌλ‘œλ„

μΆ©λΆ„νžˆ λΆ€λ“œλŸ¬μš΄ UIλ₯Ό κ΅¬ν˜„ν•  수 μžˆλ‹€λŠ” κ°€λŠ₯성을

λ³΄μ—¬λ“œλ ΈμŠ΅λ‹ˆλ‹€.

 

이 방식은 비ꡐ적 가볍고 μœ μ—°ν•˜κ²Œ μ μš©ν•  수 있기 λ•Œλ¬Έμ—,

포트폴리였, μ œν’ˆ μ†Œκ°œ, λΈ”λ‘œκ·Έ λ“± λ‹€μ–‘ν•œ νŽ˜μ΄μ§€μ—μ„œ

μ‹œλ„ν•΄λ³Ό 수 μžˆμ–΄μš”. πŸ‘¨‍πŸ’»

 

μ•žμœΌλ‘œ 더 λ‚˜μ€ μ‚¬μš©μž κ²½ν—˜μ„ μœ„ν•΄ 직접 ꡬ쑰λ₯Ό μ„€κ³„ν•˜κ³ 

μ»€μŠ€ν„°λ§ˆμ΄μ§•ν•΄λ³΄μ„Έμš”. πŸ“Œ

 

μž‘μ€ μΈν„°λž™μ…˜ ν•˜λ‚˜λ‘œ μ‚¬μ΄νŠΈμ˜ 인상이

λ‹¬λΌμ§ˆ 수 μžˆλ‹€λŠ” 점을 κΌ­ κΈ°μ–΅ν•΄μ£Όμ„Έμš”!

 

λ‹€μŒ κΈ€μ—μ„œλŠ” 슀크둀 μœ„μΉ˜μ— 따라 UI μš”μ†Œκ°€ κ³ μ •λ˜λŠ”
Sticky Scroll UI 에 λŒ€ν•΄ μ•Œμ•„λ³Ό μ˜ˆμ •μ΄μ—μš”.
더 μŠ€λ§ˆνŠΈν•˜κ³  직관적인 λ ˆμ΄μ•„μ›ƒμ„ λ§Œλ“œλŠ” 방법이
κΆκΈˆν•˜λ‹€λ©΄ κΈ°λŒ€ν•΄μ£Όμ„Έμš”!