CSS Transition Timing Functions
Control the acceleration and pacing of your CSS transitions with timing functions
What are CSS Transition Timing Functions?
CSS Transition Timing Functions determine how intermediate values of a transition are calculated, allowing you to control the acceleration and pacing of animations. They define the rate of change of a property over time, creating more natural and engaging user experiences.
Key Timing Function Types:
- Built-in functions - ease, linear, ease-in, ease-out, ease-in-out
- Step functions - step-start, step-end, steps()
- Cubic Bรฉzier functions - cubic-bezier() for custom curves
- Material Design curves - Standardized easing curves for UI animations
CSS Transition Timing Functions Reference
Function | Description | Values |
---|---|---|
ease | Slow start, fast middle, slow end (default) | cubic-bezier(0.25, 0.1, 0.25, 1) |
linear | Constant speed throughout | cubic-bezier(0, 0, 1, 1) |
ease-in | Slow start, fast end | cubic-bezier(0.42, 0, 1, 1) |
ease-out | Fast start, slow end | cubic-bezier(0, 0, 0.58, 1) |
ease-in-out | Slow start and end, fast middle | cubic-bezier(0.42, 0, 0.58, 1) |
step-start | Jumps to end state immediately | steps(1, jump-start) |
step-end | Jumps to end state at the end | steps(1, jump-end) |
steps() | Discrete steps instead of smooth transition | steps(n, jump-term) |
cubic-bezier() | Custom timing function with control points | cubic-bezier(x1, y1, x2, y2) |
CSS Transition Timing Functions in Action
Example Code
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Interactive CSS Timing Functions Showcase</title> <style> @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); :root { --primary: #6366f1; --secondary: #ec4899; --accent: #06b6d4; --success: #10b981; --warning: #f59e0b; --danger: #ef4444; --dark: #0f172a; --light: #f8fafc; --glass: rgba(255, 255, 255, 0.1); --glass-border: rgba(255, 255, 255, 0.2); --shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); --shadow-lg: 0 25px 50px -12px rgba(0, 0, 0, 0.25); } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Inter', sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; color: white; overflow-x: hidden; } .hero { text-align: center; padding: 4rem 2rem; background: linear-gradient(135deg, rgba(99, 102, 241, 0.3), rgba(236, 72, 153, 0.3)); backdrop-filter: blur(10px); margin-bottom: 3rem; } .hero h1 { font-size: clamp(2.5rem, 5vw, 4rem); font-weight: 700; background: linear-gradient(45deg, #fff, #e2e8f0); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; margin-bottom: 1rem; text-shadow: 0 0 30px rgba(255, 255, 255, 0.3); } .hero p { font-size: 1.25rem; opacity: 0.9; max-width: 600px; margin: 0 auto 2rem; } .timing-selector { display: flex; justify-content: center; gap: 0.5rem; margin-bottom: 2rem; flex-wrap: wrap; padding: 1rem; background: var(--glass); border-radius: 20px; backdrop-filter: blur(10px); max-width: 900px; margin: 0 auto 2rem; } .timing-btn { padding: 0.75rem 1.25rem; background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 25px; color: white; cursor: pointer; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); backdrop-filter: blur(5px); font-weight: 500; font-size: 0.85rem; position: relative; overflow: hidden; } .timing-btn::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.6s; } .timing-btn:hover::before { left: 100%; } .timing-btn:hover { background: rgba(255, 255, 255, 0.2); transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); } .timing-btn.active { background: var(--primary); border-color: var(--primary); transform: translateY(-2px); box-shadow: 0 0 20px rgba(99, 102, 241, 0.5); } .control-panel { display: flex; justify-content: center; gap: 1rem; margin-bottom: 2rem; flex-wrap: wrap; padding: 0 2rem; } .control-btn { padding: 0.75rem 1.5rem; background: var(--glass); border: 1px solid var(--glass-border); border-radius: 12px; color: white; cursor: pointer; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); backdrop-filter: blur(10px); font-weight: 500; } .control-btn:hover { background: rgba(255, 255, 255, 0.2); transform: translateY(-2px); box-shadow: var(--shadow); } .control-btn.active { background: var(--secondary); border-color: var(--secondary); transform: translateY(-2px); box-shadow: 0 0 20px rgba(236, 72, 153, 0.5); } .container { max-width: 1400px; margin: 0 auto; padding: 0 2rem; } .section { margin-bottom: 4rem; background: var(--glass); border: 1px solid var(--glass-border); border-radius: 24px; padding: 2rem; backdrop-filter: blur(20px); box-shadow: var(--shadow); } .section h2 { font-size: 2rem; font-weight: 600; margin-bottom: 1rem; background: linear-gradient(45deg, #fff, #e2e8f0); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } .section p { opacity: 0.8; margin-bottom: 2rem; font-size: 1.1rem; } /* Enhanced Racing Demo */ .race-container { display: grid; gap: 1.5rem; margin: 2rem 0; } .race-track { background: rgba(0, 0, 0, 0.2); border-radius: 50px; height: 80px; position: relative; padding: 10px; overflow: hidden; cursor: pointer; transition: all 0.3s ease; } .race-track:hover { background: rgba(0, 0, 0, 0.3); transform: scale(1.02); } .race-track::before { content: ''; position: absolute; top: 50%; left: 20px; right: 20px; height: 2px; background: repeating-linear-gradient(90deg, #fff 0, #fff 10px, transparent 10px, transparent 20px); opacity: 0.3; transform: translateY(-50%); } .racer { width: 60px; height: 60px; border-radius: 50%; position: absolute; top: 10px; left: 10px; display: flex; align-items: center; justify-content: center; font-size: 1.5rem; color: white; transition: all 3s; box-shadow: 0 0 20px rgba(255, 255, 255, 0.3); cursor: pointer; } .race-info { display: flex; justify-content: space-between; align-items: center; margin-top: 0.5rem; opacity: 0.8; } .race-controls { display: flex; gap: 0.5rem; align-items: center; } .race-btn { padding: 0.25rem 0.75rem; background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 15px; color: white; font-size: 0.8rem; cursor: pointer; transition: all 0.3s ease; } .race-btn:hover { background: rgba(255, 255, 255, 0.2); transform: scale(1.05); } .racing .racer { left: calc(100% - 70px); } .single-racing .racer { left: calc(100% - 70px); } /* Interactive Playground */ .playground { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 2rem; margin: 2rem 0; } .playground-item { background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 16px; padding: 2rem; text-align: center; } .playground-title { font-size: 1.2rem; font-weight: 600; margin-bottom: 1rem; color: var(--accent); } /* Bouncing Balls */ .ball-container { height: 200px; position: relative; background: rgba(0, 0, 0, 0.1); border-radius: 12px; overflow: hidden; margin: 1rem 0; } .ball { width: 40px; height: 40px; border-radius: 50%; position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%); background: linear-gradient(45deg, var(--primary), var(--secondary)); cursor: pointer; transition: transform 1s; } .bouncing .ball { transform: translateX(-50%) translateY(-150px); } /* Rotating Elements */ .rotation-demo { display: flex; justify-content: space-around; margin: 2rem 0; flex-wrap: wrap; gap: 1rem; } .rotate-element { width: 80px; height: 80px; background: linear-gradient(45deg, var(--success), var(--accent)); border-radius: 16px; cursor: pointer; transition: transform 2s; display: flex; align-items: center; justify-content: center; font-size: 1.5rem; } .rotating .rotate-element { transform: rotate(360deg) scale(1.2); } /* Scaling Elements */ .scale-demo { display: flex; justify-content: space-around; margin: 2rem 0; flex-wrap: wrap; gap: 1rem; } .scale-element { width: 60px; height: 60px; background: linear-gradient(45deg, var(--warning), var(--danger)); border-radius: 12px; cursor: pointer; transition: transform 1.5s; display: flex; align-items: center; justify-content: center; font-size: 1.2rem; } .scaling .scale-element { transform: scale(1.8); } /* Slider Controls */ .slider-container { margin: 2rem 0; } .slider-group { display: flex; align-items: center; gap: 1rem; margin: 1rem 0; flex-wrap: wrap; } .slider { flex: 1; min-width: 200px; height: 8px; border-radius: 4px; background: rgba(255, 255, 255, 0.2); outline: none; cursor: pointer; } .slider::-webkit-slider-thumb { appearance: none; width: 20px; height: 20px; border-radius: 50%; background: var(--primary); cursor: pointer; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3); } .slider::-moz-range-thumb { width: 20px; height: 20px; border-radius: 50%; background: var(--primary); cursor: pointer; border: none; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3); } /* Interactive Cards Enhanced */ .cards-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 2rem; margin: 2rem 0; } .interactive-card { background: var(--glass); border: 1px solid var(--glass-border); border-radius: 16px; padding: 2rem; text-align: center; cursor: pointer; transition: all 0.6s; backdrop-filter: blur(10px); position: relative; overflow: hidden; } .interactive-card::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent); transition: left 0.6s; } .interactive-card:hover::before { left: 100%; } .interactive-card:hover { transform: translateY(-10px) scale(1.05); box-shadow: var(--shadow-lg); } .card-icon { font-size: 3rem; margin-bottom: 1rem; opacity: 0.8; transition: all 0.3s ease; } .interactive-card:hover .card-icon { transform: rotate(10deg) scale(1.1); } .card-title { font-size: 1.25rem; font-weight: 600; margin-bottom: 0.5rem; } .card-description { opacity: 0.7; font-size: 0.9rem; } .card-demo-btn { margin-top: 1rem; padding: 0.5rem 1rem; background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 20px; color: white; cursor: pointer; transition: all 0.3s ease; font-size: 0.85rem; } .card-demo-btn:hover { background: rgba(255, 255, 255, 0.2); transform: scale(1.05); } /* Enhanced Button Playground */ .button-playground { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1.5rem; margin: 2rem 0; } .demo-button { padding: 1rem 2rem; border: none; border-radius: 12px; color: white; font-weight: 600; cursor: pointer; position: relative; overflow: hidden; transition: all 0.4s; background: linear-gradient(45deg, var(--primary), var(--secondary)); } .demo-button::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(45deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.1)); transition: left 0.5s; } .demo-button:hover::before { left: 100%; } .demo-button:hover { transform: translateY(-5px); box-shadow: 0 10px 30px rgba(99, 102, 241, 0.4); } .demo-button:active { transform: translateY(-2px) scale(0.98); } /* Custom Bezier Playground */ .bezier-playground { background: rgba(0, 0, 0, 0.2); border-radius: 16px; padding: 2rem; margin: 2rem 0; } .bezier-controls { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin-bottom: 2rem; } .bezier-input { display: flex; flex-direction: column; gap: 0.5rem; } .bezier-input label { font-size: 0.9rem; opacity: 0.8; } .bezier-input input { padding: 0.5rem; border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 8px; background: rgba(255, 255, 255, 0.1); color: white; outline: none; } .bezier-input input:focus { border-color: var(--primary); box-shadow: 0 0 10px rgba(99, 102, 241, 0.3); } .bezier-demo { width: 100px; height: 100px; background: linear-gradient(45deg, var(--accent), var(--success)); border-radius: 12px; margin: 2rem auto; cursor: pointer; transition: transform 2s; display: flex; align-items: center; justify-content: center; font-size: 2rem; } .bezier-active .bezier-demo { transform: translateX(200px) rotate(180deg) scale(1.5); } /* Physics Simulations */ .physics-demo { height: 300px; background: rgba(0, 0, 0, 0.1); border-radius: 16px; position: relative; overflow: hidden; margin: 2rem 0; cursor: pointer; } .physics-object { width: 50px; height: 50px; background: linear-gradient(45deg, var(--primary), var(--secondary)); border-radius: 50%; position: absolute; top: 20px; left: 20px; transition: all 2s; display: flex; align-items: center; justify-content: center; color: white; font-weight: bold; } .physics-active .physics-object { left: calc(100% - 70px); top: calc(100% - 70px); } /* Timing function classes */ .timing-ease { transition-timing-function: ease; } .timing-linear { transition-timing-function: linear; } .timing-ease-in { transition-timing-function: ease-in; } .timing-ease-out { transition-timing-function: ease-out; } .timing-ease-in-out { transition-timing-function: ease-in-out; } .timing-bounce { transition-timing-function: cubic-bezier(0.68, -0.55, 0.27, 1.55); } .timing-elastic { transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1); } .timing-back { transition-timing-function: cubic-bezier(0.68, -0.6, 0.32, 1.6); } .timing-anticipate { transition-timing-function: cubic-bezier(0.36, 0, 0.66, -0.56); } .timing-overshoot { transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1); } /* Morphing Shapes Enhanced */ .morphing-container { display: flex; justify-content: center; gap: 3rem; margin: 3rem 0; flex-wrap: wrap; } .morph-shape { width: 100px; height: 100px; background: linear-gradient(45deg, var(--accent), var(--success)); cursor: pointer; transition: all 1s; position: relative; display: flex; align-items: center; justify-content: center; color: white; font-weight: bold; } .morph-circle { border-radius: 50%; } .morph-square { border-radius: 0; } .morph-diamond { transform: rotate(45deg); border-radius: 20px; } .morphing .morph-shape:nth-child(1) { border-radius: 0; transform: rotate(0deg) scale(1.2); background: linear-gradient(45deg, var(--danger), var(--warning)); } .morphing .morph-shape:nth-child(2) { border-radius: 20px; transform: rotate(45deg) scale(0.8); background: linear-gradient(45deg, var(--success), var(--accent)); } .morphing .morph-shape:nth-child(3) { border-radius: 50%; transform: rotate(0deg) scale(1.1); background: linear-gradient(45deg, var(--primary), var(--secondary)); } /* Progress Bars Enhanced */ .progress-container { margin: 2rem 0; } .progress-item { margin: 1.5rem 0; cursor: pointer; } .progress-item:hover .progress-bar { transform: scale(1.02); } .progress-label { display: flex; justify-content: space-between; margin-bottom: 0.5rem; font-size: 0.9rem; opacity: 0.8; } .progress-bar { width: 100%; height: 12px; background: rgba(255, 255, 255, 0.1); border-radius: 6px; overflow: hidden; position: relative; transition: transform 0.3s ease; } .progress-fill { height: 100%; width: 0%; background: linear-gradient(90deg, var(--primary), var(--secondary)); border-radius: 6px; transition: width 2s; position: relative; } .progress-fill::after { content: ''; position: absolute; top: 0; right: 0; width: 20px; height: 100%; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3)); } .progressing .progress-fill { width: 85%; } .progress-individual.progressing .progress-fill { width: 85%; } /* Responsive */ @media (max-width: 768px) { .hero { padding: 2rem 1rem; } .container { padding: 0 1rem; } .section { padding: 1.5rem; } .timing-selector { flex-direction: column; gap: 0.5rem; } .morphing-container, .floating-demo { gap: 1rem; } .playground { grid-template-columns: 1fr; } .bezier-controls { grid-template-columns: 1fr; } } /* Animation for initial load */ @keyframes fadeInUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } } .section { animation: fadeInUp 0.8s ease-out forwards; } .section:nth-child(2) { animation-delay: 0.1s; } .section:nth-child(3) { animation-delay: 0.2s; } .section:nth-child(4) { animation-delay: 0.3s; } .section:nth-child(5) { animation-delay: 0.4s; } .section:nth-child(6) { animation-delay: 0.5s; } </style> </head> <body> <div class="hero"> <h1>CSS Timing Functions</h1> <p>Interactive showcase of animation timing functions with advanced controls and demonstrations</p> <div class="timing-selector"> <button class="timing-btn active" data-timing="ease">Ease</button> <button class="timing-btn" data-timing="linear">Linear</button> <button class="timing-btn" data-timing="ease-in">Ease In</button> <button class="timing-btn" data-timing="ease-out">Ease Out</button> <button class="timing-btn" data-timing="ease-in-out">Ease In Out</button> <button class="timing-btn" data-timing="bounce">Bounce</button> <button class="timing-btn" data-timing="elastic">Elastic</button> <button class="timing-btn" data-timing="back">Back</button> <button class="timing-btn" data-timing="anticipate">Anticipate</button> <button class="timing-btn" data-timing="overshoot">Overshoot</button> </div> <div class="control-panel"> <button class="control-btn active" data-action="start-race">๐ Start Race</button> <button class="control-btn" data-action="morph-shapes">๐ Morph Shapes</button> <button class="control-btn" data-action="bounce-balls">โฝ Bounce Balls</button> <button class="control-btn" data-action="rotate-elements">๐ Rotate Elements</button> <button class="control-btn" data-action="scale-elements">๐ Scale Elements</button> <button class="control-btn" data-action="fill-progress">๐ Fill Progress</button> <button class="control-btn" data-action="physics-sim">๐งช Physics Sim</button> <button class="control-btn" data-action="reset-all">๐ Reset All</button> </div> </div> <div class="container"> <section class="section"> <h2>๐ Interactive Racing Demonstration</h2> <p>Watch different timing functions compete in a race. Click individual tracks to test specific timing functions, or use the timing selector above to apply globally.</p> <div class="race-container"> <div class="race-track" data-timing="ease"> <div class="racer ease timing-ease">๐</div> <div class="race-info"> <span>Ease (Default)</span> <div class="race-controls"> <button class="race-btn" data-action="race-single" data-target="ease">Test</button> <span>cubic-bezier(0.25, 0.1, 0.25, 1)</span> </div> </div> </div> <div class="race-track" data-timing="linear"> <div class="racer linear timing-linear">๐๏ธ</div> <div class="race-info"> <span>Linear</span> <div class="race-controls"> <button class="race-btn" data-action="race-single" data-target="linear">Test</button> <span>Constant speed</span> </div> </div> </div> <div class="race-track" data-timing="ease-in"> <div class="racer ease-in timing-ease-in">๐</div> <div class="race-info"> <span>Ease In</span> <div class="race-controls"> <button class="race-btn" data-action="race-single" data-target="ease-in">Test</button> <span>Slow start, fast finish</span> </div> </div> </div> <div class="race-track" data-timing="ease-out"> <div class="racer ease-out timing-ease-out">๐</div> <div class="race-info"> <span>Ease Out</span> <div class="race-controls"> <button class="race-btn" data-action="race-single" data-target="ease-out">Test</button> <span>Fast start, slow finish</span> </div> </div> </div> <div class="race-track" data-timing="ease-in-out"> <div class="racer ease-in-out timing-ease-in-out">๐</div> <div class="race-info"> <span>Ease In Out</span> <div class="race-controls"> <button class="race-btn" data-action="race-single" data-target="ease-in-out">Test</button> <span>Slow start and finish</span> </div> </div> </div> <div class="race-track" data-timing="bounce"> <div class="racer bounce timing-bounce">โก</div> <div class="race-info"> <span>Bounce</span> <div class="race-controls"> <button class="race-btn" data-action="race-single" data-target="bounce">Test</button> <span>cubic-bezier(0.68, -0.55, 0.27, 1.55)</span> </div> </div> </div> <div class="race-track" data-timing="elastic"> <div class="racer elastic timing-elastic">๐พ</div> <div class="race-info"> <span>Elastic</span> <div class="race-controls"> <button class="race-btn" data-action="race-single" data-target="elastic">Test</button> <span>cubic-bezier(0.34, 1.56, 0.64, 1)</span> </div> </div> </div> <div class="race-track" data-timing="back"> <div class="racer back timing-back">๐ช</div> <div class="race-info"> <span>Back</span> <div class="race-controls"> <button class="race-btn" data-action="race-single" data-target="back">Test</button> <span>cubic-bezier(0.68, -0.6, 0.32, 1.6)</span> </div> </div> </div> </div> </section> <section class="section"> <h2>๐ฎ Interactive Playground</h2> <p>Multiple interactive demonstrations you can trigger individually or apply timing functions globally using the selector above.</p> <div class="playground"> <div class="playground-item"> <div class="playground-title">โฝ Bouncing Balls</div> <div class="ball-container"> <div class="ball timing-ease" data-demo="ball">๐</div> </div> <button class="card-demo-btn" data-action="bounce-single">Bounce Ball</button> </div> <div class="playground-item"> <div class="playground-title">๐ Rotation Demo</div> <div class="rotation-demo"> <div class="rotate-element timing-ease" data-demo="rotate">๐ฏ</div> </div> <button class="card-demo-btn" data-action="rotate-single">Rotate Element</button> </div> <div class="playground-item"> <div class="playground-title">๐ Scaling Demo</div> <div class="scale-demo"> <div class="scale-element timing-ease" data-demo="scale">๐</div> </div> <button class="card-demo-btn" data-action="scale-single">Scale Element</button> </div> <div class="playground-item"> <div class="playground-title">๐งช Physics Simulation</div> <div class="physics-demo"> <div class="physics-object timing-ease">โก</div> </div> <button class="card-demo-btn" data-action="physics-single">Start Physics</button> </div> </div> </section> <section class="section"> <h2>๐๏ธ Custom Bezier Playground</h2> <p>Create your own custom timing functions using cubic-bezier values. Adjust the parameters and test the result!</p> <div class="bezier-playground"> <div class="bezier-controls"> <div class="bezier-input"> <label>X1 (Start Control)</label> <input type="number" id="x1" min="0" max="1" step="0.01" value="0.25"> </div> <div class="bezier-input"> <label>Y1 (Start Control)</label> <input type="number" id="y1" min="-2" max="2" step="0.01" value="0.1"> </div> <div class="bezier-input"> <label>X2 (End Control)</label> <input type="number" id="x2" min="0" max="1" step="0.01" value="0.25"> </div> <div class="bezier-input"> <label>Y2 (End Control)</label> <input type="number" id="y2" min="-2" max="2" step="0.01" value="1"> </div> </div> <div class="bezier-demo" id="bezier-demo">๐จ</div> <div style="text-align: center; opacity: 0.8;"> <p id="bezier-display">cubic-bezier(0.25, 0.1, 0.25, 1)</p> <button class="card-demo-btn" id="test-bezier">Test Custom Bezier</button> </div> </div> </section> <section class="section"> <h2>๐ฎ Enhanced Interactive Cards</h2> <p>Hover over these cards and click the demo buttons to see different timing functions in action with various effects.</p> <div class="cards-grid"> <div class="interactive-card timing-ease" data-timing="ease"> <div class="card-icon">โก</div> <div class="card-title">Ease</div> <div class="card-description">Natural acceleration and deceleration</div> <button class="card-demo-btn" data-action="card-demo" data-target="ease">Demo Effect</button> </div> <div class="interactive-card timing-bounce" data-timing="bounce"> <div class="card-icon">๐พ</div> <div class="card-title">Bounce</div> <div class="card-description">Playful bouncing effect</div> <button class="card-demo-btn" data-action="card-demo" data-target="bounce">Demo Effect</button> </div> <div class="interactive-card timing-elastic" data-timing="elastic"> <div class="card-icon">๐ช</div> <div class="card-title">Elastic</div> <div class="card-description">Springy elastic motion</div> <button class="card-demo-btn" data-action="card-demo" data-target="elastic">Demo Effect</button> </div> <div class="interactive-card timing-back" data-timing="back"> <div class="card-icon">๐</div> <div class="card-title">Back</div> <div class="card-description">Pull back before moving forward</div> <button class="card-demo-btn" data-action="card-demo" data-target="back">Demo Effect</button> </div> <div class="interactive-card timing-anticipate" data-timing="anticipate"> <div class="card-icon">๐ฏ</div> <div class="card-title">Anticipate</div> <div class="card-description">Anticipation before action</div> <button class="card-demo-btn" data-action="card-demo" data-target="anticipate">Demo Effect</button> </div> <div class="interactive-card timing-ease-in-out" data-timing="ease-in-out"> <div class="card-icon">๐</div> <div class="card-title">Ease In Out</div> <div class="card-description">Smooth wave-like motion</div> <button class="card-demo-btn" data-action="card-demo" data-target="ease-in-out">Demo Effect</button> </div> </div> </section> <section class="section"> <h2>๐ฏ Enhanced Button Playground</h2> <p>Interactive buttons with different timing functions. Click and hover to experience the differences in animation feel.</p> <div class="button-playground"> <button class="demo-button timing-ease" data-timing="ease">Ease Button</button> <button class="demo-button timing-linear" data-timing="linear">Linear Button</button> <button class="demo-button timing-bounce" data-timing="bounce">Bounce Button</button> <button class="demo-button timing-elastic" data-timing="elastic">Elastic Button</button> <button class="demo-button timing-back" data-timing="back">Back Button</button> <button class="demo-button timing-anticipate" data-timing="anticipate">Anticipate Button</button> <button class="demo-button timing-ease-in" data-timing="ease-in">Ease In Button</button> <button class="demo-button timing-ease-out" data-timing="ease-out">Ease Out Button</button> </div> </section> <section class="section"> <h2>๐ Morphing Shapes</h2> <p>Watch these shapes transform using different timing functions. Click individual shapes or use the global controls.</p> <div class="morphing-container"> <div class="morph-shape morph-circle timing-bounce" data-demo="morph">1</div> <div class="morph-shape morph-square timing-elastic" data-demo="morph">2</div> <div class="morph-shape morph-diamond timing-ease-in-out" data-demo="morph">3</div> </div> <div style="text-align: center;"> <button class="card-demo-btn" data-action="morph-single">Morph Shapes</button> </div> </section> <section class="section"> <h2>๐ Interactive Progress Bars</h2> <p>Click individual progress bars to see different timing functions in action, or use the global controls.</p> <div class="progress-container"> <div class="progress-item" data-timing="ease"> <div class="progress-label"> <span>Ease</span> <span>85%</span> </div> <div class="progress-bar"> <div class="progress-fill timing-ease"></div> </div> </div> <div class="progress-item" data-timing="linear"> <div class="progress-label"> <span>Linear</span> <span>85%</span> </div> <div class="progress-bar"> <div class="progress-fill timing-linear"></div> </div> </div> <div class="progress-item" data-timing="bounce"> <div class="progress-label"> <span>Bounce</span> <span>85%</span> </div> <div class="progress-bar"> <div class="progress-fill timing-bounce"></div> </div> </div> <div class="progress-item" data-timing="elastic"> <div class="progress-label"> <span>Elastic</span> <span>85%</span> </div> <div class="progress-bar"> <div class="progress-fill timing-elastic"></div> </div> </div> <div class="progress-item" data-timing="back"> <div class="progress-label"> <span>Back</span> <span>85%</span> </div> <div class="progress-bar"> <div class="progress-fill timing-back"></div> </div> </div> </div> </section> <section class="section"> <h2>โ๏ธ Dynamic Duration Controls</h2> <p>Adjust animation duration and easing dynamically to see how timing functions behave at different speeds.</p> <div class="slider-container"> <div class="slider-group"> <label>Duration:</label> <input type="range" id="duration-slider" class="slider" min="0.5" max="5" step="0.1" value="2"> <span id="duration-value">2.0s</span> </div> <div style="text-align: center; margin: 2rem 0;"> <div class="morph-shape morph-circle timing-ease" id="dynamic-demo" style="margin: 0 auto;">๐ฎ</div> </div> <div style="text-align: center;"> <button class="card-demo-btn" id="test-duration">Test Dynamic Duration</button> </div> </div> </section> </div> <script> document.addEventListener('DOMContentLoaded', function() { const timingButtons = document.querySelectorAll('.timing-btn'); const controlButtons = document.querySelectorAll('.control-btn'); let currentTiming = 'ease'; // Global timing function selector timingButtons.forEach(button => { button.addEventListener('click', function() { timingButtons.forEach(btn => btn.classList.remove('active')); this.classList.add('active'); currentTiming = this.dataset.timing; updateGlobalTiming(); }); }); function updateGlobalTiming() { document.querySelectorAll('[data-demo]').forEach(element => { element.className = element.className.replace(/timing-w+/g, ''); element.classList.add('timing-' + currentTiming); }); } // Control panel buttons controlButtons.forEach(button => { button.addEventListener('click', function() { controlButtons.forEach(btn => btn.classList.remove('active')); this.classList.add('active'); const action = this.dataset.action; handleAction(action); }); }); function handleAction(action) { document.body.classList.remove('racing', 'morphing', 'bouncing', 'rotating', 'scaling', 'progressing', 'physics-active', 'single-racing'); setTimeout(function() { switch(action) { case 'start-race': document.body.classList.add('racing'); break; case 'morph-shapes': document.body.classList.add('morphing'); break; case 'bounce-balls': document.body.classList.add('bouncing'); break; case 'rotate-elements': document.body.classList.add('rotating'); break; case 'scale-elements': document.body.classList.add('scaling'); break; case 'fill-progress': document.body.classList.add('progressing'); break; case 'physics-sim': document.body.classList.add('physics-active'); break; case 'reset-all': break; } }, 50); } // Individual race buttons document.querySelectorAll('.race-btn').forEach(button => { button.addEventListener('click', function(e) { e.stopPropagation(); const target = this.dataset.target; const raceTrack = this.closest('.race-track'); raceTrack.classList.remove('single-racing'); setTimeout(function() { raceTrack.classList.add('single-racing'); }, 50); }); }); // Individual demo buttons document.querySelectorAll('[data-action="bounce-single"]').forEach(button => { button.addEventListener('click', function() { const ball = this.parentElement.querySelector('.ball'); ball.classList.remove('bouncing'); setTimeout(function() { ball.classList.add('bouncing'); }, 50); }); }); document.querySelectorAll('[data-action="rotate-single"]').forEach(button => { button.addEventListener('click', function() { const element = this.parentElement.querySelector('.rotate-element'); element.classList.remove('rotating'); setTimeout(function() { element.classList.add('rotating'); }, 50); }); }); document.querySelectorAll('[data-action="scale-single"]').forEach(button => { button.addEventListener('click', function() { const element = this.parentElement.querySelector('.scale-element'); element.classList.remove('scaling'); setTimeout(function() { element.classList.add('scaling'); }, 50); }); }); document.querySelectorAll('[data-action="physics-single"]').forEach(button => { button.addEventListener('click', function() { const demo = this.parentElement.querySelector('.physics-demo'); demo.classList.remove('physics-active'); setTimeout(function() { demo.classList.add('physics-active'); }, 50); }); }); document.querySelectorAll('[data-action="morph-single"]').forEach(button => { button.addEventListener('click', function() { const container = this.parentElement.querySelector('.morphing-container') || document.querySelector('.morphing-container'); container.classList.remove('morphing'); setTimeout(function() { container.classList.add('morphing'); }, 50); }); }); // Card demo buttons document.querySelectorAll('[data-action="card-demo"]').forEach(button => { button.addEventListener('click', function(e) { e.stopPropagation(); const card = this.closest('.interactive-card'); card.style.transform = 'translateY(-20px) scale(1.1) rotate(5deg)'; setTimeout(function() { card.style.transform = ''; }, 600); }); }); // Progress bar individual clicks document.querySelectorAll('.progress-item').forEach(item => { item.addEventListener('click', function() { this.classList.remove('progress-individual'); setTimeout(function() { item.classList.add('progress-individual', 'progressing'); }, 50); }); }); // Custom bezier controls const bezierInputs = ['x1', 'y1', 'x2', 'y2']; const bezierDisplay = document.getElementById('bezier-display'); const bezierDemo = document.getElementById('bezier-demo'); function updateBezier() { const x1 = document.getElementById('x1').value; const y1 = document.getElementById('y1').value; const x2 = document.getElementById('x2').value; const y2 = document.getElementById('y2').value; const bezierValue = 'cubic-bezier(' + x1 + ', ' + y1 + ', ' + x2 + ', ' + y2 + ')'; bezierDisplay.textContent = bezierValue; bezierDemo.style.transitionTimingFunction = bezierValue; } bezierInputs.forEach(function(id) { document.getElementById(id).addEventListener('input', updateBezier); }); document.getElementById('test-bezier').addEventListener('click', function() { const container = document.querySelector('.bezier-playground'); container.classList.remove('bezier-active'); setTimeout(function() { container.classList.add('bezier-active'); }, 50); }); // Duration slider const durationSlider = document.getElementById('duration-slider'); const durationValue = document.getElementById('duration-value'); const dynamicDemo = document.getElementById('dynamic-demo'); durationSlider.addEventListener('input', function() { const duration = this.value; durationValue.textContent = duration + 's'; dynamicDemo.style.transitionDuration = duration + 's'; }); document.getElementById('test-duration').addEventListener('click', function() { dynamicDemo.style.transform = 'translateX(200px) rotate(180deg) scale(1.5)'; setTimeout(function() { dynamicDemo.style.transform = ''; }, 100); }); // Enhanced button interactions document.querySelectorAll('.demo-button').forEach(button => { button.addEventListener('click', function() { const self = this; this.style.transform = 'scale(0.95)'; setTimeout(function() { self.style.transform = ''; }, 150); }); }); // Shape click interactions document.querySelectorAll('.morph-shape').forEach(shape => { shape.addEventListener('click', function() { const self = this; this.style.transform += ' rotate(360deg)'; setTimeout(function() { self.style.transform = self.style.transform.replace(' rotate(360deg)', ''); }, 1000); }); }); // Auto-start demo setTimeout(function() { handleAction('start-race'); }, 1000); // Preset timing function buttons const presetButtons = [ { name: 'Bounce Effect', values: [0.68, -0.55, 0.27, 1.55] }, { name: 'Elastic', values: [0.34, 1.56, 0.64, 1] }, { name: 'Back In', values: [0.36, 0, 0.66, -0.56] }, { name: 'Overshoot', values: [0.34, 1.56, 0.64, 1] } ]; // Add preset buttons to bezier playground const presetContainer = document.createElement('div'); presetContainer.style.textAlign = 'center'; presetContainer.style.marginTop = '1rem'; presetButtons.forEach(function(preset) { const btn = document.createElement('button'); btn.className = 'card-demo-btn'; btn.textContent = preset.name; btn.style.margin = '0.25rem'; btn.addEventListener('click', function() { document.getElementById('x1').value = preset.values[0]; document.getElementById('y1').value = preset.values[1]; document.getElementById('x2').value = preset.values[2]; document.getElementById('y2').value = preset.values[3]; updateBezier(); }); presetContainer.appendChild(btn); }); document.querySelector('.bezier-playground').appendChild(presetContainer); }); </script> </body> </html>
Timing Function Techniques
Built-in Functions
Use predefined timing functions for common animation patterns.
Custom Cubic Bezier
Create unique animation curves with cubic-bezier() functions.
Step Functions
Create discrete animations with step timing functions.
Material Design Curves
Use standardized timing functions for consistent UI animations.
Best Practices for Timing Functions
Effective Usage
- Use ease-out for elements entering the screen
- Use ease-in for elements exiting the screen
- Use ease-in-out for elements moving within the screen
- Use consistent timing functions across your UI
- Test timing functions with your actual content
- Consider using Material Design curves for consistency
Common Mistakes to Avoid
- Using inappropriate timing functions for the context
- Overusing complex cubic-bezier curves unnecessarily
- Not testing with reduced motion preferences
- Using different timing functions for similar interactions
- Creating animations that are too slow or distracting
- Not considering performance implications
Browser Support & Accessibility
- CSS Timing Functions are supported in all modern browsers
- Use feature queries (@supports) for progressive enhancement
- Respect reduced motion preferences with media queries
- Ensure animations don't cause accessibility issues
- Test with screen readers and keyboard navigation
- Provide fallbacks for older browsers when necessary
Ready to Try It Yourself?
Experiment with CSS Transition Timing Functions in our interactive editor. See your changes in real-time and build your understanding through practice.