Tutorial css

CSS Animations

CSS Animations membuat website menjadi hidup dan interactive. Dengan animations, Anda dapat menambahkan gerakan yang smooth, feedback visual, dan pengalaman user yang lebih engaging tanpa JavaScript.

Mengapa CSS Animations?

Benefits of Animations

Better user experience - Visual feedback yang jelas
Attention guidance - Arahkan fokus user
Smooth interactions - Transisi yang natural
Modern feel - Website terasa contemporary
Performance - Hardware-accelerated di browser

When to Use Animations

  • Hover effects pada buttons dan links
  • Page transitions dan loading states
  • Form validation feedback
  • Content reveals dan scroll animations
  • Micro-interactions untuk better UX

CSS Transitions

Basic Transition

.button {
  background-color: #007bff;
  color: white;
  padding: 12px 24px;
  border: none;
  border-radius: 6px;
  cursor: pointer;

  /* Transition property */
  transition: background-color 0.3s ease;
}

.button:hover {
  background-color: #0056b3; /* Smooth color change */
}

Transition Properties

.element {
  /* Shorthand: property duration timing-function delay */
  transition: all 0.3s ease-in-out 0.1s;

  /* Or individual properties */
  transition-property: background-color, transform, opacity;
  transition-duration: 0.3s, 0.5s, 0.2s;
  transition-timing-function: ease, ease-out, linear;
  transition-delay: 0s, 0.1s, 0.2s;
}

Transition Timing Functions

.timing-examples {
  /* Built-in functions */
  transition: transform 0.3s ease; /* Slow start & end */
  transition: transform 0.3s ease-in; /* Slow start */
  transition: transform 0.3s ease-out; /* Slow end */
  transition: transform 0.3s ease-in-out; /* Slow start & end */
  transition: transform 0.3s linear; /* Constant speed */

  /* Custom cubic-bezier */
  transition: transform 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
  /* Bouncy effect */
}

Multi-Property Transitions

.card {
  background-color: white;
  transform: translateY(0);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  opacity: 1;

  /* Multiple transitions */
  transition: transform 0.3s ease, box-shadow 0.3s ease,
    background-color 0.2s ease;
}

.card:hover {
  transform: translateY(-5px);
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.15);
  background-color: #f8f9fa;
}

CSS Keyframe Animations

Basic Keyframe Animation

/* Define animation */
@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Apply animation */
.fade-in-element {
  animation: fadeIn 0.6s ease-out;
}

Complex Keyframe Animation

