가이드/CSS
touch_app

CSS 호버 효과 15가지 예제

좋은 호버 효과는 세 가지를 합니다: 사용자에게 요소가 인터랙티브함을 알리고, 주의를 보상하고, 모바일에서 방해되지 않게 합니다. 이 모음은 버튼, 카드, 이미지, 아이콘용 현대적이고 접근 가능한 복사·붙여넣기 패턴 15가지를 다룹니다 — 모두 순수 CSS, JavaScript 없음.

2026년 4월 · 10분 분량

코드 전 원칙

호버 효과를 전문적으로 보이게 하는 세 가지 규칙:

  • 속성을 즉시 바꾸지 말고 항상 transition으로 애니메이션화하세요. 150–250ms 전환은 의도적으로 느껴지고; 0ms는 망가진 느낌입니다.
  • 움직임에는 transformopacity를 사용하세요 — GPU 가속됩니다. 레이아웃 재계산을 트리거하는 width, height, margin, top 애니메이션은 피하세요.
  • prefers-reduced-motion을 존중하세요 — 시스템 전반에서 모션을 비활성화한 사용자는 애니메이션을 원하지 않습니다.

1. 호버 시 리프트 (카드)

.card {
  transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1),
              box-shadow 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 12px 32px -8px rgba(0, 0, 0, 0.25);
}

2. 버튼 채우기 슬라이드

