안녕하세요! 이전 시간에 박스 모델을 활용한 형태 만들기를 배우셨다면, 이번 문서는 한 단계 더 나아간 기본 도형 함수(Basic shapes)를 사용해 복잡한 형태를 그리는 방법입니다.
단순히 네모난 박스를 벗어나 텍스트가 동그라미, 타원, 혹은 다각형 모양을 따라 흐르게 만드는 마법 같은 CSS 기술이죠! 포트폴리오의 독후감 사이트나 프로필 페이지를 만들 때, 잡지나 매거진 같은 세련된 레이아웃을 구현하고 싶다면 이 기능이 아주 유용할 겁니다.
공식 문서를 차근차근, 제 실무 팁과 함께 구어체로 완벽하게 번역해 드릴게요.
shape-outside를 사용한 기본 도형 (Basic shapes with shape-outside)CSS 도형은 <basic-shape> 타입을 사용해서 정의할 수 있습니다. 이 가이드에서는 shape-outside 속성을 사용하여 직사각형, 원, 타원, 그리고 다각형(polygon)을 만드는 방법을 다룹니다. 이 기능들은 CSS 도형 모듈(CSS shapes module)에 정의되어 있습니다.
도형을 직접 살펴보기 전에, 이 도형들을 가능하게 만드는 두 가지 핵심 개념을 먼저 이해하는 것이 좋습니다:
<basic-shape> 타입 (기본 도형 타입)<basic-shape> 타입 (The <basic-shape> type)inset()circle()ellipse()polygon()<basic-shape> 타입 (The <basic-shape> type)<basic-shape> 타입은 우리가 만들 모든 기본 도형의 값으로 사용됩니다. 이 타입은 함수 표기법(functional notation)을 따릅니다. 즉, 함수 이름 뒤에 오는 괄호 () 안에 도형을 묘사하는 인수(arguments)들이 들어간다는 뜻이죠.
이 괄호 안에 들어갈 수 있는 인수들은 여러분이 어떤 도형을 만드느냐에 따라 달라집니다. 아래의 예제들에서 하나씩 다뤄볼 예정입니다.
기본 도형을 다룰 때, CSS 도형이 사용하는 참조 박스(reference box)를 이해하는 것은 매우 중요합니다. 왜냐하면 이 참조 박스가 각 도형의 좌표계(좌표 기준점)를 정의하기 때문이죠. 여러분은 이전 가이드인 박스 값으로 도형 만들기에서 이 참조 박스라는 개념을 이미 만나본 적이 있습니다. (해당 가이드에서는 도형을 만들 때 박스 값을 직접 참조 박스로 사용했었죠.)
아래 스크린샷은 파이어폭스(Firefox)의 개발자 도구 중 '도형 검사기(Shapes Inspector)'가 shape-outside: circle(50%)를 사용해 만든 원의 참조 박스를 보여주는 모습입니다. 이 요소에는 20픽셀의 패딩(padding), 테두리(border), 마진(margin)이 적용되어 있습니다. 도형 검사기는 이러한 참조 박스 영역을 하이라이트(강조)해서 보여줍니다.

