스위처 레이아웃

Switcher layout

가로로 나란한 배치와 세로 스택 배치 사이를 미디어 쿼리 없이 "컨테이너 자체 폭"만으로 전환하는 레이아웃.

다른 이름: Every Layout Switcher
···
html
<div class="stage" id="stage">
  <div class="switcher">
    <div class="item">One</div>
    <div class="item">Two</div>
    <div class="item">Three</div>
  </div>
</div>
css
.stage{width:20%;min-width:70px;max-width:92%;border:2px dashed var(--muted);border-radius:10px;padding:12px;
  transition:width 2.8s cubic-bezier(.4,0,.2,1)}
.stage.wide{width:92%}
.switcher{display:flex;flex-wrap:wrap;gap:8px}
.switcher .item{flex-grow:1;flex-basis:calc((220px - 100%) * 999);border-radius:8px;background:var(--accent-3);
  color:#fff;font-size:11px;font-weight:800;padding:10px;text-align:center}
js
const stage = document.getElementById('stage');
setInterval(() => stage.classList.toggle('wide'), 2400);

핵심 코드는 두 줄입니다: `.switcher { display: flex; flex-wrap: wrap }`, 그리고 자식마다 `flex-grow: 1; flex-basis: calc((var(--threshold) - 100%) * 999)`. `--threshold`(예: `30rem`)보다 스위처 자신의 폭이 넓으면 `(threshold - 100%)`가 음수가 되어 `flex-basis`가 음수로 계산되고, 음수 `flex-basis`는 `0`으로 취급되어 아이템들이 `flex-grow: 1`만으로 균등하게 한 줄에 나란히 놓입니다.

반대로 스위처 폭이 `--threshold`보다 좁아지면 `(threshold - 100%)`가 양수가 되고, 곱해진 `999`가 그 값을 거대한 양수로 부풀립니다. `flex-basis`가 사실상 무한대에 가까워지면 각 아이템은 자기 줄을 통째로 요구하게 되고, `flex-wrap: wrap`이 하나씩 다음 줄로 떨어뜨립니다 — 세로 스택이 되는 것입니다.

미디어 쿼리 버전과 결정적으로 다른 점은 "무엇을 기준으로 재는가"입니다. 미디어 쿼리는 브라우저 창 폭을 기준으로 삼지만, 이 계산은 스위처 자신의 실제 폭을 기준으로 삼습니다. 그래서 같은 스위처를 넓은 메인 영역과 좁은 사이드바에 동시에 두면, 화면 폭은 하나인데 한쪽은 가로로, 다른 쪽은 세로로 각자 알아서 배치됩니다.

언제 쓰나

탭 vs 세로 메뉴, 두 칼럼 폼 vs 한 칼럼 폼처럼 "가로/세로 두 가지 모드"만 있는 재사용 컴포넌트에 씁니다. 세 가지 이상의 중간 단계가 필요하면 컨테이너 쿼리가 더 명확합니다.