CSS 논리적 속성: margin-inline, padding-block 완전 가이드

이런 경험 있으신가요?

웹사이트를 다국어로 지원하려고 할 때 이런 문제를 만난 적 있나요? 영어 버전에서는 완벽하게 보이던 레이아웃이, 아랍어나 히브리어(오른쪽에서 왼쪽으로 읽는 언어)로 바꾸면 모든 여백과 정렬이 어색해지는 상황.

예를 들어, 아이콘이 텍스트 왼쪽에 있어야 하는데 RTL(Right-to-Left) 레이아웃에서는 오른쪽에 있어야 자연스럽습니다. 이걸 위해 CSS를 두 벌 작성하고, [dir="rtl"] 선택자로 일일이 오버라이드하는 것은 정말 번거로운 일이죠.

/* ❌ 전통적인 방식: 언어별로 따로 관리 */
.button {
  margin-left: 8px;
}

[dir="rtl"] .button {
  margin-left: 0;
  margin-right: 8px; /* 모든 속성마다 이렇게... */
}

바로 이럴 때 CSS 논리적 속성(Logical Properties)이 등장합니다.

/* ✅ 논리적 속성: 자동으로 적응 */
.button {
  margin-inline-start: 8px; /* LTR에서는 left, RTL에서는 right */
}

먼저, 기초부터 이해하기

물리적 속성 vs 논리적 속성

전통적인 CSS는 물리적 방향(physical direction)을 사용합니다. top, right, bottom, left는 화면의 절대적인 위치를 나타내죠.

물리적 방향 (Physical)
       top
        ↑
left ← [ ] → right
        ↓
      bottom

하지만 논리적 속성(logical properties)은 콘텐츠의 흐름(content flow)을 기준으로 합니다.

논리적 방향 (Logical)
    block-start
        ↑
inline-start ← [ ] → inline-end
        ↓
     block-end

핵심 개념:

  • block: 콘텐츠가 블록으로 쌓이는 방향 (수직 스크롤 방향)
  • inline: 텍스트가 한 줄로 흐르는 방향 (읽는 방향)

왜 이게 필요한가요?

쓰기 방향(writing mode)은 언어와 문화에 따라 다릅니다:

쓰기 방향 언어 예시 inline 방향 block 방향
horizontal-tb (기본) 한국어, 영어 왼쪽→오른쪽 위→아래
horizontal-tb + RTL 아랍어, 히브리어 오른쪽→왼쪽 위→아래
vertical-rl 전통 일본어, 중국어 위→아래 오른쪽→왼쪽
vertical-lr 몽골어 위→아래 왼쪽→오른쪽

논리적 속성을 사용하면 하나의 CSS로 모든 쓰기 방향에 대응할 수 있습니다.

margin-inline, margin-block: 무엇이 다른가?

margin의 물리적 속성

전통적인 margin은 절대적 방향을 사용합니다.

/* 물리적 속성 */
.element {
  margin-top: 10px;
  margin-right: 20px;
  margin-bottom: 10px;
  margin-left: 20px;
}

margin의 논리적 속성

논리적 속성은 콘텐츠 흐름을 기준으로 합니다.

/* 논리적 속성 */
.element {
  margin-block-start: 10px;   /* 블록 시작 (보통 위) */
  margin-inline-end: 20px;     /* 인라인 끝 (LTR: 오른쪽, RTL: 왼쪽) */
  margin-block-end: 10px;      /* 블록 끝 (보통 아래) */
  margin-inline-start: 20px;   /* 인라인 시작 (LTR: 왼쪽, RTL: 오른쪽) */
}

단축 속성 (Shorthand)

더 간결하게 작성할 수 있습니다:

/* 전통적 margin */
.element {
  margin: 10px 20px; /* 상하 좌우 */
}

/* 논리적 margin */
.element {
  margin-block: 10px;   /* block-start와 block-end */
  margin-inline: 20px;  /* inline-start와 inline-end */
}