기본 도형을 사용할 때 설정되는 기본 참조 박스는 margin-box(마진 영역)입니다. 스크린샷을 보면 도형(원)이 박스 모델의 마진 영역을 기준으로 정의된 것을 확인할 수 있죠.
기본 참조 박스가 margin-box이긴 하지만, 이 기준점은 바꿀 수 있습니다. 다른 박스(예: 패딩 박스, 보더 박스 등)를 참조 박스로 설정하고 싶다면, 기본 도형을 정의하는 함수 바로 뒤에 원하는 박스 값을 적어주면 됩니다.
따라서, 아래의 두 선언은 완전히 똑같이 작동합니다 (아무것도 안 적으면 margin-box가 기본값이니까요):
shape-outside: circle(50%);
shape-outside: circle(50%) margin-box;
여러분이 만든 도형이 다른 참조 박스를 기준으로 삼게 하려면, 다른 <box-edge> 값을 적어주세요. 예를 들어, 원의 기준점을 마진이 아닌 테두리(border)로 삼고 싶다면 아래처럼 설정합니다:
.shape {
shape-outside: circle(50%) border-box; /* 테두리 안쪽으로 텍스트가 바짝 붙어 흐릅니다 */
}
주의할 점: 생성된 도형이 마진 박스(margin box) 바깥으로 넘어가게(extend past) 되면, 마진 박스를 벗어난 모양은 잘려나가게(clipped) 됩니다. 아래의 기본 도형 예제들에서 이 현상을 직접 확인하실 수 있습니다.
💡 강사의 실무 팁 1
좌표의 0,0 지점(시작점)이 어디냐를 정하는 아주 중요한 개념입니다.margin-box라면 요소의 바깥쪽 여백의 왼쪽 위 모서리가 0,0이 되고,border-box라면 테두리의 왼쪽 위 모서리가 0,0이 됩니다. 그래서 텍스트가 이미지나 요소로부터 여유를 두고 흐르게 하고 싶다면 기본값인margin-box를 두는 것이 보통 제일 안전합니다!
inset()inset() 함수는 직사각형(rectangle)을 정의합니다.
"어? 그냥 float만 줘도 기본적으로 직사각형 모양으로 텍스트가 흐르는데, 굳이 이게 왜 필요하죠?"라고 생각하실 수 있습니다. 하지만 inset() 타입은 오프셋(offsets, 간격)을 지정할 수 있다는 아주 강력한 장점이 있습니다. 즉, 텍스트가 감싸는 직사각형의 크기를 실제 떠 있는(floated) 요소의 크기보다 더 작게 줄여서, 텍스트가 요소의 일부 영역 위로 겹쳐서 흐르도록 만들 수 있습니다.
inset() 함수는 (상, 우, 하, 좌) 최대 4개의 측면 오프셋 값을 받습니다. 그리고 추가로 round라는 키워드를 쓴 뒤에 border-radius 값을 적어 모서리를 둥글게 깎을 수도 있습니다.
아래의 CSS는 떠 있는 요소(floated element)의 참조 박스를 기준으로 위와 아래에서 20px, 왼쪽과 오른쪽에서 10px씩 안쪽으로 들어간 직사각형 도형을 만듭니다. 그리고 모서리는 10px 만큼 둥글게 깎았습니다.
.shape {
float: left;
/* 상 우 하 좌 | 둥글게 | 모서리 반경 */
shape-outside: inset(20px 10px 20px 10px round 10px);
}
이 오프셋 값들은 우리가 흔히 쓰는 margin 단축 속성과 똑같은 규칙을 따릅니다. 공백으로 구분된 네 개의 값은 순서대로 상(top), 우(right), 하(bottom), 좌(left) 오프셋을 정의합니다. 물론 한 번에 여러 개의 오프셋을 설정할 수도 있죠:
따라서 방금 위에서 본 코드는 아래처럼 더 짧게 쓸 수 있습니다:
.shape {
float: left;
shape-outside: inset(20px 10px round 10px); /* 상하 20px, 좌우 10px */
}
아래 예제는 inset() 도형을 사용해서 텍스트(콘텐츠)를 떠 있는 요소 위로 끌어당긴(pull content over) 모습입니다. (오프셋 값들을 바꿔보면서 도형이 어떻게 변하는지 관찰해 보세요.)
<div class="box">
<div class="shape"></div>
<p>
One November night in the year 1782, so the story runs, two brothers sat
over their winter fire in the little French town of Annonay, watching the
grey smoke-wreaths from the hearth curl up the wide chimney. Their names
were Stephen and Joseph Montgolfier, they were papermakers by trade...
</p>
</div>
body {
font: 1.2em sans-serif;
}
.shape {
float: left;
width: 150px;
height: 100px;
/* 위 20px, 오른쪽 50px, 아래 10px, 왼쪽 0px 만큼 안으로 깎아냅니다. */
shape-outside: inset(20px 50px 10px 0 round 50px);
background-color: rebeccapurple;
border: 2px solid black;
border-radius: 10px;
margin: 20px;
padding: 20px;
}
(실행 결과: 보라색 박스의 영역과 상관없이, inset으로 깎인 보이지 않는 가상의 둥근 직사각형 모양을 따라 텍스트가 박스 위를 침범하며 흐르는 것을 볼 수 있습니다.)
circle()circle() 값은 shape-outside에서 두 가지 인수를 받을 수 있습니다: 하나는 크기를 정의하는 <shape-radius>(원의 반지름)이고, 다른 하나는 위치를 정의하는 <position>입니다.
circle()과 뒤에 나올 ellipse()(타원) 함수는 모두 인수로 <shape-radius>를 받습니다. 이 값으로는 절대적인 길이(100px 같은 <length>)나 퍼센트(50% 같은 <percentage>)를 쓸 수도 있고, closest-side(가장 가까운 면)나 farthest-side(가장 먼 면)라는 키워드를 쓸 수도 있습니다.
closest-side 키워드를 쓰면, 원의 중심에서 참조 박스의 가장 가까운 모서리(면)까지의 거리를 원의 반지름으로 삼습니다.farthest-side 키워드를 쓰면, 원의 중심에서 참조 박스의 가장 먼 모서리(면)까지의 거리를 반지름으로 삼습니다.두 번째 인수는 원의 중심점(위치)을 가리키는 position입니다. 하나 또는 두 개의 키워드로 구성된 <position> 값을 받죠. 이건 배경 이미지의 위치를 잡는 background-position과 똑같이 작성하면 됩니다. 값을 하나만 쓰거나 아예 안 쓰면, 생략된 부분의 기본값은 무조건 center(중앙)가 됩니다.
원을 만들기 위해서는 반지름(radius) 값 하나를 넣고, 선택적으로 at이라는 키워드 뒤에 위치(position) 값을 넣어주면 됩니다.
아래 예제는 너비(width)와 높이(height)가 210px이고 마진(margin)이 20px인 <img> 요소에 원형 도형을 적용했습니다. (기본 참조 박스가 마진 박스이므로 총 너비는 210 + 20 + 20 = 250px이 됩니다.)
반지름 값으로 50%를 주었으니 원의 반지름은 125px이 됩니다. 위치 값은 at 30%로 설정했는데, 이는 가로 방향으로는 왼쪽에서 30% 지점에 중심을 두고, 세로 방향으로는 아무것도 안 적었으니 기본값인 center(50%)에 중심을 두겠다는 뜻입니다.
<div class="box">
<img alt="열기구의 밑면 모습" src="round-balloon.png" />
<p>
One November night in the year 1782, so the story runs...
</p>
</div>
img {
float: left;
shape-outside: circle(50% at 30%); /* 반지름 50%, 중심점은 가로 30% 지점 */
margin: 20px;
}
(실행 결과: 열기구 이미지의 왼쪽 30% 지점을 중심으로 한 가상의 큰 원이 생기고, 그 원의 둘레를 따라 텍스트가 흐르게 됩니다.)
circle(closest-side at top left) 같이 키워드(closest-side, farthest-side)를 사용하는 것은 떠 있는 요소의 참조 박스 크기를 기반으로 빠르고 간편하게 원을 그릴 때 아주 유용합니다.
아래 예제는 가상 요소(::before)로 생성된 콘텐츠에 circle(50% at top left)를 적용한 모습입니다. 텍스트가 감싸안을 수 있도록 화면(박스)의 왼쪽 위 모서리(top left)에 정확히 '4분원(quarter circle)' 모양을 만들어줍니다. (중심이 박스의 맨 왼쪽 위 0,0 위치에 있으니 원의 1/4 조각만 박스 안으로 들어오게 되죠!)
.box::before {
content: "";
float: left;
width: 250px;
height: 250px;
shape-outside: circle(50% at top left); /* 왼쪽 위 모서리를 중심으로 한 4분원 생성 */
}
앞서 참조 박스 섹션에서 강조했듯이, margin-box 범위를 벗어난 도형은 잘려나갑니다(clipped).
위의 열기구 예제에서 중심점의 위치를 콘텐츠 쪽으로 더 당겨서 60%(circle(50% at 60%))로 바꿔보면 이를 확실히 볼 수 있습니다. 원의 중심이 콘텐츠(오른쪽)에 가까워지면서, 원의 오른쪽 테두리가 요소의 마진 박스 경계선을 넘어가게 됩니다. 이 넘어가 버린 부분은 칼로 자른 것처럼 직선으로 뚝 잘리게(squared off) 됩니다.

