LaTeX에서 글을 프레임으로 감싸려 할 때 대개 가장 먼저 치는 것은 \fbox{...} 입니다. 잘 작동합니다. 내용이 한 줄에 들어가는 동안에는요. 문단을 통째로 넘기는 순간 프레임은 줄바꿈하지 않고 종이 밖까지 뻗어 나가며, 로그에는 Overfull \hbox 가 찍힙니다. 바로 이 하나의 제약이 framed, mdframed, tcolorbox 같은 프레임 패키지들이 존재하는 이유입니다. 이 페이지는 표준 \fbox와 \framebox부터 페이지를 넘길 수 있는 프레임, 색과 제목이 붙은 패널까지를 “프레임은 왜 잘리지 않는가”라는 하나의 줄기로 따라갑니다.
\fbox와 \framebox — 표준으로 그리는 프레임, 그리고 그 벽
\fbox{...} 는 아무 패키지도 필요 없이 인수의 내용에 꼭 맞는 얇은 선을 그립니다. 폭과 정렬까지 지정하려면 \framebox[width][position]{...} 를 씁니다. 첫 번째 선택 인수가 상자의 가로폭을 정하고, 두 번째가 내용이 상자 안에 놓이는 방식을 고릅니다. c(가운데, 기본), l(왼쪽), r(오른쪽), s(양끝 맞춤)입니다. 선택 인수가 없는 \framebox는 \fbox와 완전히 같게 동작합니다. 둘 다 행 안에 놓이는 상자이고 베이스라인에 얹히므로 \hspace나 앞뒤 글자와 자연스럽게 나란히 놓입니다.
\fbox{a framed word}
% width 5cm, content flush left inside the box
\framebox[5cm][l]{flush left}
% multi-line: frame a \parbox, not the text itself
\fbox{\parbox{0.8\linewidth}{%
Several lines of text. The inner box wraps them
first, and only then does the frame go around.}}그리고 여기가 벽입니다. \fbox도 \framebox도 내용을 줄바꿈하지 않습니다. 긴 문단을 넘기면 한 줄 그대로 오른쪽으로 계속 늘어나 프레임이 종이 밖으로 밀려나고, Overfull \hbox (... too wide) 경고가 나옵니다. 버그가 아니라 정의 그대로의 동작입니다. \fbox는 인수를 수평 상자 하나, 즉 \hbox로 조판하는데, \hbox 안에는 줄바꿈 지점 자체가 없습니다. 여러 줄을 감싸려면 위 예처럼 먼저 \parbox나 minipage로 문단을 만들고 그 상자를 감싸면 됩니다. \parbox와 minipage 자체는 “상자” 페이지에서 다룹니다. 다만 이 방법도 프레임이 페이지 경계를 넘어야 하는 순간 막힙니다. 그 이유는 곧 살펴봅니다.
\fboxrule과 \fboxsep — 선을 두껍게, 안쪽 여백을 넓게
프레임의 모양은 길이 두 개로만 정해집니다. \fboxrule은 선 두께이고 표준 클래스의 기본값은 0.4pt, \fboxsep은 선과 내용 사이의 여백(패딩)이며 기본값은 3pt입니다. 둘 다 \setlength로 바꿉니다. 기본값 0.4pt는 본문만큼 가늘어서, 상자를 주의문처럼 눈에 띄게 하려면 대개 부족합니다. 다만 이들은 평범한 전역 길이라서 프리앰블에서 바꾸면 문서 안의 모든 \fbox가 함께 바뀝니다. 한 군데만 두껍게 하려면 아래처럼 그룹 {...} 안에서 \setlength를 하십시오. color나 xcolor를 불러오면 똑같은 두 길이를 따르는 \fcolorbox{선색}{배경색}{...} 도 쓸 수 있습니다. 색 이름과 혼색은 “색(xcolor)” 페이지에 있습니다.
% global: every \fbox in the document becomes thicker
\setlength{\fboxrule}{1pt}
\setlength{\fboxsep}{8pt}
% local: the group limits the change to this one box
{\setlength{\fboxrule}{2pt}\fbox{a heavy frame}}
% same two lengths, plus colour (needs color or xcolor)
\fcolorbox{red}{yellow!20}{warning}프레임은 왜 페이지를 넘어 나뉘지 못할까
답은 단순합니다. 선을 두른 재료는 상자 하나가 되고, TeX의 페이지 분할기는 세로로 놓인 요소들 “사이”에서만 자를 수 있을 뿐 상자 안쪽은 절대 자르지 못합니다. 감싸는 순간 그 재료는 페이지를 자를 수 있는 후보 목록에서 사라집니다. 여기서 “나뉘는 프레임”의 정체도 드러납니다. 사실 하나의 프레임이 잘리는 일은 없습니다. 패키지가 먼저 내용을 페이지에 들어갈 크기로 나누고, 조각마다 별도의 프레임을 그린 다음, 이음매가 보이지 않도록 쌓아 올리는 것입니다.
Donald Arseneau의 framed 패키지는 그 구조를 설계 표면에 그대로 드러냅니다. 문서에 따르면 나뉜 환경의 첫 조각에는 \FirstFrameCommand, 중간 조각들에는 \MidFrameCommand, 마지막 조각에는 \LastFrameCommand가 적용됩니다. oframed 환경이 페이지 분할 지점에서 위아래가 열린 프레임이 되는 이유가 바로 이것입니다. 양 끝과 이음매에 서로 다른 명령을 써서, 잘린 자리에는 가로선을 그리지 않는 것입니다. framed.sty의 저작권 표시는 1992년부터 시작하는데, 이 문제가 LaTeX2e보다도 오래되었음을 말해 줍니다. 구조가 “먼저 나누고 나중에 꾸미기”인 이상 한계도 자연히 따라옵니다. 나뉘는 프레임 안의 각주, 플로트, 단 넘김 재료는 깨지기 쉬우며, tcolorbox와 mdframed의 매뉴얼도 이를 주의 사항으로 적어 두었습니다.
framed 패키지 — framed / shaded / leftbar 세 환경
\usepackage{framed} 한 줄만으로 페이지 나눔을 견디는 환경 세 개가 생깁니다. framed는 본문 폭 전체에 선을 그리고, shaded는 선 대신 배경을 칠하며, leftbar는 왼쪽 여백에 굵은 세로선 하나를 그립니다. 인용이나 보충 설명 블록의 표시로 자주 쓰입니다. shaded 계열을 쓰려면 shadecolor라는 이름의 색이 먼저 있어야 합니다. \definecolor{shadecolor}{gray}{0.9}처럼 직접 정의하거나, xcolor를 불러와 \colorlet{shadecolor}{gray!15}라고 씁니다. 잊으면 친절한 안내가 아니라 색이 정의되지 않았다는 오류로 컴파일이 멈춥니다.
\usepackage{framed}
\usepackage{xcolor}
\colorlet{shadecolor}{gray!15}
% these lengths are the framed counterparts of
% \fboxrule and \fboxsep
\setlength{\FrameRule}{1pt}
\setlength{\FrameSep}{10pt}
\begin{framed}
A long note. If it reaches the bottom of the page the
frame is split and continues on the next one, which is
precisely what \fbox cannot do.
\end{framed}
\begin{shaded}
Filled background instead of a rule.
\end{shaded}
\begin{leftbar}
A single vertical rule in the left margin.
\end{leftbar}치수는 \FrameRule과 \FrameSep으로 조정합니다. 패키지 문서가 분명히 밝히듯, 이 둘은 framed 환경 안에서 \fboxrule과 \fboxsep을 대신하는 길이입니다. 환경 앞뒤의 세로 공백은 \OuterFrameSep이며 기본값은 \topsep과 같습니다. 파생 환경도 몇 가지 따라옵니다. shaded*는 채움의 가장자리를 본문 폭에 맞추고(별표 없는 shaded는 여백 쪽으로 조금 삐져나갑니다), snugshade와 snugshade*는 내용에 바싹 붙으며, oframed는 앞 절에서 본 분할 지점이 열린 프레임입니다. 여기서 더 나아가 \FrameCommand를 직접 정의하고 \MakeFramed ... \endMakeFramed로 감싸면 원하는 어떤 “나뉘는 장식”도 만들 수 있습니다. 문서는 오히려 그것이 이 패키지의 더 일반적인 목적이라고 말합니다. 반대로 framed에는 둥근 모서리도 그림자도 제목도 없습니다. 그것이 필요해지면 한 단계 올라갑니다.
수식을 감싸는 \boxed — 속을 보면 결국 \fbox
결론 수식을 감싸려면 \usepackage{amsmath}를 불러오고 수식 모드 안에서 \boxed{...}를 씁니다. 인수를 수식으로 조판한 뒤 프레임을 붙여 주는 명령입니다. 재미있는 것은 그 정의입니다. amsmath 안에서 \boxed는 사실상 \fbox{\m@th$\displaystyle#1$} 그대로 쓰여 있습니다. 별도의 그리기 방식이 아니라 수식을 $...$로 감싸 \fbox에 넘길 뿐입니다. 여기서 실무적 결론 세 가지가 나옵니다. \fboxrule과 \fboxsep이 그대로 적용된다는 것, 당연히 페이지를 넘을 수 없다는 것, 그리고 \displaystyle이 강제되므로 첨자 안에 \boxed를 쓰면 감싼 식만 본문 크기로 크게 나온다는 것입니다.
\usepackage{amsmath}
\[
\boxed{E = mc^2}
\]
% \fbox inside math sets its argument in TEXT mode:
% upright roman letters, not math italic
$\fbox{x+y}$ \quad versus \quad $\boxed{x+y}$둘을 나란히 놓아 보면 차이가 분명합니다. $\fbox{x+y}$는 인수를 문자 모드로 조판하므로 x도 y도 정체(로만체)가 되고, + 앞뒤의 간격도 수식의 것이 아닙니다. $\boxed{x+y}$는 수식 이탤릭과 수식 간격을 지킵니다. 수식 안에서 프레임이 필요하면 망설이지 말고 \boxed를 쓰십시오. 식 번호까지 함께 감싸거나 align의 여러 줄에 걸쳐 감싸는 복잡한 요구에는 mathtools에 함께 제공되는 empheq 패키지가 알맞습니다. 수식 모드 자체는 “수식 모드의 기본” 페이지를 참조하십시오.
tcolorbox — 색과 제목, 그리고 breakable
색과 제목과 페이지 나눔을 한 번에 해결하고 싶다면 답은 tcolorbox입니다. \usepackage[most]{tcolorbox}로 불러오고, tcolorbox 환경에 colback=(배경색), colframe=(선 색), title=(제목 띠), breakable(페이지 나눔 허용)을 넘깁니다. 여기서 가장 걸려 넘어지기 쉬운 대목이 most의 역할입니다. tcolorbox는 본체와 수많은 라이브러리로 나뉘어 있고, breakable은 옵션 이름인 동시에 라이브러리 이름이기도 합니다. \usepackage{tcolorbox}만 쓰고 breakable을 지정해도 라이브러리가 불러와지지 않았으므로 프레임은 나뉘지 않습니다. [most]를 붙이거나 \tcbuselibrary{breakable}을 명시해야 합니다. 소스를 보면 most는 many(raster, skins, breakable, hooks, theorems, fitting)에 listingsutf8, external, magazine, vignette, poster를 더한 것으로, 외부 도구에 의존하는 minted만 빠져 있습니다.
\usepackage[most]{tcolorbox}
\begin{tcolorbox}[colback=blue!5, colframe=blue!60!black,
title=Remarks, fonttitle=\bfseries, breakable]
A coloured box with a title bar. Because breakable was
given, a long body is split across the page boundary.
\end{tcolorbox}
% inline, fitted to its content, no page breaks
\tcbox[colback=red!5, colframe=red!60!black]{inline box}모양은 수치 키로 다듬습니다. boxrule=이 선 두께(기본 0.5mm), arc=이 둥근 모서리 반지름(기본 1mm)이고, 직각으로 하려면 sharp corners, 기본값인 둥근 모서리를 쓰려면 rounded corners입니다. 제목 띠의 배경색은 colbacktitle=, 제목 글꼴은 fonttitle=(\bfseries 같은 것을 넘깁니다)입니다. 행 안에 작은 프레임 하나만 놓을 때는 환경 대신 \tcbox{...}를 씁니다. \fbox처럼 내용에 맞게 줄어들고, \fbox처럼 나뉘지 않습니다. 그 밑에는 pgf가 있습니다. 본체는 pgf를 요구하고, most에 포함된 skins 라이브러리는 tikz 자체를 요구합니다. 그래서 enhanced를 지정하면 TikZ의 그리기 능력이 그대로 앞으로 나와 그림자, 이중 프레임, 투명도, 장식적 제목까지 쓸 수 있습니다. 정리형 상자를 만드는 theorems 라이브러리, \tcblower로 상자를 위아래 두 칸으로 나누어 소스 위에 출력을 놓는 방식 등 기능은 끝이 없습니다.
“끝이 없다”는 말은 비유가 아닙니다. TeX Live 2024에 들어 있는 tcolorbox 매뉴얼(texdoc tcolorbox로 열립니다)은 548쪽입니다. 상자를 그리는 패키지 하나의 설명서로는 웬만한 전문서적입니다. 저자는 Thomas F. Sturm이며, LaTeX에서 CSV 파일을 읽는 csvsimple과 가계도를 조판하는 genealogytree도 같은 사람이 만들었습니다. 실무적인 조언은 그 548쪽을 통독하려 들지 말라는 것입니다. colback, colframe, title, breakable 네 개만으로 대부분의 문서가 필요로 하는 것은 거의 다 됩니다. 정말 공들이고 싶어질 때 매뉴얼 색인을 찾아보는 정도가 현실적입니다.
\newtcolorbox로 같은 프레임 재사용하기
같은 옵션 묶음을 본문에서 몇 번이고 되풀이해 쓰면, 색을 바꾸고 싶어지는 날 반드시 후회합니다. 프리앰블에서 \newtcolorbox로 한 번만 정의하십시오. 형식은 \newtcolorbox[init options]{name}[인수 개수][기본값]{options}이며, \newenvironment처럼 인수를 받는 환경도 만들 수 있습니다. 환경이 아니라 명령이 필요하면 \newtcbox를, 문서 전체의 기본값을 한꺼번에 바꾸려면 \tcbset{...}을 씁니다. 익혀 둘 만한 습관이 하나 있습니다. blueroundbox 같은 겉모습 이름이 아니라 note, warning, definition처럼 의미로 이름을 붙이는 것입니다. 그러면 나중에 배색을 바꾸는 일이 본문 전체 치환이 아니라 프리앰블 몇 줄 수정으로 끝납니다.
\usepackage[most]{tcolorbox}
% one argument: the heading text
\newtcolorbox{note}[1]{%
colback=yellow!10, colframe=orange!70!black,
fonttitle=\bfseries, title=#1, breakable}
\begin{document}
\begin{note}{Careful}
The note environment is now defined; its heading
arrives as an argument.
\end{note}
\end{document}mdframed — framed와 tcolorbox 사이
framed보다 보기 좋으면서 tcolorbox만큼 무겁지 않은, 페이지를 넘길 수 있는 프레임을 원한다면 mdframed가 바로 그 자리에 있습니다. \usepackage{mdframed}로 불러오고, mdframed 환경의 선택 인수에 backgroundcolor=, roundcorner=, linecolor=, linewidth= 같은 키를 넘깁니다. 이 패키지가 왜 만들어졌는지는 소스 첫머리에 저자 자신의 말로 적혀 있습니다. \fbox나 \fcolorbox를 쓰면 페이지 나눔을 손으로 처리해야 하는데, mdframed 환경은 그것을 자동으로 다룬다고 말입니다. 이 페이지가 출발점으로 삼았던 \fbox의 제약이 그대로 다른 패키지의 존재 이유로 명문화되어 있는 셈입니다. 구현 역시 framed.sty의 발상을 바탕으로 한다고 소스에 분명히 적혀 있습니다.
\usepackage{mdframed}
\begin{mdframed}[backgroundcolor=gray!10, roundcorner=5pt,
linecolor=gray!60, linewidth=1pt]
An mdframed box. It breaks across pages.
\end{mdframed}
% a named environment of your own, and a framed theorem
\newmdenv[linecolor=red, linewidth=1.5pt]{alert}
\newmdtheoremenv{prop}{Proposition}특징은 그리기 백엔드를 고를 수 있다는 점입니다. framemethod=default는 표준 LaTeX 명령으로 그리고, framemethod=TikZ나 framemethod=pstricks로 바꾸면 더 정교한 장식을 쓸 수 있습니다. 자주 쓰는 설정은 \mdfsetup{...}에 모아 둘 수 있습니다. 자신만의 프레임 환경은 \newmdenv{...}로, 프레임이 붙은 정리 환경은 \newmdtheoremenv{...}로 정의합니다. 알아 둘 만한 사실이 하나 있습니다. 현재 mdframed는 버전 1.9b, 날짜는 2013년 7월 1일이며, 소스에는 이 패키지가 베타 상태라는 문장이 지금도 남아 있습니다. 그럼에도 10년 넘게 TeX Live에 실려 왔고 실제로 잘 작동합니다. 다만 새 문서에서 본격적으로 손댈 생각이라면, 지금도 활발히 유지되는 tcolorbox 쪽이 더 안전한 선택입니다.
\fbox와 tcolorbox 중 무엇을 쓸까 — 한눈에 보기
기준은 사실 하나, 감쌀 재료의 크기입니다. 단어 하나나 한 줄이면 \fbox / \framebox, 수식이면 \boxed, 문단 묶음을 담백하게 감싸기만 하면 framed, 색과 둥근 모서리가 필요하면 mdframed, 제목과 페이지 나눔과 장식까지 원하면 tcolorbox입니다. 망설여질 때는 그 상자가 페이지 나눔을 견뎌야 하는지를 먼저 자문하십시오. 이 한 가지 질문으로 후보가 두 무리로 깔끔하게 갈립니다. 실무적인 조언 하나를 더하자면, framed와 tcolorbox를 한 문서에서 함께 써도 충돌하지는 않지만, 전체 인상을 통일하고 싶다면 하나로 좁히는 편이 결과가 좋습니다.
| 명령·패키지 | 감쌀 대상 | 페이지 나눔 | 알맞은 상황 |
|---|---|---|---|
\fbox / \framebox | 한 줄에 들어가는 내용 | 불가 | 단어나 짧은 문장을 빠르게 |
\boxed | 수식(수식 모드) | 불가 | 결론이 되는 식 강조 |
framed | 문단 묶음 | 가능 | 장식 없이 가볍게 감싸기 |
mdframed | 문단 묶음 | 가능 | 적은 수고로 색과 둥근 모서리 |
tcolorbox | 문단, 행 안, 정리 환경 | 가능(breakable) | 제목·배색·장식까지 한 번에 |