비교표: 물리적 vs 논리적

물리적 속성 논리적 속성 (LTR 기준) 논리적 속성 (RTL 기준)
margin-top margin-block-start margin-block-start
margin-bottom margin-block-end margin-block-end
margin-left margin-inline-start margin-inline-end
margin-right margin-inline-end margin-inline-start

핵심: RTL에서는 inline-startinline-end가 자동으로 바뀝니다!

padding도 마찬가지입니다

padding도 정확히 같은 원리로 작동합니다.

/* 물리적 padding */
.card {
  padding-top: 16px;
  padding-right: 24px;
  padding-bottom: 16px;
  padding-left: 24px;
}

/* 논리적 padding */
.card {
  padding-block-start: 16px;
  padding-inline-end: 24px;
  padding-block-end: 16px;
  padding-inline-start: 24px;
}

/* 단축 속성 */
.card {
  padding-block: 16px;   /* 상하 */
  padding-inline: 24px;  /* 좌우 (방향 자동 조정) */
}

전통적 속성과의 차이점

margin과 padding의 전통적 shorthand:

/* 4개 값: 시계방향 (위 오른쪽 아래 왼쪽) */
margin: 10px 20px 30px 40px;

/* 2개 값: 상하, 좌우 */
margin: 10px 20px;

논리적 속성의 shorthand:

/* 2개 값: start, end */
margin-block: 10px 20px;   /* start: 10px, end: 20px */
margin-inline: 30px 40px;  /* start: 30px, end: 40px */

/* 1개 값: start와 end 동일 */
margin-block: 10px;        /* start와 end 모두 10px */
margin-inline: 20px;       /* start와 end 모두 20px */

중요한 차이점:

  • 전통적 shorthand는 4방향을 한 번에 (top, right, bottom, left)
  • 논리적 shorthand는 2방향씩 분리 (block은 block끼리, inline은 inline끼리)

쓰기 모드 변경

vertical-rl (세로쓰기, 오른쪽에서 왼쪽)

.vertical-text {
  writing-mode: vertical-rl;
  padding-block: 20px;   /* 이제 좌우 패딩이 됨 */
  padding-inline: 16px;  /* 이제 상하 패딩이 됨 */
}

시각화:

horizontal-tb (기본)         vertical-rl
┌─────────────┐            ┌─────┐
│ block:      │            │ b   │
│ ↓           │            │ l → │
│ inline: →   │            │ o   │
│             │            │ c   │
└─────────────┘            │ k   │
                           └─────┘

실제 예제:

<style>
.book-title {
  writing-mode: vertical-rl;
  padding-block: 24px;      /* 실제로는 좌우 패딩 */
  padding-inline: 16px;     /* 실제로는 상하 패딩 */
  background: #f5f5f5;
  font-size: 24px;
}
</style>

<div class="book-title">日本語の本</div>

horizontal-tb + RTL (아랍어, 히브리어)

<style>
.rtl-content {
  direction: rtl;
  padding-inline-start: 24px; /* RTL에서 오른쪽 패딩 */
}
</style>

<div class="rtl-content" dir="rtl">
  <p>مرحبا بك في موقعنا</p>
</div>

다른 논리적 속성들

margin과 padding 외에도 많은 속성이 논리적 버전을 가지고 있습니다:

border

/* 물리적 */
border-top: 1px solid black;
border-right: 2px solid blue;

/* 논리적 */
border-block-start: 1px solid black;
border-inline-end: 2px solid blue;

/* 단축 */
border-block: 1px solid black;
border-inline: 2px solid blue;

위치 (inset)

/* 물리적 */
.element {
  position: absolute;
  top: 0;
  left: 0;
}

/* 논리적 */
.element {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
}

/* 단축 */
.element {
  position: absolute;
  inset-block: 0;    /* top + bottom */
  inset-inline: 0;   /* left + right */
}

크기

/* 물리적 */
width: 300px;
height: 200px;

