Tbody 가로 스크롤 - Tbody galo seukeulol

일반적으로 테이블은 다음과 같은 형태로 만듭니다.

<table width="100%" border="0" cellspacing="0" cellpadding="0">

<tr>

<td></td>

<td></td>

...

<td></td>

</tr>

</table>

좀 더 보기 좋게 짠다면 thead 나 tbody 등의 태그를 사용하기도 하고, colgroup 태그를 활용할 수 있습니다. 테이블 태그에 대한 내용은 이번 포스팅 주제가 아니므로 접어두고,

위의 테이블은 웹 브라우저의 너비(또는 테이블이 다른 table 또는 div 영역에 속한 경우, 해당 영역의 최대치)에 맞추어 너비가 가변적 변하며, 화면에 최대치(100%)로 표시됩니다.

그런데 위의 <td> 태그 내에 표시해야할 내용이 많거나 <td> 사이즈가 고정되어 화면을 100% 사용했음에도 불구하고 너비를 벗어나는 경우가 있을 수 있습니다.

이러한 경우, 즉 테이블 내용이 테이블의 영역을 벗어나는 경우, 스크롤을 넣으면 한 결 더 보기가 좋지 않을까요?

테이블에 스크롤을 넣는 방법은 div태그를 이용하는 것입니다.

table을 div로 감싸고, div를 원하는 사이즈로 고정한 뒤, table 내부의 내용이 div 사이즈를 벗어나는 경우, 스크롤을 생성시키는 방법입니다. (즉, 정확하게 말하면 테이블 자체에 스크롤이 생기는 것이 아니라 div 태그에 생성되는 것이지요.

<div style="width:100%;height:200px;overflow:auto">

<table width="100%" border="0" cellspacing="0" cellpadding="0">

<tr>

<td></td>

<td></td>

...

<td></td>

</tr>

</table>

</div>

실제 코드도 위와 같이 간단합니다.

div는 너비를 100%로, 높이를 200픽셀로 잡았습니다. div 내의 테이블에 내용이 위의 div 공간을 벗어나게 되면 스크롤이 생기게 됩니다. 너비는 자신이 가질 수 있는 영역 최대치(100%)를 초과한 경우, 높이는 200픽셀을 초과한 경우, 스크롤이 나타납니다.

이는 위의 overflow 라는 스타일 속성 때문인데요. overflow 는 해당 태그의 범위를 벗어나는 객체를 표현해야 하는 경우, 어떻게 처리할지에 대한 설정을 할 수 있는 속성이며, 다음과 같은 옵션이 있습니다.

overflow:auto : 영역 범위를 벗어나지 않으면 그대로 표시하고, 벗어나면 스크롤바를 표시합니다.

overflow:scroll : 영역 범위의 초과 여부 상관없이 항상 테이블에 스크롤을 표시합니다.

overflow:hidden : 영역을 초과하더라도 스크롤을 표시하지 않습니다. 

가로 또는 세로 스크롤을 별도로 지정합니다.

overflow-x:scroll : 가로(너비) 스크롤만 표시합니다.

overflow-y:scroll : 세로(높이) 스크롤만 표시합니다.

overflow-x:hidden : 가로(너비) 스크롤만 표시하지 않습니다.

overflow-y:hidden : 세로(높이) 스크롤만 표시하지 않습니다.

눈치 채셨을 수도 있겠지만, 이번 포스팅은 테이블 스크롤에 관한 것이지만, 사실 스크롤이 필요한 모든 태그 개체에 적용할 수 있습니다.

이전에 작성한 글 중에 css의 position: sticky를 이용하여 테이블의 헤더를 간단하게 고정하는 방법을 올린적이 있었다.

2020/05/18 - [Web-Front/HTML] - [HTML]테이블 헤더 고정하는 방법

[HTML]테이블 헤더 고정하는 방법

position: sticky를 활용해서 테이블의 헤더를 고정시키는 방법입니다. 이 방법이 좋은이유는 테이블이 가로스크롤에 대해서는 자연스럽게 스크롤되면서 세로스크롤에서는 헤더가 고정이 됩니다.

usang0810.tistory.com

쉽지만 유용한 방법이라 괜찮았었는데 댓글중에 헤더에서 rowspan을 사용했을 때 문제가 발생하는 것 같아서 확인해 보았다.

Tbody 가로 스크롤 - Tbody galo seukeulol
sticky multi header issue

실제로 테스트해보니 첫번째 헤더위에 두번재 헤더가 올라가면서 의도치 않은 문제가 발생한다.

해결방법을 찾는과정에서 sticky는 유지하면서 사용하고, javascript의 개입을 최소화 시키면서 적용시키고 싶었다.

다음의 블로그에서 해결방법을 찾을 수 있었다.

velog.io/@drawyourmind/table-thead-%EA%B3%A0%EC%A0%95%EA%B3%BC-tbody-%EC%8A%A4%ED%81%AC%EB%A1%A4

table thead 고정과 tbody 스크롤

image HR시스템이 유난히 테이블과의 싸움이다. 그중 하나가 헤더 고정 이슈인데 이 한개가 아니고 colspan, rowspan으로 셀이 합쳐지면서 헤더가 고정되는 부분들이 있다보니 은근히 노가다 이슈

velog.io

Tbody 가로 스크롤 - Tbody galo seukeulol

해결방법을 보면 sticky를 적용시키는 헤더의 높이만큼 top에 크기를 주어서 해결한다. 

#userListTable th,
#userListTable td {
    width: 20%;
    height: 23px;
    border-right: 1px solid lightgray;
}

