피그마에서 잘 정리된 화면은 옮기기도 수월합니다. 저는 디자인을 좌표가 아니라 관계의 언어로 다시 읽는 일부터 시작합니다.

70.1 절대 위치 대신 관계로

도구가 자동으로 뽑아 주는 코드는 요소를 좌표에 못 박아 둡니다. 화면 폭이 조금만 달라져도 배치가 무너집니다.


.card {
position: absolute;
left: 24px;
top: 16px;
width: 320px;
}


대신 요소끼리의 간격과 정렬로 말하면 배치가 스스로 버팁니다.


.card {
display: flex;
flex-direction: column;
gap: 16px;
padding: 24px;
}


좌표가 사라지고 간격만 남습니다. 폭이 바뀌어도 카드 안의 요소가 알아서 자리를 잡습니다.

70.2 박스 모델의 네 겹

모든 요소는 내용, 안쪽 여백, 테두리, 바깥 여백의 네 겹으로 이루어집니다. 오토 레이아웃의 여백은 대부분 이 padding과 gap으로 옮겨집니다.


.box {
box-sizing: border-box;
width: 300px;
padding: 20px;
border: 1px solid #e5e7eb;
margin: 12px 0;
}


box-sizing을 border-box로 두면 padding과 border가 width 안쪽으로 계산됩니다. 300px로 정한 폭이 실제로도 300px로 유지됩니다.


이 규칙을 문서 전체에 먼저 깔아 두면 계산이 늘 단순해집니다.


*, *::before, *::after {
box-sizing: border-box;
}


모든 요소가 같은 방식으로 크기를 셉니다. 폭이 어긋나 요소가 넘치는 일이 사라집니다.

70.3 값은 아래로 흘러내립니다

색이나 글꼴 같은 값은 부모에서 자식으로 상속됩니다. 물처럼 한 곳에 부으면 아래로 흘러내립니다.


body {
color: #1f2937;
font-family: system-ui, sans-serif;
line-height: 1.6;
}


본문 아래 모든 문단이 같은 색과 글꼴을 물려받습니다. 예외가 필요한 곳에서만 다시 적어 주면 됩니다.


되풀이되는 색과 간격은 변수로 묶어 두면 한 번에 바꿀 수 있습니다.


:root {
--brand: #2563eb;
--text: #1f2937;
--gap: 16px;
}
.title {
color: var(--brand);
}


피그마의 색 스타일과 변수 이름을 맞춰 두면, 디자인이 바뀔 때 이 한 줄만 고치면 됩니다.

70.4 상태를 규칙으로

버튼 위에 마우스를 올렸을 때의 변화는 피그마에서는 별도 프레임이지만, 코드에서는 상태 한 줄로 이어집니다.


.btn {
background: var(--brand);
color: #fff;
padding: 10px 18px;
border: 0;
border-radius: 8px;
transition: background 0.2s;
}
.btn:hover {
background: #1d4ed8;
}
.btn:active {
transform: translateY(1px);
}


기본 모습과 올렸을 때, 눌렀을 때를 나란히 적으면 여러 프레임이 하나의 규칙으로 묶입니다.

70.5 반복을 컴포넌트로

같은 카드가 열 개라면 규칙은 하나면 충분합니다. 되풀이되는 모양을 클래스로 묶어 이름을 붙입니다.


<article class="card">
<h3 class="card__title">제목</h3>
<p class="card__body">내용을 적습니다</p>
</article>


구조에 이름을 붙였으니 모양은 그 이름에 걸어 둡니다.


.card__title {
font-size: 1.125rem;
font-weight: 700;
margin: 0 0 8px;
}
.card__body {
color: #6b7280;
margin: 0;
}


카드가 몇 개로 늘어나도 손댈 곳은 이 규칙 한 벌뿐입니다. 피그마의 컴포넌트가 곧 이 클래스 한 세트에 대응합니다.

70.6 정렬로 중심 잡기

피그마에서 요소를 가운데로 옮겨 눈대중으로 맞췄다면, 코드에서는 여백을 억지로 넣는 대신 정렬 규칙으로 세웁니다.


.hero {
margin-top: 180px;
padding-left: 240px;
}


이렇게 여백으로 밀어 가운데를 흉내 내면 화면 크기가 바뀔 때 중심이 어긋납니다. 정렬 축을 직접 지정하면 어떤 크기에서도 한가운데를 지킵니다.


.hero {
display: flex;
justify-content: center;
align-items: center;
min-height: 60vh;
}


justify-content는 가로축, align-items는 세로축의 정렬을 맡습니다. 여백을 세지 않아도 내용이 늘 중앙에 놓입니다.

70.7 간격은 이름 있는 단위로

피그마에서 8, 16, 24처럼 규칙적으로 쓰던 간격은 코드에서도 낱낱의 px 대신 한 단위를 곱해 씁니다.


:root {
--space: 8px;
}
.stack {
display: flex;
flex-direction: column;
gap: calc(var(--space) * 2);
padding: calc(var(--space) * 3);
}


기준 간격 하나에 배수를 곱하니, 16px과 24px이 우연이 아니라 8의 두 배와 세 배로 이어집니다. 리듬이 무너지지 않습니다.

70.8 겹쳐 뜨는 요소

대부분의 요소는 흐름을 따라 줄지어 놓이지만, 알림 딱지처럼 다른 것 위에 떠 있어야 하는 것도 있습니다. 이때만 좌표를 씁니다.


.avatar {
position: relative;
}
.badge {
position: absolute;
top: -4px;
right: -4px;
z-index: 1;
}


부모에 relative를 두면 자식의 absolute가 그 부모를 기준으로 뜹니다. z-index는 무엇이 앞에 오는지를 정합니다. 좌표는 이렇게 떠야만 하는 요소에만 아껴 씁니다.


화면 전체를 덮는 창이라면 기준을 화면으로 삼습니다.


.modal {
position: fixed;
inset: 0;
display: flex;
justify-content: center;
align-items: center;
z-index: 100;
}


inset을 0으로 두면 상하좌우가 화면에 딱 붙습니다. 그 안에서 다시 정렬로 내용을 가운데에 세웁니다.

70.9 옮기기 좋은 디자인

옮기기 좋은 디자인은 옮기기 좋은 코드가 됩니다. 좌표 대신 관계로, 흩어진 값 대신 상속과 변수로, 낱개 대신 규칙으로 적으면 화면은 훨씬 덜 부서집니다.


.list {
display: flex;
flex-direction: column;
gap: var(--gap);
}


간격 하나까지 이름으로 부르면, 디자인과 코드가 같은 언어로 대화하게 됩니다.


버튼 하나를 예로 들면, 지금까지의 규칙이 이렇게 한자리에 모입니다.


.btn-primary {
display: inline-flex;
align-items: center;
gap: var(--space);
padding: 10px 18px;
background: var(--brand);
color: #fff;
border-radius: 8px;
transition: background 0.2s;
}


정렬과 간격, 상속받는 변수와 상태 전환이 한 규칙 안에 담깁니다. 좌표는 어디에도 없습니다.