/* 논리적 */
inline-size: 300px;  /* 인라인 방향 크기 */
block-size: 200px;   /* 블록 방향 크기 */

min/max 크기

/* 물리적 */
max-width: 1200px;
min-height: 400px;

/* 논리적 */
max-inline-size: 1200px;
min-block-size: 400px;

텍스트 정렬

/* 물리적 */
text-align: left;

/* 논리적 */
text-align: start;  /* LTR: left, RTL: right */
text-align: end;    /* LTR: right, RTL: left */

float

/* 물리적 */
float: left;

/* 논리적 */
float: inline-start;  /* LTR: left, RTL: right */
float: inline-end;    /* LTR: right, RTL: left */

전환 가이드: 언제 사용할까?

논리적 속성을 사용해야 할 때

다국어 지원이 필요한 프로젝트

/* 여러 언어를 지원하는 글로벌 서비스 */
.button__icon {
  margin-inline-end: 8px;
}

RTL 언어 (아랍어, 히브리어, 페르시아어 등) 지원

.card {
  padding-inline: 20px;
}

세로쓰기를 사용하는 경우 (일본어, 중국어 전통 서적 등)

.vertical-text {
  writing-mode: vertical-rl;
  margin-block: 20px;
}

미래 지향적 코드를 작성하고 싶을 때

/* 나중에 다국어 지원이 필요할 수도 */
.layout {
  padding-inline: 24px;
}

물리적 속성을 계속 사용해도 되는 경우

단일 언어만 지원하고 변경 계획 없음

/* 한국어만 지원하는 내부 관리 도구 */
.header {
  padding-left: 20px;
  padding-right: 20px;
}

특정 방향이 중요한 경우 (예: 애니메이션)

/* 항상 왼쪽에서 오른쪽으로 슬라이드 */
@keyframes slideIn {
  from { transform: translateX(-100%); }
  to { transform: translateX(0); }
}

레거시 브라우저 지원이 필수인 경우

/* IE11 지원 필요 */
.element {
  margin-left: 20px; /* 논리적 속성 미지원 */
}

점진적 전환 전략

새 프로젝트나 리팩토링 시 점진적으로 전환:

/* 1단계: margin, padding부터 시작 */
.element {
  /* 변경 전 */
  margin-left: 20px;
  margin-right: 20px;

  /* 변경 후 */
  margin-inline: 20px;
}

/* 2단계: border 추가 */
.element {
  border-left: 1px solid black;
  border-inline-start: 1px solid black;
}

/* 3단계: 위치와 크기 */
.element {
  width: 300px;
  inline-size: 300px;
}

흔한 실수와 함정

1. 물리적 + 논리적 속성 혼용

/* ❌ 혼란스럽고 예측 불가능 */
.element {
  margin-left: 10px;           /* 물리적 */
  margin-inline-start: 20px;   /* 논리적 - 덮어씀! */
}

/* ✅ 하나만 사용 */
.element {
  margin-inline-start: 20px;
}

주의: 논리적 속성이 나중에 선언되면 물리적 속성을 덮어씁니다!

2. shorthand 혼동

/* ❌ 이렇게 쓸 수 없음 */
.element {
  margin: 10px 20px; /* 전통적 shorthand */
  margin-block: 15px; /* 일부만 덮어쓰려고 시도 - 예상과 다름! */
}

/* ✅ 명확하게 분리 */
.element {
  margin-block: 15px;   /* 상하 */
  margin-inline: 20px;  /* 좌우 */
}

3. text-align: left 대신 start 사용

/* ❌ RTL에서 예상과 다름 */
.element {
  text-align: left; /* RTL에서도 왼쪽 정렬됨 */
}

/* ✅ 논리적 속성 사용 */
.element {
  text-align: start; /* RTL에서 자동으로 오른쪽 */
}

4. transform에서 사용 불가

/* ❌ transform은 논리적 속성 미지원 */
.element {
  transform: translateInlineStart(100px); /* 존재하지 않음! */
}

