박스 모델을 익히고 나니 상자 하나하나는 이해가 됐지만, 그 상자들이 왜 어떤 건 세로로 쌓이고 어떤 건 옆으로 흐르는지는 여전히 미스터리였다. 문단은 무조건 줄바꿈이 되는데 링크는 글 사이에 자연스럽게 끼어들었다. 크기를 지정해도 먹히는 요소가 있고 무시되는 요소가 있었다. 그 모든 차이를 결정하는 열쇠가 표시 속성이었다.


이번 편은 요소가 화면에서 어떻게 배치되는지를 좌우하는 표시 속성을 다룬다. 블록과 인라인의 근본적인 차이부터, 둘의 성질을 섞은 방식, 요소를 완전히 숨기는 방식, 그리고 상자 자체를 없애 자식을 승격시키는 특별한 값까지 살펴본다. 이 속성을 이해하면 배치의 밑그림이 비로소 손에 잡힌다.

1. 블록과 인라인이라는 두 세계

표시 속성의 기본은 블록과 인라인이다. 블록 요소는 한 줄 전체를 독차지하고 위아래로 차곡차곡 쌓인다. 문단이나 제목, 구획 요소가 여기에 속한다. 반면 인라인 요소는 자기 내용만큼의 폭만 차지하고 글의 흐름을 따라 옆으로 이어진다. 링크나 강조, 인라인 코드가 대표적이다.


이 둘의 가장 큰 차이는 크기 지정 여부다. 블록 요소는 폭과 높이를 자유롭게 지정할 수 있다. 그러나 인라인 요소는 폭과 높이 지정이 사실상 무시된다. 나는 링크에 폭을 줬는데 아무 반응이 없어 한참 당황했는데, 인라인 요소라 크기 속성이 통하지 않았던 것이다.


여백의 동작도 다르다. 인라인 요소는 좌우 여백은 먹지만 위아래 여백은 레이아웃에 거의 영향을 주지 않는다. 그래서 인라인 요소로 세로 간격을 만들려는 시도는 늘 실패한다. 위아래로 공간을 벌리고 싶다면 그 요소를 블록이나 다음에 볼 혼합 방식으로 바꿔야 한다.


블록 요소는 폭을 지정하지 않으면 부모의 폭을 가득 채운다. 이건 아주 자연스러운 기본 동작이라, 나는 카드나 배너처럼 가로를 꽉 채워야 하는 요소를 만들 때 이 성질을 그대로 활용한다. 반대로 폭을 제한하고 싶으면 명시적으로 값을 주거나 최대 폭을 걸어둔다.


인라인 요소는 글자와 같은 흐름 안에 놓이기 때문에 줄 높이와 정렬의 영향을 받는다. 그래서 인라인 요소 여러 개를 나란히 놓으면 그 사이에 눈에 보이지 않는 공백이 생기기도 한다. 소스의 줄바꿈이 공백 문자로 해석되기 때문인데, 나는 이 유령 같은 틈 때문에 정렬이 어긋나 애를 먹은 적이 여러 번이다.


이 블록과 인라인의 구분은 원래 HTML 요소마다 기본으로 정해져 있다. 하지만 그 기본값은 표시 속성으로 얼마든지 바꿀 수 있다. 즉 문단을 인라인처럼, 링크를 블록처럼 만들 수 있다. 요소의 종류가 곧 배치 방식을 영원히 결정하는 게 아니라는 것, 이게 표시 속성의 자유로움이다.

2. 두 성질을 섞은 인라인 블록

블록과 인라인 사이에는 둘의 장점을 섞은 방식이 있다. 인라인 블록은 인라인처럼 옆으로 나란히 놓이면서도, 블록처럼 폭과 높이와 위아래 여백을 지정할 수 있다. 나는 이 방식을 알기 전까지 나란한 배치와 크기 지정을 동시에 원할 때마다 좌절했다.


대표적인 쓰임은 태그나 배지처럼 작은 상자들을 한 줄에 나열하는 경우다. 각각에 크기와 안쪽 여백을 주면서도 옆으로 이어 붙이고 싶을 때 인라인 블록이 딱 맞는다. 버튼을 글 흐름 속에 넣으면서 크기를 조절할 때도 유용하다. 크기가 필요한 인라인이 필요하면 이 방식을 떠올린다.


다만 인라인 블록도 인라인의 성질을 물려받아 요소 사이 공백 문제를 겪는다. 소스에서 요소들 사이에 줄바꿈이나 공백이 있으면 화면에도 미세한 틈이 생긴다. 나는 예전에 이 틈을 없애려고 소스에서 요소들을 붙여 쓰거나 주석으로 공백을 지우는 편법을 썼다. 지금은 이런 경우 대개 더 나은 배치 방식을 택한다.