💡 강사의 실무 팁 2:
shape-margin활용하기
도형과 텍스트 사이가 너무 바짝 붙어서 답답해 보인다면,shape-margin: 10px;같은 속성을 추가해 보세요. 도형의 외곽선에서 지정한 픽셀만큼 텍스트를 밀어내 주어 훨씬 깔끔하고 가독성 좋은 잡지 레이아웃을 만들 수 있습니다.
ellipse()타원(ellipse)은 '찌그러진 원'입니다. 따라서 ellipse() 함수는 circle()과 거의 똑같이 작동합니다. 딱 하나 다른 점이 있다면, 원과 달리 타원은 가로 방향의 x 반지름과 세로 방향의 y 반지름, 이렇게 두 개의 반지름 값을 순서대로 적어주어야 한다는 것입니다.
그 뒤에는 circle()과 마찬가지로 타원의 중심점을 지정하기 위해 선택적으로 at 키워드와 함께 1~2개의 <position> 값을 붙일 수 있습니다.
아래 예제에서 우리는 가로(x) 반지름이 40%, 세로(y) 반지름이 50%이고, 위치(position)가 at left인 타원을 만들었습니다. 이는 타원의 중심점이 참조 박스 왼쪽 모서리의 한가운데에 위치한다는 뜻입니다. 결과적으로 텍스트가 감싸는 예쁜 '반쪽짜리 타원(half ellipse)' 모양이 만들어집니다. (이 값들을 직접 수정해 보며 타원이 어떻게 변하는지 확인해 보세요.)
.shape {
float: left;
/* 가로반지름 40%, 세로반지름 50%, 중심점은 왼쪽 끝(left) */
shape-outside: ellipse(40% 50% at left);
margin: 20px;
width: 100px;
height: 200px;
}
polygon()polygon() 함수는 훨씬 복잡하지만, 다면체 형태의 다각형(polygon)을 그릴 수 있게 해줍니다. 이 도형 함수는 3개 이상의 값의 쌍(pairs of values)을 받습니다. (다각형을 그리려면 최소한 점 3개를 이어 '삼각형'은 만들어야 하니까요.)
각각의 좌표 쌍(x, y)은 띄어쓰기로 구분하고, 각 점(vertex)과 점 사이는 쉼표(,)로 구분합니다. 이 좌표들은 참조 박스를 기준으로 찍히게 됩니다. 이 좌표 쌍들이 모여 다각형의 각 테두리(선)를 정의하게 되며, 맨 마지막에 찍은 점과 맨 처음에 찍은 점이 자동으로 연결되어 닫힌 도형이 완성됩니다.
아래 예제는 polygon() 함수를 사용하여 텍스트가 따라 흐르는 복잡한 다각형을 만듭니다. (각 꼭짓점 좌표 값들을 수정해 보면서 모양이 어떻게 바뀌는지 테스트해 보세요.)
.shape {
float: left;
shape-outside: polygon(
0px 0px, /* 첫 번째 점: 왼쪽 위 모서리 */
0px 189px, /* 두 번째 점: 왼쪽 아래로 쭉 내려옴 */
100.48% 94.71%, /* 세 번째 점: 오른쪽 아래 어딘가 */
200px 120px, /* 네 번째 점: 살짝 안쪽으로 들어옴 */
80.67% 37.17% /* 다섯 번째 점: 뾰족하게 튀어나옴 */
/* 마지막 80.67% 지점과 처음 0px 0px 지점이 자동으로 연결됩니다 */
);
width: 200px;
height: 200px;
}
이보다 더 복잡하고 자유로운 곡선의 도형을 원하신다면 path()나 shape() 함수를 사용해서 SVG처럼 완벽한 윤곽선을 그려낼 수도 있습니다.
inset(), circle(), ellipse(), polygon()은 파이어폭스 개발자 도구의 '도형 검사기(Shape Inspector)'를 사용하여 눈으로 확인하고 마우스로 드래그해서 쉽게 편집할 수 있습니다. 아래 스크린샷은 도구에서 다각형이 하이라이트된 모습입니다.