@keyframes bounceIn {
  0% {
    opacity: 0;
    transform: scale(0.3);
  }
  50% {
    opacity: 1;
    transform: scale(1.05);
  }
  70% {
    transform: scale(0.9);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

.bounce-element {
  animation: bounceIn 0.8s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}

Animation Properties

.animated-element {
  /* Shorthand: name duration timing-function delay iteration-count direction fill-mode play-state */
  animation: slideIn 0.5s ease-out 0.2s 1 normal forwards running;

  /* Or individual properties */
  animation-name: slideIn;
  animation-duration: 0.5s;
  animation-timing-function: ease-out;
  animation-delay: 0.2s;
  animation-iteration-count: 1; /* infinite for loop */
  animation-direction: normal; /* reverse, alternate */
  animation-fill-mode: forwards; /* backwards, both */
  animation-play-state: running; /* paused */
}

Common Animation Patterns

Fade Animations

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes fadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(30px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes fadeInScale {
  from {
    opacity: 0;
    transform: scale(0.8);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

Slide Animations

@keyframes slideInLeft {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0);
  }
}

@keyframes slideInRight {
  from {
    transform: translateX(100%);
  }
  to {
    transform: translateX(0);
  }
}

@keyframes slideDown {
  from {
    transform: translateY(-100%);
    opacity: 0;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}

Rotation Animations

@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

@keyframes wiggle {
  0%,
  7% {
    transform: rotateZ(0);
  }
  15% {
    transform: rotateZ(-15deg);
  }
  20% {
    transform: rotateZ(10deg);
  }
  25% {
    transform: rotateZ(-10deg);
  }
  30% {
    transform: rotateZ(6deg);
  }
  35% {
    transform: rotateZ(-4deg);
  }
  40%,
  100% {
    transform: rotateZ(0);
  }
}

Scale Animations

@keyframes pulse {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.05);
  }
  100% {
    transform: scale(1);
  }
}

@keyframes heartbeat {
  0% {
    transform: scale(1);
  }
  14% {
    transform: scale(1.3);
  }
  28% {
    transform: scale(1);
  }
  42% {
    transform: scale(1.3);
  }
  70% {
    transform: scale(1);
  }
}

Interactive Animations

Hover Effects

.interactive-button {
  background-color: #007bff;
  color: white;
  padding: 12px 24px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: all 0.3s ease;
}

.interactive-button::before {
  content: "";
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(
    90deg,
    transparent,
    rgba(255, 255, 255, 0.2),
    transparent
  );
  transition: left 0.5s ease;
}

.interactive-button:hover {
  background-color: #0056b3;
  transform: translateY(-2px);
  box-shadow: 0 4px 15px rgba(0, 123, 255, 0.3);
}

.interactive-button:hover::before {
  left: 100%; /* Shine effect */
}

.interactive-button:active {
  transform: translateY(0);
  box-shadow: 0 2px 8px rgba(0, 123, 255, 0.2);
}

Card Hover Effects

.animated-card {
  background: white;
  border-radius: 12px;
  padding: 2rem;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
  position: relative;
  overflow: hidden;
}

.animated-card::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: linear-gradient(
    45deg,
    transparent,
    rgba(255, 255, 255, 0.1),
    transparent
  );
  transform: translateX(-100%) translateY(-100%) rotate(45deg);
  transition: transform 0.6s ease;
}

.animated-card:hover {
  transform: translateY(-10px) scale(1.02);
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
}

.animated-card:hover::before {
  transform: translateX(100%) translateY(100%) rotate(45deg);
}

Navigation Animations

.nav-link {
  position: relative;
  color: #333;
  text-decoration: none;
  padding: 0.5rem 1rem;
  transition: color 0.3s ease;
}

.nav-link::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 50%;
  width: 0;
  height: 2px;
  background-color: #007bff;
  transition: all 0.3s ease;
}

.nav-link:hover {
  color: #007bff;
}

.nav-link:hover::after {
  width: 100%;
  left: 0;
}

/* Alternative underline effect */
.nav-link-alt {
  position: relative;
  overflow: hidden;
}

.nav-link-alt::before {
  content: "";
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 2px;
  background-color: #007bff;
  transform: translateX(-100%);
  transition: transform 0.3s ease;
}

.nav-link-alt:hover::before {
  transform: translateX(0);
}

Loading Animations

Spinner Animations

