배경이 단색이면 패럴랙스는 성립하지 않는다. 앞의 것이 몇 px 어긋나도
비교할 대상이 없다. 히어로 말고는 기준면이 없어 시차가 안 보였다.
배경 이미지를 사 오는 대신 이 페이지가 이미 주장하는 것을 그렸다
.bg-grid 간격 눈금 격자. 셀이 --grid-cell = --space-6
파이프라인 · 수치. "모든 값이 토큰에서 나온다"가 배경에서도 성립
.bg-glow 광원 블롭. 섹션마다 --glow-x 로 자리를 옮긴다
재료 · 설치. 히어로의 빛이 마지막 CTA 에서 돌아온다
실측 3층 (스크롤 1000 -> 1600)
격자 +14.9px · 산출물 -14px · 단계명 0
한 층은 반드시 고정이다. 전부 움직이면 그냥 흔들리는 페이지다
그리드 wide 트랙을 좁은 화면에서 닫는다
고정 10rem 이라 모바일에서도 좌우 80px 이 살아남아, 390px 에서 본문이
x=112 부터 시작하고 폭이 278px 로 줄어 제목이 네 줄로 접혔다.
--wide-pad 를 clamp 로 바꿔 닫았다. 이제 전부 x=32 에서 시작하고 두 줄이다
파이프라인 정렬선을 하나로
제목 x=371 / 리드 x=435 / 스파인 x=143 이던 것을 전부 x=183 으로.
제목·리드·브리프를 스파인과 같은 컨테이너에 넣었다
히어로 높이를 콘텐츠에 맞춘다
모바일에서 콘텐츠 390px 에 736px 을 씌워 여백이 화면의 41% 였고
다음 섹션이 화면 밖으로 밀려 스크롤 단서까지 사라졌다.
모바일 min-height 제거(736 -> 554), 데스크톱 88dvh -> 78dvh
배경 마스크 62% -> 82% 로 늘려 하단의 죽은 띠를 없앴다
스킬 motion.md 에 "패럴랙스에는 기준면이 필요하다" 를 추가.
페이지가 주장하는 것을 배경으로 그리는 표와, 한 층은 고정이라는 규칙.
390px / 1440px 실렌더: 가로 스크롤 0, 대비 실패 0. 테스트 22개 통과
120 lines
3.8 KiB
Text
120 lines
3.8 KiB
Text
---
|
|
import type { Content } from "../i18n/content";
|
|
|
|
interface Props { c: Content["metrics"]; }
|
|
const { c } = Astro.props;
|
|
const feature = c.items.filter((m) => m.feature);
|
|
const rest = c.items.filter((m) => !m.feature);
|
|
---
|
|
|
|
{/*
|
|
레이아웃 패밀리: 수치 조판.
|
|
카드에 담지 않는다. 숫자가 크기와 정렬선으로 스스로 위계를 만든다.
|
|
카드는 elevation 이 진짜 위계를 나를 때만 쓴다는 규칙을 여기서 지킨다.
|
|
*/}
|
|
{/*
|
|
이 섹션에는 패럴랙스를 넣지 않는다. 빠뜨린 것이 아니라 결정이다.
|
|
|
|
여기가 이 페이지의 수치를 공개하는 자리다. 숫자가 스크롤에 따라
|
|
흔들리면 그 값도 흔들리는 것처럼 읽힌다. 계기판의 바늘은 떨지 않는다.
|
|
움직임이 의미를 만드는 자리가 있으면, 움직이지 않는 것이 의미인 자리도 있다.
|
|
*/}
|
|
<section id="metrics" class="section metrics bg-grid" aria-labelledby="metrics-h">
|
|
<div class="head">
|
|
<p class="eyebrow reveal">{c.eyebrow}</p>
|
|
<h2 id="metrics-h" class="reveal">{c.h2}</h2>
|
|
</div>
|
|
<p class="lead metrics-lead reveal">{c.lead}</p>
|
|
|
|
<div class="full figures">
|
|
{
|
|
feature.map((m, i) => (
|
|
<div class="fig fig-lead reveal" style={`--reveal-delay:${i * 80}ms`}>
|
|
<span class="fig-value nums">{m.value}</span>
|
|
<span class="fig-label">{m.label}</span>
|
|
<span class="fig-note muted">{m.note}</span>
|
|
</div>
|
|
))
|
|
}
|
|
|
|
<dl class="fig-rest">
|
|
{
|
|
rest.map((m, i) => (
|
|
<div class="row reveal" style={`--reveal-delay:${(i + 2) * 50}ms`}>
|
|
<dt>{m.label}</dt>
|
|
<dd class="nums">{m.value}</dd>
|
|
<dd class="row-note muted">{m.note}</dd>
|
|
</div>
|
|
))
|
|
}
|
|
</dl>
|
|
</div>
|
|
|
|
<p class="caveat muted reveal">{c.caveat}</p>
|
|
</section>
|
|
|
|
<style>
|
|
.metrics-lead { margin-block: var(--space-4) var(--space-7); max-width: 30em; }
|
|
|
|
.figures {
|
|
max-width: 1180px;
|
|
margin-inline: auto;
|
|
padding-inline: var(--gutter);
|
|
display: grid;
|
|
/* 비대칭. 큰 수치 둘이 왼쪽을 차지하고 나머지는 오른쪽 여백에 흐른다 */
|
|
grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
|
|
column-gap: var(--space-7);
|
|
row-gap: var(--space-6);
|
|
align-items: start;
|
|
}
|
|
|
|
.fig-lead { display: grid; gap: var(--space-1); }
|
|
.fig-lead:nth-child(2) {
|
|
/* 두 번째 큰 수치는 한 칸 내려앉는다 */
|
|
margin-top: var(--space-6);
|
|
}
|
|
.fig-value {
|
|
font-size: clamp(3.4rem, 2rem + 5vw, 6rem);
|
|
line-height: 0.92;
|
|
font-weight: var(--weight-strong);
|
|
letter-spacing: -0.04em;
|
|
color: var(--accent);
|
|
}
|
|
.fig-label { font-size: var(--step-1); font-weight: var(--weight-medium); margin-top: var(--space-2); }
|
|
.fig-note { font-size: var(--step-0); max-width: 22em; }
|
|
|
|
/* 나머지 수치는 오른쪽 열에서 두 칸을 세로로 이어 쓴다 */
|
|
.fig-rest {
|
|
grid-column: 2;
|
|
grid-row: 1 / span 2;
|
|
margin: 0;
|
|
display: grid;
|
|
align-content: start;
|
|
}
|
|
.row {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1fr) auto;
|
|
column-gap: var(--space-4);
|
|
align-items: baseline;
|
|
padding-block: var(--space-3);
|
|
border-top: 1px solid var(--line);
|
|
}
|
|
.row:last-child { border-bottom: 1px solid var(--line); }
|
|
dt { font-weight: var(--weight-medium); }
|
|
dd { margin: 0; }
|
|
dd.nums { font-size: var(--step-1); color: var(--accent); justify-self: end; }
|
|
.row-note {
|
|
grid-column: 1 / -1;
|
|
font-size: var(--step-0);
|
|
margin-top: var(--space-1);
|
|
max-width: 32em;
|
|
}
|
|
|
|
.caveat { margin-top: var(--space-6); font-size: var(--step-0); max-width: 34em; }
|
|
|
|
@media (max-width: 860px) {
|
|
.figures { grid-template-columns: 1fr; }
|
|
.fig-rest { grid-column: 1; grid-row: auto; }
|
|
.fig-lead:nth-child(2) { margin-top: 0; }
|
|
}
|
|
</style>
|