모달·윈도우 팝업 안에 목록(표) 을 넣을 때의 표준입니다.
시안 정본은 ppt-41-42 의 전체항목 그리드이고, 퍼블이 그걸 그리는 규칙을 그대로 씁니다.
💡 한 줄 요약 — 스크롤 컨테이너는 표를 감싸는 div 하나, 그리고 높이를 직접 준다. <div class="board-tbl 스크롤러"> > <table> 구조에
display:block · height · overflow-y:auto 를 주고, thead th 에 position:sticky;top:0 + 배경.
퍼블도 똑같이 합니다 — util.css:322.shuttle-cont .board-tbl{display:block;overflow-y:auto;height:235px}
⚠ flex 로 높이를 '받으려' 하지 마세요. .modal-cont > .wrap > .grid 처럼 중첩해 놓고 flex:1 로 높이를 흘려보내는 방식은
단계마다 min-height:0 이 필요하고, 한 곳만 빠져도 조용히 실패합니다
(표가 안 줄고 → 스크롤바가 안 생기고 → 부모가 대신 스크롤되어 머리글·버튼이 밀려 나갑니다).
실제로 통합코드 팝업에서 이 실패를 여러 번 겪었습니다. 높이는 스크롤러에 직접 주는 게 표준입니다.
부득이 flex 를 써야 하면 flex:1 1 0 로 두세요 — auto 는 기준이 '내용 크기'라 축소 계산이 어긋납니다.
1. 기본형 — 모달 + 목록
가장 흔한 경우. 래퍼에 board-tbl 을 주면 퍼블 표 스킨(테두리·머리글 배경·셀 여백)이 전부 따라옵니다.
거기에 스크롤 클래스 하나만 덧붙이면 끝입니다.
⚠ 윈도우 팝업 레이아웃은 퍼블 CSS 를 로드하지 않습니다(normalize/popup/style.css 만).
그래서 data-tbl 같은 퍼블 클래스가 안 걸립니다 — 표 스킨을 값으로 직접 그려야 합니다.
페이지 자체가 창(또는 iframe) 높이에 맞아야 하므로 html,body{height:100%} 부터 잡습니다.
실제 적용 사례는 data/dwnlSvc/unifCodeSearch.jsp 입니다.
아래는 전부 다운로드 서비스 팝업 전환(2026.08)에서 실제로 하루씩 잡아먹은 것들입니다.
머리글이 본문과 같이 스크롤된다
→ 스크롤러가 둘이다. 바깥(.modal-cont 등)이 스크롤되면 sticky 머리글은 그 안에서
같이 밀려 올라간다. 스크롤러는 반드시 하나.
머리글 위/뒤로 본문 행이 비친다
→ ① sticky 요소에 배경이 없다(투명이면 그대로 통과한다)
② 스크롤포트에 padding-top 이 있다 — sticky 의 top:0 은 padding 안쪽 기준이라
그 padding 자리에 내용이 비친다. 스크롤러의 padding-top 은 0 으로.
머리글 위에 글자 한 줄이 비친다
→ <caption> 이다. 퍼블·앱 base.css 는 caption 을 감추지만
윈도우 팝업 레이아웃은 그 CSS 를 안 불러서 실제로 그려진다.
스크롤하면 표 위쪽 선이 사라진다
→ 퍼블은 그 선을 <table> 에 건다(common.css:867 + util.css:11 `.data-tbl table{border-top-width:1px}`).
표는 스크롤되는 쪽이라 같이 올라가 버린다. → 표의 것은 끄고(`> table{border-top-width:0}`)
스크롤 컨테이너에 border-top 을 건다. 컨테이너는 안 움직이니 늘 제자리다.
스크롤하면 머리글의 테두리만 사라진다
→ border-collapse:collapse 에서 테두리는 표에 속해 sticky 셀과 같이 안 움직인다.
머리글 선은 border 말고 box-shadow(inset) 로 그릴 것.
하단 버튼이 모달 바닥에 딱 붙는다
→ 버튼줄(.modal-footer board-button)이 .modal-cont 밖(= .modal-body 직속)에 있다. 그래야 footer 로 고정된다.
안에 넣어야 `.modal-cont{padding:30px}`(common.css:948)을 받는다.
하단 버튼이 잘려 안 보인다
→ 버튼줄이 스크롤 영역 안에 있다. 버튼줄은 스크롤러 밖(flex:none).
브라우저를 좁히면 오른쪽 열이 통째로 사라진다
→ 스크롤러가 `overflow:hidden; overflow-y:auto` 다(퍼블 셔틀 기본값). 가로가 넘치면 말없이 잘린다.
→ `overflow:auto` + 표에 `min-width` 를 주어 그 아래로는 가로 스크롤되게 한다.
체크박스가 칸 가운데로 안 온다
→ 보이는 상자는 `label:before` 가 label 왼쪽 끝에 그린다(board.css:759~760).
래퍼(span)가 가운데여도 래퍼 안에 군더더기 폭이 있으면 상자만 왼쪽으로 밀린다.
⚠ 셀 padding(좌우 대칭)은 원인이 아니고, 래퍼에 flex 를 걸어도 안 통했다(실측).
→ label 에 직접 `display:block; width:18px; margin:0 auto`.
스크롤바가 아예 안 생긴다 / 표가 안 줄어든다
→ flex 로 높이를 받는 구조에서 어느 단계의 min-height:0 이 빠졌거나 flex-basis 가 auto 다.
스크롤러에 height 를 직접 주면 이 부류가 통째로 사라진다.
표 스킨(테두리·머리글 배경)이 하나도 안 걸린다
→ 래퍼 클래스에 '-tbl' 이 없거나, 래퍼와 <table> 사이에 div 가 끼어 있다.
퍼블 엔진 선택자가 `[class*="-tbl"] > table` 이라 직계 자식이어야 한다.
높이를 늘려도 목록이 안 늘어난다 (max-height 를 키워도 그대로)
→ 옛 CSS 가 height 고정값을 걸어 둔 것이다. max-height 는 height 를 이기지 못한다.
dlService.css:442 .appfrom-box .data-table .scroll{height:180px}
dlService.css:136 .scroll{height:503px} ← 스코프 없는 전역!
→ 내 규칙에 height:auto 를 함께 주어 고정값을 먼저 풀어야 max-height 가 의미를 갖는다.
⚠⚠ 클래스 이름만으로 옛 전역 CSS 가 딸려온다 (같은 계열 함정)
→ 흔한 단어를 옛 CSS 가 선점하고 있다. 새 마크업에 아래 이름을 쓰면 원치 않는 스타일이 붙는다.
'scroll' → dlService.css:136 .scroll{height:503px}
'-tbl' 포함 → css/common.css:667~801 옛 표 엔진(굵은 검은 윗선 등)
'close' 포함 → 퍼블 .modal-body [class*='close'] → 우측 상단 X 자리로 절대배치
→ 새로 만들 때는 이런 이름을 피하거나, 쓸 거면 무엇이 딸려오는지 확인하고 덮을 것.
⚠⚠ 윈도우 팝업에서 굵은 검은 윗선이 생기고, CSS 를 고쳐도 안 없어진다
→ 클래스 이름에 '-tbl' 이 들어가서앱 css/common.css:667~801 의 표 엔진에 걸린 것이다.
(퍼블 것을 흉내 낸 앱 시절 버전이 아직 살아 있고, 팝업도 commonJs.jsp 로 이걸 로드한다)
[class*="-tbl"] table{border-top:2px solid var(--gray-90)} ← 그 검은 선
[class*="-tbl"] * > tr{height:50px} · * > tr > *{padding:10px;font-size:16px}
선이 <table> 에 걸려 있어 스크롤하면 그 선만 사라지는 특징이 있다.
→ 퍼블 CSS 가 없는 윈도우 팝업에서 표 스킨을 직접 그릴 때는 클래스명에 '-tbl' 을 피할 것
(예: .pop-grid). 반대로 모달(퍼블 CSS 로드됨)에서는 '-tbl' 을 일부러 써서 퍼블 스킨을 탄다.