또 다른 아주 유용한 리소스(툴)로 Clippy가 있습니다. 이 도구는 원래 CSS clip-path 속성을 이용해 요소를 잘라내는 도형을 시각적으로 만드는 사이트인데, clip-path와 shape-outside는 똑같은 기본 도형 함수와 문법을 공유하기 때문에 여기서 좌표를 만들어 그대로 복사해 오면 아주 편리합니다!
💡 강사의 실무 팁 3: 무조건 도구를 활용하세요!
polygon의 점 4~5개 좌표를 머릿속으로 계산해서 코딩하는 프론트엔드 개발자는 거의 없습니다. 문서 마지막에 소개된 Clippy 사이트는 실무자들의 필수 북마크입니다. 마우스로 점을 찍고 드래그해서 예쁜 도형을 만든 뒤 밑에 나오는 CSS 코드를 그대로shape-outside에 복사/붙여넣기 하세요!
MDN 향상에 도움 주기 (Help improve MDN)
지금까지 CSS로 멋진 레이아웃을 만들 수 있는 shape-outside와 기본 도형 함수들에 대해 완벽하게 마스터하셨습니다!
준비 중이신 포트폴리오의 '독후감 사이트'에 이 기술을 활용해서, 책의 표지 이미지나 작가의 얼굴 사진 모양을 따라 리뷰 텍스트가 예쁘게 감싸도록 만들어보시는 건 어떨까요? 분명 면접관에게 큰 임팩트를 남길 수 있을 겁니다!