.btn-fill {
  position: relative;
  overflow: hidden;
  color: #7c5cfc;
  border: 2px solid #7c5cfc;
  padding: 0.75rem 1.5rem;
  transition: color 0.3s ease;
  z-index: 0;
}
.btn-fill::before {
  content: '';
  position: absolute; inset: 0;
  background: #7c5cfc;
  transform: translateX(-100%);
  transition: transform 0.3s ease;
  z-index: -1;
}
.btn-fill:hover { color: #fff; }
.btn-fill:hover::before { transform: translateX(0); }

3. 밑줄 슬라이드 (링크)

.link-underline {
  position: relative;
  text-decoration: none;
}
.link-underline::after {
  content: '';
  position: absolute;
  left: 0; bottom: -2px;
  width: 100%; height: 2px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.3s ease;
}
.link-underline:hover::after { transform: scaleX(1); }

4. 이미지 줌 (컨테이너 내부)

.img-zoom { overflow: hidden; border-radius: 12px; }
.img-zoom img { transition: transform 0.5s ease; }
.img-zoom:hover img { transform: scale(1.08); }

5. 발광 윤곽선 (접근 가능한 포커스 링)

.btn-glow { transition: box-shadow 0.25s ease; }
.btn-glow:hover, .btn-glow:focus-visible {
  box-shadow: 0 0 0 4px rgba(124, 92, 252, 0.3);
  outline: none;
}

6. 아이콘 회전

.icon-rotate {
  display: inline-block;
  transition: transform 0.4s ease;
}
.icon-rotate:hover { transform: rotate(90deg); }

7. 화살표 슬라이드 앞으로

.link-arrow .arrow {
  display: inline-block;
  transition: transform 0.2s ease;
}
.link-arrow:hover .arrow { transform: translateX(4px); }

8. 그라디언트 시프트

.btn-gradient {
  background: linear-gradient(135deg, #7c5cfc, #ec4899, #7c5cfc);
  background-size: 200% 200%;
  background-position: 0% 50%;
  transition: background-position 0.5s ease;
  color: #fff;
  padding: 0.75rem 1.5rem;
  border-radius: 8px;
}
.btn-gradient:hover { background-position: 100% 50%; }

9. 틸트 (3D 원근법)

.tilt {
  transform-style: preserve-3d;
  perspective: 1000px;
  transition: transform 0.3s ease;
}
.tilt:hover {
  transform: perspective(1000px) rotateX(4deg) rotateY(-4deg) translateZ(10px);
}

10. 샤인 스윕 (프리미엄)

.shine { position: relative; overflow: hidden; }
.shine::after {
  content: '';
  position: absolute;
  top: 0; left: -100%;
  width: 50%; height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
  transform: skewX(-20deg);
  transition: left 0.6s ease;
}
.shine:hover::after { left: 150%; }

11. 테두리 그리기

.border-draw {
  position: relative;
  padding: 1rem 2rem;
}
.border-draw::before {
  content: '';
  position: absolute;
  inset: 0;
  border: 2px solid transparent;
  width: 0; height: 100%;
  border-top-color: #7c5cfc;
  border-left-color: #7c5cfc;
  transition: width 0.3s ease, height 0.3s ease 0.3s;
}
.border-draw:hover::before { width: 100%; }

12. 스케일 & 그림자 콤보

.scale-shadow { transition: transform 0.3s, box-shadow 0.3s; }
.scale-shadow:hover {
  transform: scale(1.03);
  box-shadow: 0 20px 40px -10px rgba(0, 0, 0, 0.3);
}

13. 캡션 슬라이드 업 (이미지 오버레이)

.caption-slide { position: relative; overflow: hidden; }
.caption-slide .caption {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 1rem;
  background: rgba(0, 0, 0, 0.75);
  color: #fff;
  transform: translateY(100%);
  transition: transform 0.3s ease;
}
.caption-slide:hover .caption { transform: translateY(0); }

14. 형제 요소 채도 감소

.grid .item { transition: opacity 0.3s, filter 0.3s; }
.grid:has(.item:hover) .item:not(:hover) {
  opacity: 0.5;
  filter: saturate(0.5);
}

15. 리플 확장 (머티리얼 스타일)

.ripple { position: relative; overflow: hidden; }
.ripple::after {
  content: '';
  position: absolute;
  left: 50%; top: 50%;
  width: 0; height: 0;
  border-radius: 50%;
  background: rgba(124, 92, 252, 0.3);
  transform: translate(-50%, -50%);
  transition: width 0.5s ease, height 0.5s ease;
}
.ripple:hover::after { width: 300%; height: 300%; }

자주 묻는 질문

호버 효과가 모바일에서 작동하나요?
대부분 작동하지 않습니다 — 모바일에는 호버 상태가 없습니다. 탭이 잠시 :hover를 트리거한 후 탐색하므로 종종 시각적 결함이 발생합니다. @media (hover: hover)를 사용하여 호버 효과를 호버를 지원하는 기기로 범위를 좁히고 모바일 피드백을 위해 일치하는 :active 상태를 추가하세요.
이상적인 전환 지속 시간은?
대부분의 호버에 150–300ms. 100ms 미만은 즉시처럼 느껴지고(인지된 애니메이션 없음). 400ms 이상은 느릿느릿 — 애니메이션이 끝날 때까지 사용자는 이미 이동했습니다. 샤인이나 리플 같은 장식 효과의 경우 400–600ms가 허용됩니다.
ease-in-out을 사용해야 하나요, 사용자 정의 곡선?
cubic-bezier(0.4, 0, 0.2, 1)(머티리얼의 표준 ease)이 가장 안전한 기본값 — 빠르게 시작하고 부드럽게 끝납니다. ease-out은 대부분의 경우에 작동합니다.
상위 요소가 호버될 때 자식 요소에 호버하는 방법은?
후손 선택자 사용: .parent:hover .child { ... }. 마우스가 .parent 어디에 있든 적용되며, 여기에는 .child가 포함됩니다.
호버 효과가 깜박이거나 떨리는 이유는?
두 가지 일반적인 원인: (1) 호버가 요소의 크기에 영향을 주는 속성(예: border-width)을 변경하여 레이아웃 시프트를 일으키고 커서가 잠시 요소를 떠남; (2) transition이 없어 호버 진입 또는 종료 시 변경이 즉시 발생.