인라인 블록은 정렬 기준선의 영향도 받는다. 여러 개를 나란히 놓으면 기본적으로 글자의 바닥선에 맞춰 정렬되어, 크기가 제각각이면 아래 위치가 들쭉날쭉해진다. 이때는 수직 정렬 속성으로 위나 가운데에 맞출 수 있다. 나는 아이콘과 글자를 나란히 놓을 때 이 정렬을 자주 손본다.


사실 오늘날 인라인 블록으로 하던 많은 배치 작업은 더 강력한 배치 방식으로 대체되었다. 그럼에도 인라인 블록은 여전히 쓸모가 있다. 글의 흐름 안에 크기 있는 조각을 자연스럽게 끼워 넣어야 할 때, 이만큼 간단한 방법이 없다. 나는 상황에 맞게 골라 쓴다.


정리하면 인라인 블록은 흐름을 따르되 크기를 갖는 절충안이다. 블록의 크기 지정과 인라인의 나란한 배치, 두 세계의 좋은 점을 하나로 묶는다. 다만 공백과 정렬이라는 인라인의 그림자를 함께 물려받으므로, 이 두 가지를 늘 의식하면서 써야 뒤탈이 없다.

3. 요소를 숨기는 여러 방법

요소를 화면에서 감추는 방법은 하나가 아니고, 각각 의미가 다르다. 가장 강한 것은 표시를 없음으로 두는 것이다. 이 값을 주면 요소가 렌더 트리에서 완전히 빠져 공간조차 차지하지 않는다. 접근성 트리에서도 제거되어 화면 낭독기도 그 요소를 읽지 않는다.


이와 대비되는 것이 가시성을 숨김으로 두는 방식이다. 이 경우 요소는 보이지 않지만 원래 차지하던 공간은 그대로 남는다. 마치 투명 인간처럼 자리는 지키되 모습만 사라지는 셈이다. 나는 레이아웃을 흔들지 않으면서 잠깐 감췄다 보여야 할 때 이 방식을 고른다.


투명도를 0으로 주는 방법도 있다. 이건 가시성 숨김과 비슷하게 공간을 유지하지만, 요소가 여전히 클릭에 반응하고 접근성 트리에도 남는다는 차이가 있다. 그래서 부드럽게 사라지는 애니메이션에는 좋지만, 완전히 없애려는 목적에는 맞지 않는다. 나는 이 셋의 차이를 상황마다 따진다.


화면에는 감추되 화면 낭독기에는 읽히게 하고 싶은 특수한 경우도 있다. 본문 바로가기 링크나 보조 설명이 그렇다. 이때는 표시를 없애면 안 되고, 대신 요소를 화면 밖으로 밀어내거나 아주 작게 만드는 전용 기법을 쓴다. 나는 이런 용도로 만든 감춤 클래스를 프로젝트마다 하나씩 준비해둔다.


표시 없음과 가시성 숨김의 선택은 목적에 달렸다. 공간까지 지워야 하면 없음을, 자리를 지켜야 하면 숨김을 쓴다. 접근성까지 지워야 하는지도 함께 따진다. 나는 이 판단을 대충 하다가 화면 낭독기 사용자에게 엉뚱한 내용이 읽히거나, 반대로 필요한 내용이 사라지는 실수를 저지른 적이 있다.


숨김과 관련해 HTML 자체의 속성으로 숨기는 방법도 있다는 걸 기억해두면 좋다. 다만 그 역시 내부적으로는 표시 없음과 비슷하게 동작한다. 결국 무엇으로 숨기든, 그 요소가 공간을 차지하는지 그리고 기계에 읽히는지를 명확히 아는 것이 핵심이다. 숨김은 단순해 보여도 의미가 여럿이다.

4. 상자를 없애는 특별한 값

표시 속성에는 요소의 상자 자체를 없애버리는 값이 있다. 이 값을 주면 요소는 사라지지만 그 자식들은 마치 부모의 자식인 것처럼 위로 승격된다. 즉 껍데기만 벗기고 알맹이는 남기는 것이다. 나는 처음 이걸 봤을 때 이게 대체 언제 쓰이나 싶었지만, 배치 방식과 만나면 진가를 발휘한다.


