All checks were successful
ci / build (push) Successful in 26s
제목과 본문이 붙어 있던 문제를 고친다.
- h2{margin:0} + p{margin-top:0} 이라 제목 다음 간격이 0px 이었다.
섹션마다 각자 margin-top 을 붙여 어떤 곳은 0, 어떤 곳은 24px 로 갈려 있었다.
base.css 에서 한 번만 정하고 각 섹션의 margin-top 오버라이드를 걷어냈다.
- :where() 로 감싼 첫 시도는 특이도 0 이라 p 규칙에 져서 무효였다.
특이도를 갖추고 p 뒤로 옮겼다.
- 제목을 .head 로 감싼 수치 섹션은 인접 형제가 끊겨 혼자 0px 이었다.
.head 도 규칙에 포함했다.
파이프라인 정거장 간격이 224px 로 벌어져 목록이 흩어져 보이던 문제도 고친다.
- 읽기 간격과 sticky 스크롤 구간을 같은 값으로 맞추려던 것이 원인이다.
간격은 --stop-pad(space-5)로 되돌리고, 스크롤 구간은 .after 뒤 여백으로 옮겼다.
게이트당 237px 확보 — 과민 반응 기준(200px) 위다.
- 마커 원의 top 이 space-4, 패딩이 space-6 로 따로 적혀 있어 원이 제목보다
24px 위에 떠 있었다. 셋 다 --stop-pad 를 보게 했다.
3D 판 위 본문 대비는 실측 결과 최저 9.83:1 로 AAA 를 넘어 손대지 않았다.
스킬 내재화:
- tokens.md 제목 다음 간격 SSOT, :where() 특이도 함정, 리듬은 지역 토큰으로
- motion.md 읽기 간격과 스크롤 구간은 같은 손잡이가 아니다
- antipatterns.md 재는 도구가 거짓말하는 세 방식
(reveal 중 측정 / sharp stats 가 extract 를 무시 / 눈보다 숫자)
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" 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-bottom: 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>
|