.sticky-head-one {
    position: sticky;
    top: 0px;
}

.sticky-head-two {
    position: sticky;
    top: 23px;
}
Tbody 가로 스크롤 - Tbody galo seukeulol
이슈 해결

rowspan이나 colspan이나 적용이 잘 되고 header가 몇줄이 되든 높이값만큼 top의 크기를 늘려가면 잘 적용이 된다.

전체 코드

더보기

<!DOCTYPE html>

<html lang="ko">

<head>

    <meta charset="UTF-8">

    <title>test</title>

    <style>

        * {

            box-sizingborder-box;

        }

        .tableWrapper {

            width400px;

            height300px;

            background-colorlightgreen;

            overflowauto;

        }

        #userListTable {

            width500px;

            border0px;

            border-collapsecollapse;

            positionrelative;

        }

        #userListTable th,

        #userListTable td {

            width20%;

            height23px;

            border-right1px solid lightgray;

        }

        #userListTable th:last-child,

        #userListTable td:last-child {

            border-right0px !important;

        }

        #userListTable tr:nth-child(odd) {

            background-colorblanchedalmond;

        }

        #userListTable thead th {

            background-colorgray !important;

        }

        .sticky-head-one {

            positionsticky;

            top0px;

        }

        .sticky-head-two {

            positionsticky;

            top23px;

        }

    </style>

</head>

<body>

    <div class="tableWrapper">

        <table id="userListTable">

            <thead>

                <tr>

                    <th rowspan="2" class="sticky-head-one">1번헤더</th>

                    <th colspan="2" class="sticky-head-one">2,3번헤더</th>

                    <th rowspan="2" colspan="2" class="sticky-head-one">4,5번헤더</th>

                </tr>

                <tr>

                    <th class="sticky-head-two">2서브헤더</th>

                    <th class="sticky-head-two">3서브헤더</th>

                </tr>

            </thead>

            <tbody>

                <tr>

                    <td>1</td>

                    <td>2</td>

                    <td>3</td>

                    <td>4</td>

                    <td>5</td>

                </tr>

                <tr>

                    <td>1</td>

                    <td>2</td>

                    <td>3</td>

                    <td>4</td>

                    <td>5</td>

                </tr>

                <tr>

                    <td>1</td>

                    <td>2</td>

                    <td>3</td>

                    <td>4</td>

                    <td>5</td>

                </tr>

                <tr>

                    <td>1</td>

                    <td>2</td>

                    <td>3</td>

                    <td>4</td>

                    <td>5</td>

                </tr>

                <tr>

                    <td>1</td>

                    <td>2</td>

                    <td>3</td>

                    <td>4</td>

                    <td>5</td>

                </tr>

                <tr>

                    <td>1</td>

                    <td>2</td>

                    <td>3</td>

                    <td>4</td>

                    <td>5</td>

                </tr>

                <tr>

                    <td>1</td>

                    <td>2</td>

                    <td>3</td>

                    <td>4</td>

                    <td>5</td>

                </tr>

                <tr>

                    <td>1</td>

                    <td>2</td>

                    <td>3</td>

                    <td>4</td>

                    <td>5</td>

                </tr>

                <tr>

                    <td>1</td>

                    <td>2</td>

                    <td>3</td>

                    <td>4</td>

                    <td>5</td>

                </tr>

                <tr>

                    <td>1</td>

                    <td>2</td>

                    <td>3</td>

                    <td>4</td>

                    <td>5</td>

                </tr>

                <tr>

                    <td>1</td>

                    <td>2</td>

                    <td>3</td>

                    <td>4</td>

                    <td>5</td>

                </tr>

                <tr>

                    <td>1</td>

                    <td>2</td>

                    <td>3</td>

                    <td>4</td>

                    <td>5</td>

                </tr>

                <tr>

                    <td>1</td>

                    <td>2</td>

                    <td>3</td>

                    <td>4</td>

                    <td>5</td>

                </tr>

                <tr>

                    <td>1</td>

                    <td>2</td>

                    <td>3</td>

                    <td>4</td>

                    <td>5</td>

                </tr>

                <tr>

                    <td>1</td>

                    <td>2</td>

                    <td>3</td>

                    <td>4</td>

                    <td>5</td>

                </tr>

            </tbody>

        </table>

    </div>

</body>

</html>