대표적인 쓰임은 불필요한 감싸개를 배치에서 제거하는 것이다. 예를 들어 여러 상자를 격자로 배열하는데, 그중 하나가 감싸개로 한 번 더 싸여 있으면 그 감싸개가 격자의 칸을 차지해버린다. 이때 감싸개의 상자를 없애면 그 안의 자식들이 직접 격자의 칸이 된다. 마크업 구조는 유지하면서 배치만 깔끔해진다.


이 값은 서버가 만들어주는 마크업을 내가 마음대로 바꿀 수 없을 때 특히 요긴하다. 구조상 어쩔 수 없이 생긴 중간 감싸개를 레이아웃에서만 투명하게 만들 수 있기 때문이다. 나는 컴포넌트 라이브러리가 씌워준 껍데기를 배치에서 지울 때 이 값을 종종 활용한다.


다만 이 값에는 주의할 점이 있다. 상자가 사라지면 그 요소에 준 배경이나 테두리, 여백 같은 상자 관련 스타일도 함께 사라진다. 상자가 없으니 칠할 곳이 없는 셈이다. 그래서 시각적 장식이 걸린 요소에는 이 값을 쓰면 안 된다. 순수하게 구조만 담당하는 감싸개에만 써야 한다.


접근성 측면에서도 조심해야 한다. 일부 요소는 상자가 사라지면서 그 요소의 의미까지 접근성 트리에서 왜곡되는 경우가 있었다. 표나 목록처럼 구조가 의미를 갖는 요소에는 특히 신중해야 한다. 나는 이 값을 쓰기 전에 화면 낭독기에서 구조가 깨지지 않는지 확인하는 습관을 들였다.


결국 상자를 없애는 값은 레이아웃을 위해 마크업의 계층을 투명하게 만드는 도구다. 강력하지만 시각 스타일과 접근성을 함께 지워버릴 수 있으니 용도가 제한적이다. 나는 이 값을 순수한 구조용 감싸개에만, 그것도 확인을 거친 뒤에만 쓴다. 알아두면 가끔 아주 요긴한 카드다.

5. 표시 속성을 배치의 출발점으로 삼기

표시 속성은 레이아웃의 가장 앞 단추다. 요소가 블록인지 인라인인지에 따라 이후의 모든 배치가 달라지기 때문이다. 나는 어떤 요소의 배치가 이상하면 가장 먼저 그 요소의 표시 값이 무엇인지 확인한다. 크기가 안 먹거나 여백이 이상하면 십중팔구 인라인 요소인 경우가 많다.


더 중요한 사실은 오늘날 배치의 주력이 두 가지 강력한 표시 값이라는 점이다. 하나는 한 방향으로 유연하게 나열하는 방식이고, 다른 하나는 행과 열의 격자를 다루는 방식이다. 이 두 값은 부모에 지정하면 그 자식들의 배치 규칙을 통째로 바꾼다. 다음 편들에서 이 둘을 깊이 파고들 예정이다.


부모에 이 배치 값을 주면 자식들은 더 이상 평범한 블록이나 인라인으로 동작하지 않고, 그 배치 문맥의 아이템이 된다. 이때 자식의 원래 표시 값은 대부분 무시되고 배치 규칙에 흡수된다. 나는 이 사실을 몰라 자식에 표시 값을 주며 왜 안 먹히나 고민한 적이 있는데, 부모의 배치 문맥이 이미 지배권을 가진 탓이었다.


표시 값을 바꿀 때는 그 변화가 자식과 형제에게 미치는 파장을 함께 생각해야 한다. 블록을 인라인으로 바꾸면 줄바꿈이 사라지고 크기 지정이 무력해진다. 인라인을 블록으로 바꾸면 갑자기 한 줄을 독차지한다. 이런 연쇄 효과를 예상하지 못하면 한 곳을 고쳤는데 엉뚱한 곳이 무너진다.


나는 새 컴포넌트를 만들 때 표시 값을 가장 먼저 결정한다. 이 조각이 세로로 쌓일지, 옆으로 흐를지, 격자로 배열될지를 정하는 것이 곧 배치의 설계도이기 때문이다. 색이나 여백 같은 디테일은 그다음이다. 배치의 골격을 먼저 세우면 이후 작업이 훨씬 수월하다.


정리하면 표시 속성은 요소가 블록처럼 쌓일지 인라인처럼 흐를지, 아니면 강력한 배치 문맥의 아이템이 될지를 결정하는 근본 스위치다. 숨김의 여러 방식과 상자를 없애는 값까지 알아두면 배치의 선택지가 넓어진다. 다음 편에서는 이 흐름을 벗어나 요소를 원하는 위치에 고정하거나 띄우는 포지셔닝을 다룬다.