지적받은 것: 모바일 마진·패딩, 폰트 웨이트, 버튼 스타일 불일치, SSOT,
스크롤바, 모바일 메뉴, 그리고 3D 를 왜 상자에 넣었는지.
3D 의 역할을 잘못 잡았다
lusion.co 의 "3D 는 액자 안"은 3D 자체가 상품일 때의 규칙이다.
우리는 절차를 파는데 액자에 넣을 상품이 없어 "저 상자는 뭐냐"가 됐고,
의미를 게이트 판독기가 자막으로 설명하고 있었다.
이 씬의 역할은 재질이다. 배경으로 되돌리고 값을 전부 낮췄다 —
테두리 광 0.85->0.42, 알파 0.72->0.34, UV 경계 0.05->0.17, 이동 60%
ResizeObserver 로 캔버스를 따라가게 했다. window.resize 만 듣는 동안
히어로 높이 변화를 놓쳐 배경이 화면의 3분의 2만 덮었다
SSOT
웨이트 6종(400/500/560/600/620/660) -> 3종. 셋은 토큰에 없던 값이었다
.btn + btn-solid/btn-quiet. 두 버튼이 높이 36 vs 44, 패딩 16 vs 8,
테두리 1px vs 0, 웨이트 400 vs 500 이었다
--header-h. 간격을 clamp 로 바꾸자 관계가 끊겨 h1 이 헤더 뒤로 들어갔다
--space-5~8 과 --gutter 를 clamp 로. 고정이면 모바일 여백이 화면의 26%
scrollbar-color 지정
모바일
좌우 여백 24 -> 32px, 섹션 상하 112 -> 56px
헤더에 섹션 앵커 4개. 900px 미만은 details 기반 메뉴(JS 0바이트)
패럴랙스는 섹션마다 다른 말을 한다
히어로 글자 상승 / 배경 하강 — 반대 방향이라야 시차가 보인다
파이프라인 단계명 고정, 산출물만 지연 — 인과
재료 타일이 서로 다른 깊이 — 표면은 한 겹이 아니다
프리플라이트 뒤 항목일수록 늦게 — 로그는 흐른다
수치 없음. 의도적 정지 — 계기판의 바늘은 떨지 않는다
스킬
three.md §0-A 를 역할별로 갈랐다. "액자 안"만 적어둔 것이 잘못된
일반화였고 내가 거기 그대로 걸렸다. 재질일 때의 값 교정을 실측으로 남김
tokens.md 웨이트·컨트롤·헤더 높이·반응형 간격 — 토큰이 아예 없던 네 축
motion.md 섹션별 패럴랙스 배정표. 움직이지 않는 것도 결정이다
390px 실렌더: 가로 스크롤 0, 대비 실패 0, 웨이트 3종, radius 2종. 테스트 22개 통과
79 lines
2.1 KiB
Text
79 lines
2.1 KiB
Text
---
|
|
import type { Content } from "../i18n/content";
|
|
|
|
interface Props { c: Content["preflight"]; }
|
|
const { c } = Astro.props;
|
|
---
|
|
|
|
{/*
|
|
레이아웃 패밀리: 로그.
|
|
걸린 것과 고친 것이 한 줄에서 이어진다. 상자에 담지 않는다.
|
|
왼쪽 세로선이 로그라는 형식을 만든다.
|
|
*/}
|
|
<section class="section preflight" aria-labelledby="pf-h">
|
|
<h2 id="pf-h" class="reveal">{c.h2}</h2>
|
|
<p class="lead pf-lead reveal">{c.lead}</p>
|
|
|
|
<div class="full log">
|
|
{
|
|
c.items.map((i, idx) => (
|
|
<article class="entry reveal par-lag" style={`--reveal-delay:${idx * 45}ms; --par-lag:${6 + idx * 2}px`}>
|
|
<p class="caught">{i.caught}</p>
|
|
<p class="fixed muted">{i.fixed}</p>
|
|
</article>
|
|
))
|
|
}
|
|
</div>
|
|
|
|
<p class="pf-note muted reveal">{c.note}</p>
|
|
</section>
|
|
|
|
<style>
|
|
.pf-lead { margin-block: var(--space-4) var(--space-7); max-width: 30em; }
|
|
|
|
.log {
|
|
max-width: 1180px;
|
|
margin-inline: auto;
|
|
padding-inline: var(--gutter);
|
|
display: grid;
|
|
}
|
|
.entry {
|
|
position: relative;
|
|
padding: var(--space-4) 0 var(--space-4) var(--space-5);
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
|
|
gap: var(--space-5);
|
|
align-items: start;
|
|
}
|
|
/* 로그를 관통하는 세로선. 항목마다 상자를 두르지 않는다 */
|
|
.entry::before {
|
|
content: "";
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0;
|
|
bottom: 0;
|
|
width: 1px;
|
|
background: var(--line);
|
|
}
|
|
.entry:first-child::before { top: var(--space-4); }
|
|
.entry:last-child::before { bottom: var(--space-4); }
|
|
/* 걸린 지점을 표시하는 짧은 획 */
|
|
.entry::after {
|
|
content: "";
|
|
position: absolute;
|
|
left: -2px;
|
|
top: calc(var(--space-4) + 0.55em);
|
|
width: 5px;
|
|
height: 5px;
|
|
border-radius: var(--radius-sm);
|
|
background: var(--accent);
|
|
}
|
|
|
|
.caught { margin: 0; font-weight: var(--weight-medium); }
|
|
.fixed { margin: 0; font-size: var(--step-0); }
|
|
.pf-note { margin-top: var(--space-6); font-size: var(--step-0); max-width: 34em; }
|
|
|
|
@media (max-width: 800px) {
|
|
.entry { grid-template-columns: 1fr; gap: var(--space-2); }
|
|
}
|
|
</style>
|