03Đường cong ease-out-expo
cubic-bezier(.16, 1, .3, 1) xong gần hết hành trình chỉ trong vài khung hình đầu, đoạn còn lại bò chậm gần như mắt thường không nhận ra, kéo dài thêm phần hạ cánh.
Dùng choSidebar·dropdown bung ra thật nhanh, hover CTA cần nhấn cảm giác nhanh
cubic-bezier급감속transform

<main class="stage is-demo">
<div class="track">
<span class="dot dot--start"></span>
<span class="dot dot--end"></span>
<div class="puck"></div>
</div>
</main>@use "../../../../site/static/demo-tokens" as *;
// ── 변수 3개 ──────────────────────────────────────────
$duration: $dur-loop; // 2s
$easing: cubic-bezier(.16, 1, .3, 1); // ease-out-expo — 첫 프레임부터 거의 다 이동해 있고, 나머지 구간은 아주 천천히 기어간다
$color: $subject-cream;
@include stage($stage-orange);
$track-w: 220px;
$puck-w: $sp-6;
$travel: $track-w - $puck-w;
.track {
position: relative;
width: $track-w;
height: $sp-2;
}
.dot {
position: absolute;
top: 50%;
width: $sp-2;
height: $sp-2;
border-radius: $r-pill;
background: rgba(255, 255, 255, .3);
transform: translate(-50%, -50%);
}
.dot--start { left: 0; }
.dot--end { left: $track-w; }
.puck {
position: absolute;
top: 50%;
left: 0;
width: $puck-w;
height: $puck-w;
border-radius: $r-pill;
background: $color;
box-shadow: $shadow-raised;
transform: translate(0, -50%);
}
.stage.is-demo .puck {
animation: move $duration $easing infinite alternate;
}
@keyframes move {
from { transform: translate(0, -50%); }
to { transform: translate($travel, -50%); }
}
@media (prefers-reduced-motion: reduce) {
.stage.is-demo .puck { animation: none; transform: translate($travel, -50%); }
}html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: #ff4d1f;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.track {
position: relative;
width: 220px;
height: 8px;
}
.dot {
position: absolute;
top: 50%;
width: 8px;
height: 8px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.3);
transform: translate(-50%, -50%);
}
.dot--start {
left: 0;
}
.dot--end {
left: 220px;
}
.puck {
position: absolute;
top: 50%;
left: 0;
width: 24px;
height: 24px;
border-radius: 999px;
background: #fff7e6;
box-shadow: 0 14px 24px rgba(23, 20, 26, 0.32);
transform: translate(0, -50%);
}
.stage.is-demo .puck {
animation: move 2s cubic-bezier(0.16, 1, 0.3, 1) infinite alternate;
}
@keyframes move {
from {
transform: translate(0, -50%);
}
to {
transform: translate(196px, -50%);
}
}
@media (prefers-reduced-motion: reduce) {
.stage.is-demo .puck {
animation: none;
transform: translate(196px, -50%);
}
}import type { CSSProperties } from "react";
import styles from "./EaseOutExpo.module.scss";
export type EaseOutExpoProps = {
duration?: number;
color?: string;
};
export default function EaseOutExpo({ duration = 2000, color = "#fff7e6" }: EaseOutExpoProps) {
const vars: CSSProperties = { "--duration": `${duration}ms`, "--color": color } as CSSProperties;
return (
<div className={styles.stage} style={vars}>
<div className={styles.track}>
<span className={`${styles.dot} ${styles.dotStart}`} />
<span className={`${styles.dot} ${styles.dotEnd}`} />
<div className={styles.puck} />
</div>
</div>
);
}03 Đường cong ease-out-expo — Diện tích đo được 5.573% · khung hình chuyển động 21/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · 9 cubic bezier css — đường cong copy-paste
Bài viết chứa demo này
9 cubic bezier css — đường cong copy-pasteCách ghi thay đổi tốc độ của một chuyển động bằng bốn con số trong CSS chính là giá trị cubic bezier css, còn kiểu nảy t Xem tất cả demo trong bài này