/* ✅ CSS 변수로 해결 */
.element {
  --offset: 100px;
}

[dir="rtl"] .element {
  --offset: -100px;
}

.element {
  transform: translateX(var(--offset));
}

5. calc()에서 방향 고려 안 함

/* ❌ RTL에서 의도와 다를 수 있음 */
.element {
  left: calc(50% - 100px);
}

/* ✅ 논리적 속성 사용 */
.element {
  inset-inline-start: calc(50% - 100px);
}

6. gap은 이미 논리적임을 잊음

/* ✅ gap은 이미 논리적 속성 */
.flex-container {
  display: flex;
  gap: 16px; /* 자동으로 방향 대응 - 추가 작업 불필요 */
}

/* ❌ 불필요한 걱정 */
.flex-container {
  gap: 16px;
  /* RTL용 추가 CSS? 필요 없음! */
}

브라우저 지원

속성 Chrome Firefox Safari Edge
margin-inline/block 87+ 66+ 14.1+ 87+
padding-inline/block 87+ 66+ 14.1+ 87+
border-inline/block 87+ 66+ 14.1+ 87+
inset-inline/block 87+ 63+ 14.1+ 87+
inline-size/block-size 57+ 41+ 12.1+ 79+

좋은 소식: 모든 모던 브라우저에서 지원합니다!

레거시 지원:

/* Fallback 제공 */
.element {
  margin-left: 20px;                /* IE11 등 */
  margin-inline-start: 20px;        /* 모던 브라우저 */
}

/* 또는 @supports */
@supports (margin-inline-start: 0) {
  .element {
    margin-inline-start: 20px;
  }
}

@supports not (margin-inline-start: 0) {
  .element {
    margin-left: 20px;
  }
}

테스트 방법

1. HTML dir 속성으로 테스트

<!-- LTR 테스트 -->
<div dir="ltr">
  <div class="element">English content</div>
</div>

<!-- RTL 테스트 -->
<div dir="rtl">
  <div class="element">محتوى عربي</div>
</div>

2. Chrome DevTools

  1. Elements 패널 열기
  2. 요소 선택
  3. Computed 탭에서 실제 적용된 값 확인
  4. HTML에 dir="rtl" 추가하고 변화 관찰

3. 브라우저 확장

  • RTL Tester (Chrome Extension)
  • Force RTL (Firefox Add-on)

4. 실제 번역 테스트

<html lang="ar" dir="rtl">
  <!-- 실제 아랍어 콘텐츠로 테스트 -->
</html>

마무리

CSS 논리적 속성은 글로벌 웹을 만드는 필수 도구입니다.

핵심 요약:

  • margin-inline/block: 쓰기 방향에 자동 적응
  • padding-inline/block: 동일한 원리로 작동
  • inline: 텍스트 흐름 방향 (LTR: 좌우, RTL: 우좌)
  • block: 블록 쌓임 방향 (보통 상하)
  • 자동 대응: RTL/LTR/세로쓰기 모두 하나의 CSS로
  • ⚠️ 주의사항: 물리적 속성과 혼용 금지, transform 미지원

언제 사용할까?

  1. 다국어 지원 프로젝트
  2. RTL 언어 지원
  3. 세로쓰기 사용

전통적 속성 vs 논리적 속성:

/* 전통적: 방향 고정 */
margin-left: 20px;     /* 항상 왼쪽 */

/* 논리적: 방향 자동 */
margin-inline-start: 20px;  /* LTR: 왼쪽, RTL: 오른쪽 */

한 번 익숙해지면, 논리적 속성이 훨씬 자연스럽게 느껴지실 겁니다. “왼쪽에 여백”이 아니라 “시작 지점에 여백”이라고 생각하면, 모든 쓰기 방향에서 의미가 명확하니까요!

여러분의 프로젝트에서 논리적 속성을 사용해보셨나요? RTL 지원하면서 어떤 어려움을 겪으셨는지 궁금합니다!

Happy coding! 🌍✨

참고 자료

댓글