.spinner {
  width: 40px;
  height: 40px;
  border: 4px solid #f3f3f3;
  border-top: 4px solid #007bff;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

.dots-loader {
  display: flex;
  gap: 4px;
  align-items: center;
}

.dots-loader span {
  width: 8px;
  height: 8px;
  background-color: #007bff;
  border-radius: 50%;
  animation: dotPulse 1.4s ease-in-out infinite both;
}

.dots-loader span:nth-child(1) {
  animation-delay: -0.32s;
}
.dots-loader span:nth-child(2) {
  animation-delay: -0.16s;
}

@keyframes dotPulse {
  0%,
  80%,
  100% {
    transform: scale(0);
    opacity: 0.5;
  }
  40% {
    transform: scale(1);
    opacity: 1;
  }
}

Progress Bars

.progress-bar {
  width: 100%;
  height: 8px;
  background-color: #e9ecef;
  border-radius: 4px;
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  background: linear-gradient(90deg, #007bff, #00d4ff);
  border-radius: 4px;
  width: 0%;
  transition: width 0.3s ease;
  animation: progressShine 2s ease-in-out infinite;
}

@keyframes progressShine {
  0% {
    background-position: -200px 0;
  }
  100% {
    background-position: calc(200px + 100%) 0;
  }
}

.progress-fill {
  background-image: linear-gradient(
    90deg,
    #007bff 0%,
    #007bff 40%,
    #00d4ff 50%,
    #007bff 60%,
    #007bff 100%
  );
  background-size: 200px 100%;
}

Skeleton Loading

.skeleton {
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: skeleton-loading 1.5s infinite;
}

@keyframes skeleton-loading {
  0% {
    background-position: 200% 0;
  }
  100% {
    background-position: -200% 0;
  }
}

.skeleton-text {
  height: 1rem;
  border-radius: 4px;
  margin-bottom: 0.5rem;
}

.skeleton-text.short {
  width: 60%;
}

.skeleton-text.medium {
  width: 80%;
}

.skeleton-text.long {
  width: 100%;
}

Scroll Animations

CSS-only Scroll Animations

.scroll-reveal {
  opacity: 0;
  transform: translateY(30px);
  transition: all 0.6s ease;
}

/* Using Intersection Observer API with CSS class toggle */
.scroll-reveal.visible {
  opacity: 1;
  transform: translateY(0);
}

/* Staggered animations */
.scroll-reveal:nth-child(1) {
  transition-delay: 0.1s;
}
.scroll-reveal:nth-child(2) {
  transition-delay: 0.2s;
}
.scroll-reveal:nth-child(3) {
  transition-delay: 0.3s;
}

Parallax Effects

.parallax-container {
  perspective: 1px;
  height: 100vh;
  overflow-x: hidden;
  overflow-y: auto;
}

.parallax-element {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  transform: translateZ(-1px) scale(2);
}

.parallax-foreground {
  transform: translateZ(0);
}

Form Animations

Input Focus Effects

.floating-label-group {
  position: relative;
  margin-bottom: 2rem;
}

.floating-input {
  width: 100%;
  padding: 1rem 0.75rem 0.5rem;
  border: 2px solid #e1e5e9;
  border-radius: 6px;
  font-size: 1rem;
  transition: border-color 0.3s ease;
  background: transparent;
}

.floating-input:focus {
  outline: none;
  border-color: #007bff;
}

.floating-label {
  position: absolute;
  left: 0.75rem;
  top: 1rem;
  font-size: 1rem;
  color: #666;
  pointer-events: none;
  transition: all 0.3s ease;
  background: white;
  padding: 0 0.25rem;
}

.floating-input:focus + .floating-label,
.floating-input:not(:placeholder-shown) + .floating-label {
  top: -0.5rem;
  font-size: 0.75rem;
  color: #007bff;
}

Button States

.form-button {
  background-color: #007bff;
  color: white;
  border: none;
  padding: 12px 24px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 1rem;
  position: relative;
  overflow: hidden;
  transition: all 0.3s ease;
}

.form-button:hover {
  background-color: #0056b3;
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(0, 123, 255, 0.3);
}

.form-button:active {
  transform: translateY(0);
  box-shadow: 0 2px 6px rgba(0, 123, 255, 0.2);
}

.form-button.loading {
  background-color: #6c757d;
  cursor: not-allowed;
  pointer-events: none;
}

.form-button.loading::after {
  content: "";
  position: absolute;
  width: 16px;
  height: 16px;
  margin: auto;
  border: 2px solid transparent;
  border-top-color: white;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

Performance Optimization

Hardware Acceleration

.gpu-accelerated {
  /* Force GPU acceleration */
  transform: translateZ(0);
  /* or */
  will-change: transform;
  /* or */
  transform: translate3d(0, 0, 0);
}

.smooth-animation {
  /* Optimize for animations */
  will-change: transform, opacity;
  transform: translateZ(0);
}

Efficient Properties

/* ✅ Efficient - No layout/paint */
.efficient-animation {
  transition: transform 0.3s ease, opacity 0.3s ease;
}

.efficient-animation:hover {
  transform: translateX(10px) scale(1.1);
  opacity: 0.8;
}

/* ❌ Expensive - Causes layout/paint */
.expensive-animation {
  transition: width 0.3s ease, height 0.3s ease, top 0.3s ease;
}

.expensive-animation:hover {
  width: 200px;
  height: 200px;
  top: 20px;
}

Reduce Motion for Accessibility

/* Respect user preferences */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* Provide alternative for essential animations */
@media (prefers-reduced-motion: reduce) {
  .loading-spinner {
    animation: none;
    opacity: 0.5;
  }

  .loading-spinner::after {
    content: "Loading...";
  }
}

Advanced Animation Techniques

Morphing Shapes

.morphing-shape {
  width: 100px;
  height: 100px;
  background-color: #007bff;
  transition: all 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
  clip-path: circle(50% at 50% 50%);
}

.morphing-shape:hover {
  clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
  background-color: #dc3545;
  transform: rotate(180deg);
}

Text Animations

.typewriter {
  overflow: hidden;
  border-right: 0.15em solid orange;
  white-space: nowrap;
  margin: 0 auto;
  letter-spacing: 0.15em;
  animation: typewriter 3.5s steps(40, end), blink-caret 0.75s step-end infinite;
}

@keyframes typewriter {
  from {
    width: 0;
  }
  to {
    width: 100%;
  }
}

@keyframes blink-caret {
  from,
  to {
    border-color: transparent;
  }
  50% {
    border-color: orange;
  }
}

.glitch-text {
  position: relative;
  color: white;
  font-size: 2rem;
  font-weight: bold;
  animation: glitch 2s infinite;
}

@keyframes glitch {
  0%,
  100% {
    text-shadow: 0.05em 0 0 rgba(255, 0, 0, 0.75), -0.05em -0.025em 0 rgba(0, 255, 0, 0.75),
      0.025em 0.05em 0 rgba(0, 0, 255, 0.75);
  }
  15% {
    text-shadow: 0.05em 0 0 rgba(255, 0, 0, 0.75), -0.05em -0.025em 0 rgba(0, 255, 0, 0.75),
      0.025em 0.05em 0 rgba(0, 0, 255, 0.75);
  }
  16% {
    text-shadow: -0.05em -0.025em 0 rgba(255, 0, 0, 0.75), 0.025em 0.025em 0
        rgba(0, 255, 0, 0.75), -0.05em -0.05em 0 rgba(0, 0, 255, 0.75);
  }
  49% {
    text-shadow: -0.05em -0.025em 0 rgba(255, 0, 0, 0.75), 0.025em 0.025em 0
        rgba(0, 255, 0, 0.75), -0.05em -0.05em 0 rgba(0, 0, 255, 0.75);
  }
  50% {
    text-shadow: 0.025em 0.05em 0 rgba(255, 0, 0, 0.75), 0.05em 0 0 rgba(0, 255, 0, 0.75),
      0 -0.05em 0 rgba(0, 0, 255, 0.75);
  }
}

Complex Sequences

.complex-sequence {
  animation: fadeIn 0.5s ease-out, slideUp 0.5s ease-out 0.2s,
    pulse 2s ease-in-out 0.7s infinite;
  animation-fill-mode: backwards, backwards, none;
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes slideUp {
  from {
    transform: translateY(20px);
  }
  to {
    transform: translateY(0);
  }
}

@keyframes pulse {
  0%,
  100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.05);
  }
}

Animation Libraries Integration

Using with Popular Libraries

/* AOS (Animate On Scroll) compatible */
.aos-fade-up {
  opacity: 0;
  transform: translateY(30px);
  transition: all 0.6s ease;
}

.aos-fade-up.aos-animate {
  opacity: 1;
  transform: translateY(0);
}

/* Custom animation system */
.animate {
  animation-duration: 0.6s;
  animation-fill-mode: both;
}

.animate.fade-in {
  animation-name: fadeIn;
}
.animate.slide-in-left {
  animation-name: slideInLeft;
}
.animate.bounce-in {
  animation-name: bounceIn;
}

/* Utility classes */
.animate-delay-1 {
  animation-delay: 0.1s;
}
.animate-delay-2 {
  animation-delay: 0.2s;
}
.animate-delay-3 {
  animation-delay: 0.3s;
}

.animate-duration-fast {
  animation-duration: 0.3s;
}
.animate-duration-slow {
  animation-duration: 1s;
}

Best Practices

1. Performance First

/* ✅ Use transform and opacity */
.performant-animation {
  transition: transform 0.3s ease, opacity 0.3s ease;
}

/* ❌ Avoid layout-triggering properties */
.expensive-animation {
  transition: width 0.3s ease, height 0.3s ease;
}

2. Meaningful Animations

/* ✅ Purpose-driven animations */
.feedback-animation {
  transition: background-color 0.2s ease;
}

.success {
  background-color: #28a745;
}
.error {
  background-color: #dc3545;
}

/* ❌ Gratuitous animations */
.annoying-animation {
  animation: spin 1s linear infinite;
}

3. Consistent Timing

:root {
  --duration-fast: 0.15s;
  --duration-normal: 0.3s;
  --duration-slow: 0.5s;
  --easing-default: cubic-bezier(0.4, 0, 0.2, 1);
}

.consistent-animations {
  transition: all var(--duration-normal) var(--easing-default);
}

4. Accessibility Considerations

/* Respect user preferences */
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* Provide alternatives */
@media (prefers-reduced-motion: reduce) {
  .animated-button:hover {
    background-color: #0056b3;
    /* Remove transform animation */
  }
}

Debugging Animations

Browser DevTools

  1. Elements panel - Inspect animated elements
  2. Animations panel - Control playback speed
  3. Performance panel - Check for jank
  4. Rendering panel - Enable paint flashing

CSS Debugging

.debug-animation {
  /* Slow down to debug */
  animation-duration: 5s;

  /* Pause animation */
  animation-play-state: paused;

  /* Visual debugging */
  border: 2px solid red;
}

Common Animation Mistakes

❌ Too Many Animations

/* Bad: Everything animates */
.over-animated {
  animation: bounce 1s infinite, pulse 2s infinite, wiggle 0.5s infinite;
}

❌ Wrong Easing

/* Bad: Linear motion feels robotic */
.robotic-motion {
  transition: transform 0.3s linear;
}

/* Good: Natural easing */
.natural-motion {
  transition: transform 0.3s ease-out;
}

❌ Performance Killers

/* Bad: Causes layout thrashing */
.layout-killer {
  transition: width 0.3s, height 0.3s, margin 0.3s;
}

/* Good: GPU-accelerated */
.smooth-animation {
  transition: transform 0.3s, opacity 0.3s;
}

Tools untuk Animations

  1. Animate.css - Ready-to-use animation library
  2. AOS - Animate On Scroll library
  3. Lottie - After Effects animations
  4. CSS Animation Generator - Online keyframe generator
  5. Easings.net - Easing function reference

Kesimpulan

CSS Animations membuat website menjadi hidup dan engaging. Key takeaways:

  • Use animations purposefully - tidak berlebihan
  • Focus on performance - gunakan transform dan opacity
  • Respect accessibility - honor prefers-reduced-motion
  • Keep timing consistent - gunakan design system
  • Test on real devices - pastikan smooth di semua device

Dengan animations yang baik, website Anda akan memberikan delightful user experience yang memorable!

Selamat! Anda telah menyelesaikan series tutorial CSS lengkap dari basic hingga advanced. Terus praktik dan eksplorasi untuk menguasai CSS sepenuhnya! 🎉