상호작용 모션 — 전부 피드백 목적으로만
모션은 이유가 있어야 붙인다. 여기 넣은 것은 전부 '지금 이걸 보고 있다' 또는 '이건 눌린다'를 말한다. 장식 목적 애니메이션은 넣지 않았다. - 유리 카드 29곳: 커서 아래에서 3px 떠오르고 그림자가 깊어진다 - 링크 2곳: 밑줄이 왼쪽에서 자란다 - 쇼케이스 판 2곳: 1.2% 다가온다 - 스파인 정거장: 마커가 커지고 인용선이 밝아진다 전부 transform 과 opacity 만 움직인다(하드 게이트 8). prefers-reduced-motion 안에 넣어 모션을 줄이는 설정에서는 전부 사라진다.
This commit is contained in:
parent
85be000704
commit
ed1f335a89
9 changed files with 57 additions and 8 deletions
|
|
@ -33,7 +33,7 @@ const { c, ui } = Astro.props;
|
|||
</div>
|
||||
|
||||
<p class="hero-links">
|
||||
{c.links.map((l) => <a href={l.href}>{l.label}</a>)}
|
||||
{c.links.map((l) => <a class="link-grow" href={l.href}>{l.label}</a>)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ const { c, ui } = Astro.props;
|
|||
<dl class="cmds">
|
||||
{
|
||||
c.commands.map((x) => (
|
||||
<div class="cmd-row glass">
|
||||
<div class="cmd-row glass lift">
|
||||
<dt class="mono">{x.cmd}</dt>
|
||||
<dd class="muted">{x.what}</dd>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ const { c } = Astro.props;
|
|||
{
|
||||
c.tiles.map((t, i) => (
|
||||
<li class="tile reveal" style={`--reveal-delay:${i * 80}ms`}>
|
||||
<div class="shell">
|
||||
<div class="shell lift">
|
||||
<div class="core">
|
||||
<div class={`swatch swatch-${t.id}`} aria-hidden="true"></div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const rest = c.items.filter((m) => !m.feature);
|
|||
<div class="full bento">
|
||||
{
|
||||
feature.map((m, i) => (
|
||||
<div class="cell cell-lg glass glass-2 reveal" style={`--reveal-delay:${i * 70}ms`}>
|
||||
<div class="cell cell-lg glass glass-2 lift reveal" style={`--reveal-delay:${i * 70}ms`}>
|
||||
<span class="cell-value nums">{m.value}</span>
|
||||
<span class="cell-label">{m.label}</span>
|
||||
<span class="cell-note muted">{m.note}</span>
|
||||
|
|
@ -25,7 +25,7 @@ const rest = c.items.filter((m) => !m.feature);
|
|||
}
|
||||
{
|
||||
rest.map((m, i) => (
|
||||
<div class="cell glass reveal" style={`--reveal-delay:${(i + 2) * 70}ms`}>
|
||||
<div class="cell glass lift reveal" style={`--reveal-delay:${(i + 2) * 70}ms`}>
|
||||
<span class="cell-value nums">{m.value}</span>
|
||||
<span class="cell-label">{m.label}</span>
|
||||
<span class="cell-note muted">{m.note}</span>
|
||||
|
|
|
|||
|
|
@ -114,6 +114,15 @@ const { c } = Astro.props;
|
|||
padding-left: var(--space-3);
|
||||
border-left: 2px solid var(--accent);
|
||||
}
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.stop::before {
|
||||
transition: transform var(--dur-quick) var(--ease-out);
|
||||
}
|
||||
.stop:hover::before { transform: scale(1.5); }
|
||||
.stop-becomes { transition: border-color var(--dur-quick) var(--ease-out); }
|
||||
.stop:hover .stop-becomes { border-color: var(--ink); }
|
||||
}
|
||||
|
||||
.stop-becomes.mono {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--mono-size);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ const { c } = Astro.props;
|
|||
<div class="full log">
|
||||
{
|
||||
c.items.map((i, idx) => (
|
||||
<article class="entry glass reveal" style={`--reveal-delay:${idx * 60}ms`}>
|
||||
<article class="entry glass lift reveal" style={`--reveal-delay:${idx * 60}ms`}>
|
||||
<p class="caught">
|
||||
<span class="tick" aria-hidden="true" />
|
||||
{i.caught}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ const { c } = Astro.props;
|
|||
<dl class="full rule-list">
|
||||
{
|
||||
c.items.map((r, i) => (
|
||||
<div class="rule glass reveal" style={`--reveal-delay:${i * 55}ms`}>
|
||||
<div class="rule glass lift reveal" style={`--reveal-delay:${i * 55}ms`}>
|
||||
<dt>{r.rule}</dt>
|
||||
<dd class="muted">{r.why}</dd>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ const shots = [shotCoffee, shotSaas];
|
|||
{
|
||||
c.items.map((item, i) => (
|
||||
<figure class:list={["work", "reveal", i === 0 ? "par-slow" : "par-fast"]} style={`--reveal-delay:${i * 90}ms`}>
|
||||
<div class="shell">
|
||||
<div class="shell zoom-in">
|
||||
<div class="core">
|
||||
<Image src={shots[i]!} alt={item.alt} widths={[480, 860, 1200]}
|
||||
sizes="(max-width: 820px) 92vw, 44vw" loading="lazy" />
|
||||
|
|
|
|||
|
|
@ -271,6 +271,46 @@ a:hover { color: var(--accent); }
|
|||
.reveal.is-in { transform: none; }
|
||||
}
|
||||
|
||||
/* ---- 상호작용 모션 ------------------------------------------
|
||||
모션은 이유가 있어야 붙인다. 여기 있는 것은 전부 피드백이다.
|
||||
"지금 이 카드를 보고 있다", "이 버튼은 눌린다"를 말한다.
|
||||
transform 과 opacity 만 움직인다(하드 게이트 8). */
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
/* 유리 카드는 커서 아래에서 아주 조금 떠오른다 */
|
||||
.lift {
|
||||
transition:
|
||||
transform var(--dur-quick) var(--ease-out),
|
||||
box-shadow var(--dur-quick) var(--ease-out);
|
||||
}
|
||||
.lift:hover {
|
||||
transform: translate3d(0, -3px, 0);
|
||||
box-shadow: var(--glass-hi), var(--shadow-3);
|
||||
}
|
||||
|
||||
/* 링크 밑줄이 커서 쪽에서 자란다 */
|
||||
.link-grow {
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
}
|
||||
.link-grow::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: -3px;
|
||||
height: 1px;
|
||||
background: currentColor;
|
||||
transform: scaleX(0);
|
||||
transform-origin: left;
|
||||
transition: transform var(--dur-quick) var(--ease-out);
|
||||
}
|
||||
.link-grow:hover::after { transform: scaleX(1); }
|
||||
|
||||
/* 쇼케이스 판은 들여다보면 조금 다가온다 */
|
||||
.zoom-in { transition: transform var(--dur-normal) var(--ease-out); }
|
||||
.zoom-in:hover { transform: scale(1.012); }
|
||||
}
|
||||
|
||||
/* ---- 패럴랙스 -----------------------------------------------
|
||||
scroll-driven animation 으로만 만든다. scroll 리스너는 쓰지 않는다.
|
||||
움직이는 것은 transform 뿐이라 지원되지 않는 브라우저에서는
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue