고정 헤더가있는 HTML 테이블?


231

열 머리글이 화면에 고정되어 있고 표 본문으로 스크롤되지 않도록 긴 HTML 표를 표시하는 브라우저 간 CSS / JavaScript 기술이 있습니까? Microsoft Excel의 "고정 창"효과를 생각해보십시오.

테이블의 내용을 스크롤 할 수 있지만 항상 맨 위에 열 머리글을 볼 수 있기를 원합니다.


3
이것을보십시오 : 고정 헤더가있는 순수 CSS 스크롤 가능 테이블 편집 :이 예제 는 Internet Explorer 7에서 작동해야합니다 : 고정 헤더가있는 HTML 테이블 스크롤 편집 2 : 사용할 수있는 몇 가지 추가 링크를 찾았습니다 :- 바보 fixed header-일부 제한이있는 jQuery 플러그인. - [고정 테이블 헤더 ( cross-browser.com/x/examp은
gcores

나는 일반적으로 작동하는 많은 솔루션을 보았지만 어느 것도 스크롤 div에서 작동하지 않았습니다. 내 말은, 테이블이 스크롤 가능한 div 안에 있고 여전히 div 안에 테이블 머리글을 원한다는 것을 의미합니다. 나는 그것을 해결하고 여기 에서 해결책을 공유합니다 .
Yogee

9
2018 년에 모든 브라우저는 다음과 같은 간단한 솔루션을 사용할 수 있습니다 thead th { position: sticky; top: 0; }. Safari에는 공급 업체 접두사가 필요합니다.-webkit-sticky
Daniel Waltrip

1
@DanielWaltrip 당신은 최고의 자리에 투표 할 수 있도록이 답변을 추가해야합니다-다른 모든 답변은 위치와 중복됩니다 : 스티커 현재 요즘 더 나은 지원
Peter Kerr

답변:


88

나는 이것에 대한 해결책을 잠시 찾고 있었고 대부분의 답변이 작동하지 않거나 내 상황에 적합하지 않다는 것을 알았으므로 jQuery를 사용하여 간단한 솔루션을 작성했습니다.

솔루션 개요는 다음과 같습니다.

  1. 고정 헤더가 필요한 테이블을 복제하고 복제 된 사본을 원본 위에 놓으십시오.
  2. 상단 테이블에서 테이블 본체를 제거하십시오.
  3. 하단 테이블에서 테이블 헤더를 제거하십시오.
  4. 열 너비를 조정하십시오. (우리는 원래 열 너비를 추적합니다)

다음은 실행 가능한 데모의 코드입니다.

function scrolify(tblAsJQueryObject, height) {
  var oTbl = tblAsJQueryObject;

  // for very large tables you can remove the four lines below
  // and wrap the table with <div> in the mark-up and assign
  // height and overflow property  
  var oTblDiv = $("<div/>");
  oTblDiv.css('height', height);
  oTblDiv.css('overflow', 'scroll');
  oTbl.wrap(oTblDiv);

  // save original width
  oTbl.attr("data-item-original-width", oTbl.width());
  oTbl.find('thead tr td').each(function() {
    $(this).attr("data-item-original-width", $(this).width());
  });
  oTbl.find('tbody tr:eq(0) td').each(function() {
    $(this).attr("data-item-original-width", $(this).width());
  });


  // clone the original table
  var newTbl = oTbl.clone();

  // remove table header from original table
  oTbl.find('thead tr').remove();
  // remove table body from new table
  newTbl.find('tbody tr').remove();

  oTbl.parent().parent().prepend(newTbl);
  newTbl.wrap("<div/>");

  // replace ORIGINAL COLUMN width				
  newTbl.width(newTbl.attr('data-item-original-width'));
  newTbl.find('thead tr td').each(function() {
    $(this).width($(this).attr("data-item-original-width"));
  });
  oTbl.width(oTbl.attr('data-item-original-width'));
  oTbl.find('tbody tr:eq(0) td').each(function() {
    $(this).width($(this).attr("data-item-original-width"));
  });
}

$(document).ready(function() {
  scrolify($('#tblNeedsScrolling'), 160); // 160 is height
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>

<div style="width:300px;border:6px green solid;">
  <table border="1" width="100%" id="tblNeedsScrolling">
    <thead>
      <tr><th>Header 1</th><th>Header 2</th></tr>
    </thead>
    <tbody>
      <tr><td>row 1, cell 1</td><td>row 1, cell 2</td></tr>
      <tr><td>row 2, cell 1</td><td>row 2, cell 2</td></tr>
      <tr><td>row 3, cell 1</td><td>row 3, cell 2</td></tr>
      <tr><td>row 4, cell 1</td><td>row 4, cell 2</td></tr>			
      <tr><td>row 5, cell 1</td><td>row 5, cell 2</td></tr>
      <tr><td>row 6, cell 1</td><td>row 6, cell 2</td></tr>
      <tr><td>row 7, cell 1</td><td>row 7, cell 2</td></tr>
      <tr><td>row 8, cell 1</td><td>row 8, cell 2</td></tr>			
    </tbody>
  </table>
</div>

이 솔루션은 Chrome 및 IE에서 작동합니다. jQuery를 기반으로하므로 다른 jQuery 지원 브라우저에서도 작동합니다.


4
내용이 너비보다 클 때 어떻게 문제를 해결할 수 있습니까?
Maertz

1
@tet td {최대 너비 : 30px; } 이렇게하면 개발자가 행 표시 방법을 제어 할 수 있습니다.
Lyuben Todorov

그러나 일부 헤더 셀의 내용이 td 셀보다 긴 경우 어떻게해야합니까? IE7에서 시도했지만 width ()가 모든 것을 중단합니다. IE8 및 IE9 잘 작동하지만 ...
JustAMartin

4
불행히도 열의 완벽한 픽셀 정렬이 필요한 경우에는 작동하지 않습니다. jsbin.com/elekiq/1 ( 소스 코드 ). 일부 헤더는 원래 위치와 약간 떨어져 있음을 알 수 있습니다. jsbin.com/elekiq/2 ( 소스 코드 ) 배경을 사용하는 경우 효과가 더 분명합니다 . (나는이 같은 줄을 따라 일하고 있었고, 내 코드에서 이것에 부딪 쳤고, 당신을 발견하고 "아, 그가 나를 위해 그것을 해결했는지 궁금합니다!"라고 생각했습니다. 슬프게도 아닙니다 : :)) 브라우저는 세포의 폭 ...
TJ Crowder 2016 년

가로 스크롤에서는 작동하지 않는 것 같습니다. 헤더를 만들지 만 스크롤 가능 영역을 넘어서 (눈에 보이게) 확장되며 내용과 함께 스크롤되지 않습니다.
Crash

183

이것은 네 줄의 코드로 깔끔하게 해결 될 수 있습니다.

최신 브라우저에만 관심이 있다면 CSS 변환을 사용하여 고정 헤더를 훨씬 쉽게 얻을 수 있습니다. 이상하게 들리지만 훌륭하게 작동합니다.

  • HTML과 CSS는 그대로 유지됩니다.
  • 외부 JavaScript 종속성이 없습니다.
  • 네 줄의 코드.
  • 모든 구성 (테이블 레이아웃 : 고정 등)에서 작동합니다.
document.getElementById("wrap").addEventListener("scroll", function(){
   var translate = "translate(0,"+this.scrollTop+"px)";
   this.querySelector("thead").style.transform = translate;
});

Internet Explorer 8을 제외하고 CSS 변환 지원이 광범위하게 제공 됩니다.

다음은 참조를위한 전체 예입니다.


8
이전의 의견에도 불구하고 이것이 내가 본 완벽한 솔루션에 가장 가까운 것이라고 말해야합니다. 가로 스크롤조차도 완벽합니다 (내 솔루션보다 낫습니다). 여기에 테두리 예 (당신이 국경 붕괴 사용할 수 없습니다)와 스크롤입니다 대신 컨테이너의 테이블에 스틱 : jsfiddle
DoctorDestructo

11
결과는 작동하지만 thead가 아닌 th / td에 변환을 적용해야합니다.
빨간 머리

5
@AlexAlexeev, 솔루션이 훌륭합니다. 감사합니다. 결과 고정 헤더에는 열을 구분하는 경계선이 없습니다. 기본 CSS 스타일이 손실됩니다. 내가 이것을 포함하더라도 ... $(this).addClass('border')표의 나머지 부분은 테두리 클래스에서 전달하는 글꼴, 크기, 색상을 변경합니다. 그러나 고정 헤더에는 행을 추가하지 않습니다. 이 문제를 해결하는 방법에 대한 의견을
보내

5
@ user5249203 몇 달 전에 요청한 것을 알고 있지만 동일한 문제가 발생했으며 border-collapse로 인한 것입니다 : 이것을 참조하십시오 : stackoverflow.com/questions/33777751/… .
archz

6
IE 버전이나 Edge에서는 작동하지 않습니다. @redhead
rob

58

방금 유효한 HTML (thead 및 tbody가 있어야 함)을 사용하여 유효한 단일 테이블을 가져 와서 고정 된 머리글, 복제 된 머리글 또는 임의의 고정 바닥 글이있는 고정 바닥 글이있는 테이블을 출력하는 jQuery 플러그인 작성을 완료했습니다. 선택한 콘텐츠 (페이지 매김 등) 더 큰 모니터를 이용하려면 브라우저 크기를 조정할 때 테이블 크기도 조정됩니다. 테이블 열을 모두 볼 수없는 경우 추가 된 다른 기능으로 측면 스크롤을 수행 할 수 있습니다.

http://fixedheadertable.com/

github에서 : http://markmalek.github.com/Fixed-Header-Table/

설치가 매우 쉽고 자신 만의 스타일을 만들 수 있습니다. 또한 모든 브라우저에서 둥근 모서리를 사용합니다. 방금 발표 한 내용이므로 기술적으로 베타 버전이며 해결해야 할 사소한 문제는 거의 없습니다.

Internet Explorer 7, Internet Explorer 8, Safari, Firefox 및 Chrome에서 작동합니다.


감사! 오늘 퇴근 후 새로운 릴리즈를 추가하고 있습니다. 다음은 내가 추가하고있는 블로그 항목의 링크입니다. fixedheadertable.mmalek.com/2009/10/07/…
Mark

감사합니다. 나는이 질문이 1 년이 지난 것을 알고 있지만, 정착 된 미사를 자극 할 위험이 있다고해도, 당신의 작업에 감사를 표하고
싶습니다

데모에서, 너비는 ie6 :-( 테이블 헤더와 본문이 정렬되지 않았습니다.
Cheekysoft

4
IE6에서는 최신 버전이 작동하지 않습니다. 더 이상 IE6을 지원하지 않습니다.
Mark

훌륭한 작업 표시-불행히도 모바일 장치 (iPad, Android 태블릿)의 고정 헤더 및 열 스크롤에 일부 문제가 있습니다. 콘텐츠를 스크롤 할 때 해당 고정 부분이 스크롤되지 않는 경우-스크롤을 중지하고 테이블을 한 번 탭하면 , 고정 부품이 올바른 위치로 "점프"-이 문제를 해결하는 간단한 방법이 있습니까?
Okizb

23

또한이 문제를 해결하는 플러그인을 만들었습니다. 내 프로젝트 -jQuery.floatThead 는 4 년 넘게 있었고 매우 성숙했습니다.

외부 스타일이 필요하지 않으며 테이블을 특정 방식으로 스타일을 지정할 필요가 없습니다. Internet Explorer9 + 및 Firefox / Chrome을 지원합니다.

현재 (2018-05)에는 다음이 있습니다.

GitHub에서 405 개의 커밋 및 998 개의 별


여기에 많은 답변이 전부는 아니지만 한 사람이 겪고있는 문제를 해결할 수있는 빠른 해킹이지만 모든 테이블에서 작동하지는 않습니다.

다른 플러그인 중 일부는 오래되었으며 Internet Explorer에서 잘 작동하지만 Firefox 및 Chrome에서는 작동하지 않습니다.


1
훌륭한 플러그인, 중첩 테이블 및 오프셋을 지원합니다.
Mihai Alex

2
큰. 고마워 플러그인은 Firefox 45.2, Chromium 51 및 IE 11에서 잘 작동했습니다. 또한 동일한 페이지에 빌드 된 많은 JS 및 jQuery 코드를 방해하지 않습니다.
Aldo Paradiso

감사합니다. 이 시점에서 프로젝트가 4 개월마다 1 건의 버그보고를 받는다는 것을보고하게되어 기쁩니다. 나는 많은 주요 변화를 만들고 있지 않습니다. 꽤 단단하고 작동합니다.
mkoryak

20

TL; DR

최신 브라우저를 대상으로하고 화려한 스타일링이 필요하지 않은 경우 : http://jsfiddle.net/dPixie/byB9d/3/ ... 빅 4 버전 은 꽤 달콤하지만이 버전은 유동적 인 너비를 훨씬 더 잘 처리합니다.

모두 좋은 소식입니다!

HTML5 및 CSS3의 발전으로 이제는 최신 브라우저에서 가능합니다. 내가 생각해 낸 약간의 해시 구현은 http://jsfiddle.net/dPixie/byB9d/3/ 에서 찾을 수 있습니다 . FX 25, Chrome 31 및 IE 10에서 테스트했습니다 ...

관련 HTML (문서 상단에 HTML5 문서 유형 삽입) :

html,
body {
  margin: 0;
  padding: 0;
  height: 100%;
}

section {
  position: relative;
  border: 1px solid #000;
  padding-top: 37px;
  background: #500;
}

section.positioned {
  position: absolute;
  top: 100px;
  left: 100px;
  width: 800px;
  box-shadow: 0 0 15px #333;
}

.container {
  overflow-y: auto;
  height: 200px;
}

table {
  border-spacing: 0;
  width: 100%;
}

td+td {
  border-left: 1px solid #eee;
}

td,
th {
  border-bottom: 1px solid #eee;
  background: #ddd;
  color: #000;
  padding: 10px 25px;
}

th {
  height: 0;
  line-height: 0;
  padding-top: 0;
  padding-bottom: 0;
  color: transparent;
  border: none;
  white-space: nowrap;
}

th div {
  position: absolute;
  background: transparent;
  color: #fff;
  padding: 9px 25px;
  top: 0;
  margin-left: -25px;
  line-height: normal;
  border-left: 1px solid #800;
}

th:first-child div {
  border: none;
}
<section class="positioned">
  <div class="container">
    <table>
      <thead>
        <tr class="header">
          <th>
            Table attribute name
            <div>Table attribute name</div>
          </th>
          <th>
            Value
            <div>Value</div>
          </th>
          <th>
            Description
            <div>Description</div>
          </th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>align</td>
          <td>left, center, right</td>
          <td>Not supported in HTML5. Deprecated in HTML 4.01. Specifies the alignment of a table according to surrounding text</td>
        </tr>
        <tr>
          <td>bgcolor</td>
          <td>rgb(x,x,x), #xxxxxx, colorname</td>
          <td>Not supported in HTML5. Deprecated in HTML 4.01. Specifies the background color for a table</td>
        </tr>
        <tr>
          <td>border</td>
          <td>1,""</td>
          <td>Specifies whether the table cells should have borders or not</td>
        </tr>
        <tr>
          <td>cellpadding</td>
          <td>pixels</td>
          <td>Not supported in HTML5. Specifies the space between the cell wall and the cell content</td>
        </tr>
        <tr>
          <td>cellspacing</td>
          <td>pixels</td>
          <td>Not supported in HTML5. Specifies the space between cells</td>
        </tr>
        <tr>
          <td>frame</td>
          <td>void, above, below, hsides, lhs, rhs, vsides, box, border</td>
          <td>Not supported in HTML5. Specifies which parts of the outside borders that should be visible</td>
        </tr>
        <tr>
          <td>rules</td>
          <td>none, groups, rows, cols, all</td>
          <td>Not supported in HTML5. Specifies which parts of the inside borders that should be visible</td>
        </tr>
        <tr>
          <td>summary</td>
          <td>text</td>
          <td>Not supported in HTML5. Specifies a summary of the content of a table</td>
        </tr>
        <tr>
          <td>width</td>
          <td>pixels, %</td>
          <td>Not supported in HTML5. Specifies the width of a table</td>
        </tr>
      </tbody>
    </table>
  </div>
</section>

그러나 어떻게?!

간단히 표 머리글을 지정하면 0px 높이로 시각적으로 숨기고 고정 머리글로 사용되는 div가 포함됩니다. 테이블의 컨테이너는 상단에 충분한 공간을 남겨두고 절대적으로 배치 된 헤더를 허용하고 스크롤 막대가있는 테이블이 예상대로 나타납니다.

위의 코드는 배치 된 클래스를 사용하여 테이블을 절대적으로 배치합니다 (팝업 스타일 대화 상자 positioned에서 사용하고 있음). 컨테이너 에서 클래스를 제거하여 문서 흐름에서 테이블을 사용할 수 있습니다 .

그러나 ...

완벽하지 않습니다. Firefox는 헤더 행을 0px로 만드는 것을 거부하지만 (적어도 나는 찾지 못했습니다) 최소한 4px로 고집스럽게 유지합니다 ... 큰 문제는 아니지만 스타일에 따라 테두리 등이 엉망이됩니다.

이 테이블은 컨테이너 자체의 배경색이 헤더 div의 배경으로 사용되는 가짜 열 접근 방식을 사용합니다.

요약

요구 사항, 특히 테두리 또는 복잡한 배경에 따라 스타일 문제가있을 수 있습니다. 계산 능력에 문제가있을 수도 있지만 아직 다양한 브라우저에서 확인하지는 않았지만 (해보면 경험에 의견을 보내십시오), 나는 그와 같은 것을 찾지 못하여 게시 할 가치가 있다고 생각했습니다. 어쨌든 ...


가로 스크롤이 시작될 때까지 창의 너비를 줄이면 헤더가 본문과 가로로 스크롤되지 않습니다. 꿰매다.
dlaliberte

@dlaliberte-글쎄, 헤더와 테이블은 실제로 두 가지 다른 요소이기 때문에 당연히 이상하게 될 수 있습니다. 그러나 내 예제는 테이블 열에서 오버플로를 허용하지 않으며 일반적으로 테이블 내용보다 헤더를 제어하기가 더 쉽습니다. 즉, 테이블 오른쪽에 튀어 나와 심각하게 깨진 것처럼 머리글이 "오버플로"되는 경우가 있습니다. 테이블에 최소 너비를 설정하여 페이지를 오버플로하도록 강요하여이 문제를 해결할 수 있습니다.하지만 해킹이므로 완벽하지는 않습니다 ...
Jonas Schubert Erlandsson

1
이를 위해서는 고정 높이 테이블을 지정할 수있는 디자인이 필요합니다.
Cheekysoft

1
@Cheekysoft-아니요. 테이블과 행 내용이 자유롭게 흐를 수 있습니다. 내 예제에서 <section>요소 는 컨테이너 를 오버플로하고 스크롤을 표시하도록 높이를 제한해야합니다. 컨테이너 오버플로를 만드는 모든 레이아웃이 작동합니다. 그렇지 않은 경우 바이올린에 대한 링크를 게시하십시오.
Jonas Schubert Erlandsson

하드 코딩 된 padding-top값은 또한 테이블 제목 텍스트가 둘 이상의 행에있는 경우 테이블 셀 위에 표시됨을 의미합니다. 동정은 대부분 매력처럼 작동하기 때문입니다. 대부분의 다른 솔루션이 가지고있는 열 크기 문제를 해결하기 위해 divin 을 사용하여 정말 좋은 트릭입니다 th.
Bernhard Hofmann

19

CSS 사양 외부에서 이것을 해결하려는 모든 시도는 우리가 정말로 원하는 것의 창백한 그림자입니다. THEAD의 묵시적 약속에 대한 전달.

이 고정 된 표에 대한 문제는 오랫동안 HTML / CSS에서 열린 상처였습니다.

완벽한 세상에는이 문제에 대한 순수한 CSS 솔루션이 있습니다. 불행히도, 좋은 곳은없는 것 같습니다.

이 주제와 관련된 표준 토론은 다음과 같습니다.

업데이트 : Firefox position:sticky는 버전 32로 출시 되었습니다. 모두가 승리합니다!


같은 방식으로 여우 기둥을 갖는 것이 좋을 것입니다
Csaba Toth

4
레. Firefox 및 position : sticky, 테이블 헤더에서 작동하지 않습니다. bugzilla.mozilla.org/show_bug.cgi?id=925259#c8 ... 해당 버그에 대한 패치는 다음과 같이 명시되어 있습니다. "현재 상대 위치 지정을 지원하지 않습니다 "내부 테이블 요소를 사용하여 고정 위치에서 제외합니다."
Jonas Schubert Erlandsson '12

2
이것은 현재 모든 브라우저에서 작동합니다 thead th { position: sticky; top: 0; }. 이를 명확하게 설명하기 위해이 답변을 업데이트 할 수 있습니까?
Daniel Waltrip

1
@DanielWaltrip 모든 브라우저? stackoverflow.com/a/37646284/3640407 Edges보다 여전히 더 많은 MSIE가 있습니다
edc65

페어 포인트. 이에 따라, 글로벌 웹 사용자의 86 %에 대해 지원됩니다 caniuse.com/#search=position%3Asticky
다니엘 Waltrip을

14

고정 테이블 헤더 용 jQuery 플러그인은 다음과 같습니다. 전체 페이지를 스크롤하여 상단에 도달하면 헤더를 고정시킵니다. Twitter Bootstrap 테이블 과 잘 작동합니다 .

GitHub 리포지토리 : https://github.com/oma/table-fixed-header

테이블 내용 만 스크롤 하지는 않습니다 . 다른 답변 중 하나로서 다른 도구를 찾으십시오. 귀하의 사례에 가장 적합한 것을 결정하십시오.


1
범퍼-예제 링크가 죽었습니다. "죄송합니다! Denne siden ble ikke funnet ..."코드가 여기에 붙여 졌으면 좋겠습니다.
JosephK

그래 ... 미안해 링크를 제거했습니다. 이 프로젝트는 더 이상 유지되지 않습니다
oma

걱정할 필요가 없습니다. 사전 제작 된 솔루션 중 몇 가지를 시도했지만 화면 너비를 초과 한 flex-col-width 테이블은 작동하지 않았습니다. 나는 내 자신의 해결책을 쓰는 것을 끝내었다.
JosephK

9

여기에 게시 된 대부분의 솔루션에는 jQuery가 필요합니다. 프레임 워크 독립적 인 솔루션을 찾고 있다면 Grid를 사용하십시오 : http://www.matts411.com/post/grid/

Github에서 호스팅됩니다 : https://github.com/mmurph211/Grid

고정 헤더를 지원할뿐만 아니라 고정 된 왼쪽 열과 바닥 글도 지원합니다.


그것이 당신의 요구를 충족 시키면 정말 깔끔합니다. 나는 오늘 그것을 가지고 놀았습니다. 불행히도, 이름이 실제로 의미하는 것처럼 직사각형 그리드이며 내용에 따라 행 높이가 조정 된 실제 테이블이 아닙니다. 그리고 개별 행 스타일링이 어려워 보였습니다. 나는 얼룩말 줄무늬 테이블을 만들 수 없었지만 내 요구가 실제로 더 복잡하기 때문에 열심히 노력하지 않았습니다. 어쨌든 잘 했어
mplwork 2016 년

1
이봐, 난 널 알아 우리는 매우 유사 똥 (쓴 듯 github.com/mkoryak/floatThead를 ) - 미샤
mkoryak

9

CSS 속성 position: sticky은 대부분의 최신 브라우저에서 크게 지원됩니다 (Edge에 문제가 있습니다 (아래 참조)).

이를 통해 고정 헤더 문제를 매우 쉽게 해결할 수 있습니다.

thead th { position: sticky; top: 0; }

Safari에는 공급 업체 접두사가 필요합니다 : -webkit-sticky.

Firefox의 min-height: 0경우 부모 요소 중 하나 에 추가 해야했습니다. 이것이 왜 필요한지 정확히 잊어 버렸습니다.

안타깝게도 Microsoft Edge 구현은 단지 반 작동으로 보입니다. 적어도 테스트에서 깜박 거리고 잘못 정렬 된 표 셀이있었습니다. 이 테이블은 여전히 ​​사용 가능하지만 심미적 인 문제가있었습니다.


사용 position: sticky;이 사업부 내부의 테이블 overflow: scroll;, overflow-x: scroll;또는 overflow-y: scroll;. 최신 브라우저에서 고정 테이블 헤더 및 열에 가장 적합하고 간단한 솔루션 인 것으로 보입니다. 이 답변은 맨 위에 투표되어야합니다.
Aberrant

간단하지만 효과적입니다. 내가 찾고있는 것입니다. 감사.
Catbuilts

6

보다 세련된 순수 CSS 스크롤 테이블

지금까지 내가 본 모든 순수한 CSS 솔루션은 영리하지만 어쨌든 일정 수준의 광택이 부족하거나 일부 상황에서는 제대로 작동하지 않습니다. 그래서 나는 내 자신을 만들기로 결정했습니다 ...

풍모:

  • 순수한 CSS이므로 jQuery가 필요하지 않습니다 (또는 그 문제에 대한 모든 JavaScript 코드)
  • 테이블 너비를 백분율 (일명 "유체") 또는 고정 값으로 설정하거나 내용이 너비 (일명 "자동")를 결정하게 할 수 있습니다.
  • 열 너비는 유동적이거나 고정적이거나 자동 일 수 있습니다.
  • 가로 스크롤 (고정 너비가 필요없는 다른 모든 CSS 기반 솔루션에서 발생하는 문제)로 인해 열이 헤더와 잘못 정렬되지 않습니다.
  • Internet Explorer를 버전 8로 되 돌리는 등 인기있는 모든 데스크탑 브라우저와 호환
  • 깨끗하고 세련된 외관; 느슨해 보이는 1 픽셀 간격 또는 잘못 정렬 된 테두리가 없습니다. 모든 브라우저에서 동일하게 보입니다.

다음은 유체 및 자동 너비 옵션을 보여주는 몇 가지 바이올린입니다.

  • 유체 폭 및 높이 (화면 크기에 적합) : jsFiddle (이 구성에서는 스크롤 막대가 필요할 때만 표시되므로 프레임을 축소하여 표시해야 할 수도 있음)

  • 자동 너비, 고정 높이 (다른 내용과 통합하기 쉬움) : jsFiddle

자동 너비, 고정 높이 구성에는 더 많은 사용 사례가 있으므로 아래 코드를 게시하겠습니다.

/* The following 'html' and 'body' rule sets are required only
   if using a % width or height*/

/*html {
  width: 100%;
  height: 100%;
}*/

body {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0 20px 0 20px;
  text-align: center;
}
.scrollingtable {
  box-sizing: border-box;
  display: inline-block;
  vertical-align: middle;
  overflow: hidden;
  width: auto; /* If you want a fixed width, set it here, else set to auto */
  min-width: 0/*100%*/; /* If you want a % width, set it here, else set to 0 */
  height: 188px/*100%*/; /* Set table height here; can be fixed value or % */
  min-height: 0/*104px*/; /* If using % height, make this large enough to fit scrollbar arrows + caption + thead */
  font-family: Verdana, Tahoma, sans-serif;
  font-size: 16px;
  line-height: 20px;
  padding: 20px 0 20px 0; /* Need enough padding to make room for caption */
  text-align: left;
  color: black;
}
.scrollingtable * {box-sizing: border-box;}
.scrollingtable > div {
  position: relative;
  border-top: 1px solid black;
  height: 100%;
  padding-top: 20px; /* This determines column header height */
}
.scrollingtable > div:before {
  top: 0;
  background: cornflowerblue; /* Header row background color */
}
.scrollingtable > div:before,
.scrollingtable > div > div:after {
  content: "";
  position: absolute;
  z-index: -1;
  width: 100%;
  height: 100%;
  left: 0;
}
.scrollingtable > div > div {
  min-height: 0/*43px*/; /* If using % height, make this large
                            enough to fit scrollbar arrows */
  max-height: 100%;
  overflow: scroll/*auto*/; /* Set to auto if using fixed
                               or % width; else scroll */
  overflow-x: hidden;
  border: 1px solid black; /* Border around table body */
}
.scrollingtable > div > div:after {background: white;} /* Match page background color */
.scrollingtable > div > div > table {
  width: 100%;
  border-spacing: 0;
  margin-top: -20px; /* Inverse of column header height */
  /*margin-right: 17px;*/ /* Uncomment if using % width */
}
.scrollingtable > div > div > table > caption {
  position: absolute;
  top: -20px; /*inverse of caption height*/
  margin-top: -1px; /*inverse of border-width*/
  width: 100%;
  font-weight: bold;
  text-align: center;
}
.scrollingtable > div > div > table > * > tr > * {padding: 0;}
.scrollingtable > div > div > table > thead {
  vertical-align: bottom;
  white-space: nowrap;
  text-align: center;
}
.scrollingtable > div > div > table > thead > tr > * > div {
  display: inline-block;
  padding: 0 6px 0 6px; /*header cell padding*/
}
.scrollingtable > div > div > table > thead > tr > :first-child:before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  height: 20px; /*match column header height*/
  border-left: 1px solid black; /*leftmost header border*/
}
.scrollingtable > div > div > table > thead > tr > * > div[label]:before,
.scrollingtable > div > div > table > thead > tr > * > div > div:first-child,
.scrollingtable > div > div > table > thead > tr > * + :before {
  position: absolute;
  top: 0;
  white-space: pre-wrap;
  color: white; /*header row font color*/
}
.scrollingtable > div > div > table > thead > tr > * > div[label]:before,
.scrollingtable > div > div > table > thead > tr > * > div[label]:after {content: attr(label);}
.scrollingtable > div > div > table > thead > tr > * + :before {
  content: "";
  display: block;
  min-height: 20px; /* Match column header height */
  padding-top: 1px;
  border-left: 1px solid black; /* Borders between header cells */
}
.scrollingtable .scrollbarhead {float: right;}
.scrollingtable .scrollbarhead:before {
  position: absolute;
  width: 100px;
  top: -1px; /* Inverse border-width */
  background: white; /* Match page background color */
}
.scrollingtable > div > div > table > tbody > tr:after {
  content: "";
  display: table-cell;
  position: relative;
  padding: 0;
  border-top: 1px solid black;
  top: -1px; /* Inverse of border width */
}
.scrollingtable > div > div > table > tbody {vertical-align: top;}
.scrollingtable > div > div > table > tbody > tr {background: white;}
.scrollingtable > div > div > table > tbody > tr > * {
  border-bottom: 1px solid black;
  padding: 0 6px 0 6px;
  height: 20px; /* Match column header height */
}
.scrollingtable > div > div > table > tbody:last-of-type > tr:last-child > * {border-bottom: none;}
.scrollingtable > div > div > table > tbody > tr:nth-child(even) {background: gainsboro;} /* Alternate row color */
.scrollingtable > div > div > table > tbody > tr > * + * {border-left: 1px solid black;} /* Borders between body cells */
<div class="scrollingtable">
  <div>
    <div>
      <table>
        <caption>Top Caption</caption>
        <thead>
          <tr>
            <th><div label="Column 1"/></th>
            <th><div label="Column 2"/></th>
            <th><div label="Column 3"/></th>
            <th>
              <!-- More versatile way of doing column label; requires two identical copies of label -->
              <div><div>Column 4</div><div>Column 4</div></div>
            </th>
            <th class="scrollbarhead"/> <!-- ALWAYS ADD THIS EXTRA CELL AT END OF HEADER ROW -->
          </tr>
        </thead>
        <tbody>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
          <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
        </tbody>
      </table>
    </div>
    Faux bottom caption
  </div>
</div>

<!--[if lte IE 9]><style>.scrollingtable > div > div > table {margin-right: 17px;}</style><![endif]-->

헤더 행을 고정하는 데 사용한 방법은 d-Pixie와 유사하므로 설명을 보려면 해당 게시물을 참조하십시오. 이 기술에는 수많은 CSS와 여분의 div 컨테이너로만 해결할 수있는 많은 버그와 제한 사항이있었습니다.


이 답변은 과소 평가되었습니다! 나는 특히 성가신 사건을 위해 다른 솔루션을 사용하려고 노력하는 데 며칠을 보냈습니다. 그들 모두는 어떤 방식 으로든 정렬 상태를 유지하지 못했습니다. 이것은 마침내 그것을했다! 처음에는 지나치게 복잡해 보이지만 일단 중단되면 굉장합니다. 유체 너비 등을 사용하지 않을 때 결국에는 필요하지 않은 많은 것들을 제거 할 수 있습니다.
Justin Sane

1
@JustinSane 당신이 그것을 좋아 기쁘다! 나는 감사의 부족이 막시밀리안 힐스의 놀라운 솔루션 과 페이지를 공유한다는 사실에 기인한다고 생각합니다 . 약간의 JS를 사용하는 것에 반대하지 않는다면 반드시 확인해야합니다.
DoctorDestructo

젠장, 그 입니다 실제로 거의 완벽한 솔루션. 어쨌든 jQuery를 사용하고 있었고 다른 질문에 대한 귀하의 의견을 통해 귀하를 발견하기 전에 jQuery를 사용하려고했습니다. 스크롤 리스너를 생각하지 않고 번역했습니다 ... 글쎄, 그들은 간단한 해결책을 제시하는 데 천재가 필요하다고 말합니다.;) 프로젝트를 마치고 js없이 완벽하게 작동하지만 이것을 계속 사용할 것입니다. 미래에 대한 마음. 아직도, 당신에게 굉장한 모자를 벗겨라!
Justin Sane

작은 문제이지만 다른 시스템 색상을 사용하는 경우 텍스트 색상이 헤더 이외의 항목에 대해 설정되지 않았지만 테이블 배경에 명시적인 배경색이 있음을 알 수 있습니다. 이 테이블의 흰색과 회색 배경에 노란색 텍스트가 있습니다.
매트 아놀드

1
@MattArnold 수정되었습니다. 팁을위한 Thx!
DoctorDestructo

5

간단한 jQuery 플러그인

이것은 Mahes 솔루션의 변형입니다. 당신은 그것을처럼 호출 할 수 있습니다$('table#foo').scrollableTable();

아이디어는 다음과 같습니다.

  • 분할 theadtbody분리에 table요소를
  • 셀 너비를 다시 일치 시키십시오
  • 두 번째 랩 tableA의를div.scrollable
  • CSS를 사용하여 div.scrollable실제로 스크롤

CSS는 다음과 같습니다.

div.scrollable { height: 300px; overflow-y: scroll;}

경고

  • 분명히 이러한 테이블을 분할하면 마크 업의 의미가 떨어집니다. 이것이 내게 필요한 옵션에 어떤 영향을 미치는지 잘 모르겠습니다.
  • 이 플러그인은 바닥 글, 여러 헤더 등을 처리하지 않습니다.
  • Chrome 버전 20에서만 테스트했습니다.

즉, 그것은 내 목적을 위해 작동하며 자유롭게 수정하고 수정할 수 있습니다.

플러그인은 다음과 같습니다.

jQuery.fn.scrollableTable = function () {
  var $newTable, $oldTable, $scrollableDiv, originalWidths;
  $oldTable = $(this);

  // Once the tables are split, their cell widths may change. 
  // Grab these so we can make the two tables match again.
  originalWidths = $oldTable.find('tr:first td').map(function() {
    return $(this).width();
  });

  $newTable = $oldTable.clone();
  $oldTable.find('tbody').remove();
  $newTable.find('thead').remove();

  $.each([$oldTable, $newTable], function(index, $table) {
    $table.find('tr:first td').each(function(i) {
      $(this).width(originalWidths[i]);
    });
  });

  $scrollableDiv = $('<div/>').addClass('scrollable');
  $newTable.insertAfter($oldTable).wrap($scrollableDiv);
};

1
좋은 스크립트, 이것은 내 환경에서 가장 잘 작동했습니다. 고정 바닥 글 지원으로 스크립트를 확장했습니다. 아래 게시물을 확인하십시오.
gitaarik

4

:)

깨끗하지는 않지만 순수한 HTML / CSS 솔루션.

table {
    overflow-x:scroll;
}

tbody {
    max-height: /*your desired max height*/
    overflow-y:scroll;
    display:block;
}

IE8 + JSFiddle 예제 용으로 업데이트되었습니다


2
언급 할만한
Stano

3

고정 바닥 글 지원

Nathan의 기능을 확장하여 고정 바닥 글과 최대 높이를 지원했습니다. 또한이 함수는 CSS 자체를 설정하므로 너비 만 지원하면됩니다.

용법:

고정 높이 :

$('table').scrollableTable({ height: 100 });

최대 높이 (브라우저가 CSS 'max-height'옵션을 지원하는 경우) :

$('table').scrollableTable({ maxHeight: 100 });

스크립트:

jQuery.fn.scrollableTable = function(options) {

    var $originalTable, $headTable, $bodyTable, $footTable, $scrollableDiv, originalWidths;

    // Prepare the separate parts of the table
    $originalTable = $(this);
    $headTable = $originalTable.clone();

    $headTable.find('tbody').remove();
    $headTable.find('tfoot').remove();

    $bodyTable = $originalTable.clone();
    $bodyTable.find('thead').remove();
    $bodyTable.find('tfoot').remove();

    $footTable = $originalTable.clone();
    $footTable.find('thead').remove();
    $footTable.find('tbody').remove();

    // Grab the original column widths and set them in the separate tables
    originalWidths = $originalTable.find('tr:first td').map(function() {
        return $(this).width();
    });

    $.each([$headTable, $bodyTable, $footTable], function(index, $table) {
        $table.find('tr:first td').each(function(i) {
            $(this).width(originalWidths[i]);
        });
    });

    // The div that makes the body table scroll
    $scrollableDiv = $('<div/>').css({
        'overflow-y': 'scroll'
    });

    if(options.height) {
        $scrollableDiv.css({'height': options.height});
    }
    else if(options.maxHeight) {
        $scrollableDiv.css({'max-height': options.maxHeight});
    }

    // Add the new separate tables and remove the original one
    $headTable.insertAfter($originalTable);
    $bodyTable.insertAfter($headTable);
    $footTable.insertAfter($bodyTable);
    $bodyTable.wrap($scrollableDiv);
    $originalTable.remove();
};

3

어떻게 든 나는 Position:Sticky내 경우에 잘 작동했습니다.

table{
  width: 100%;
  border: collapse;
}

th{
    position: sticky;
    top: 0px;
    border: 1px solid black;
    background: #ff5722;
    color: #f5f5f5;
    font-weight: 600;
}
td{
    background: #d3d3d3;
    border: 1px solid black;
    color: #f5f5f5;
    font-weight: 600;
}

div{
  height: 150px
  overflow: auto;
  width: 100%
}
<div>
    <table>
        <thead>
            <tr>
                <th>header 1</th>
                <th>header 2</th>
                <th>header 3</th>
                <th>header 4</th>
                <th>header 5</th>
                <th>header 6</th>
                <th>header 7</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
            <tr>
                <td>data 1</td>
                <td>data 2</td>
                <td>data 3</td>
                <td>data 4</td>
                <td>data 5</td>
                <td>data 6</td>
                <td>data 7</td>
            </tr>
        </tbody>
    </table>
</div>


1
이것은 내가 지금까지 본 가장 깨끗한 솔루션입니다. caniuse 는 5/2/2020 기준으로 접두사가없는 position : sticky가 90.06 %의 전 세계 지원을 받고 있음을 보여줍니다. 따라서이 솔루션은 모든 최신 브라우저에서 잘 작동합니다.
AlienKevin

2

두 개의 div, 하나는 헤더, 하나는 데이터. 데이터 div를 스크롤 가능하게 만들고 JavaScript를 사용하여 헤더의 열 너비를 데이터 너비와 동일하게 설정하십시오. 데이터 열 너비는 동적이 아닌 고정되어야한다고 생각합니다.


3
접근성에 관심이 있다면 이것은 실패입니다.
epascarello

1
재 접근성, div 사용을 <thead> 및 <tbody>의 스타일로 대체 할 수 있습니까 ??
Cheekysoft

1

질문에 JavaScript가 허용된다는 것을 알고 있지만 여기에 테이블을 수평으로 확장 할 수있는 순수한 CSS 솔루션이 있습니다. Internet Explorer 10과 최신 Chrome 및 Firefox 브라우저에서 테스트되었습니다. jsFiddle에 대한 링크가 맨 아래에 있습니다.

HTML :

Putting some text here to differentiate between the header
aligning with the top of the screen and the header aligning
with the top of one of its ancestor containers.

<div id="positioning-container">
<div id="scroll-container">
    <table>
        <colgroup>
            <col class="col1"></col>
            <col class="col2"></col>
        </colgroup>
        <thead>
            <th class="header-col1"><div>Header 1</div></th>
            <th class="header-col2"><div>Header 2</div></th>
        </thead>
        <tbody>
            <tr><td>Cell 1.1</td><td>Cell 1.2</td></tr>
            <tr><td>Cell 2.1</td><td>Cell 2.2</td></tr>
            <tr><td>Cell 3.1</td><td>Cell 3.2</td></tr>
            <tr><td>Cell 4.1</td><td>Cell 4.2</td></tr>
            <tr><td>Cell 5.1</td><td>Cell 5.2</td></tr>
            <tr><td>Cell 6.1</td><td>Cell 6.2</td></tr>
            <tr><td>Cell 7.1</td><td>Cell 7.2</td></tr>

        </tbody>
    </table>
</div>
</div>

그리고 CSS :

table{
    border-collapse: collapse;
    table-layout: fixed;
    width: 100%;
}
/* Not required, just helps with alignment for this example */
td, th{
    padding: 0;
    margin: 0;
}

tbody{
    background-color: #ddf;
}

thead {
    /* Keeps the header in place. Don't forget top: 0 */
    position: absolute;
    top: 0;
    background-color: #ddd;

    /* The 17px is to adjust for the scrollbar width.
     * This is a new css value that makes this pure
     * css example possible */
    width: calc(100% - 17px);
    height: 20px;
}

/* Positioning container. Required to position the
 * header since the header uses position:absolute
 * (otherwise it would position at the top of the screen) */
#positioning-container{
    position: relative;
}

/* A container to set the scroll-bar and
 * includes padding to move the table contents
 * down below the header (padding = header height) */
#scroll-container{
    overflow-y: auto;
    padding-top: 20px;
    height: 100px;
}
.header-col1{
    background-color: red;
}

/* Fixed-width header columns need a div to set their width */
.header-col1 div{
    width: 100px;
}

/* Expandable columns need a width set on the th tag */
.header-col2{
    width: 100%;
}
.col1 {
    width: 100px;
}
.col2{
    width: 100%;
}

http://jsfiddle.net/HNHRv/3/


1

Maximilian Hils가 제공 한 훌륭한 솔루션을 시도했지만 Internet Explorer에서 작동하지 못하는 사람들에게 동일한 문제 (Internet Explorer 11)가 있었고 문제가 무엇인지 알았습니다.

Internet Explorer 11에서는 스타일 변환 (적어도 번역 사용)이 작동하지 않습니다 <THEAD>. 대신 <TH>루프의 모든 스타일에 스타일을 적용하여이 문제를 해결했습니다 . 효과가있었습니다. 내 JavaScript 코드는 다음과 같습니다.

document.getElementById('pnlGridWrap').addEventListener("scroll", function () {
  var translate = "translate(0," + this.scrollTop + "px)";
  var myElements = this.querySelectorAll("th");
  for (var i = 0; i < myElements.length; i++) {
    myElements[i].style.transform=translate;
  }
});

필자의 경우 테이블은 ASP.NET의 GridView였습니다. 처음에는 그것이 없기 때문에 생각<THEAD> 했지만, 그것을 갖도록 강요해도 효과가 없었습니다. 그런 다음 위에 쓴 내용을 알았습니다.

매우 훌륭하고 간단한 솔루션입니다. Chrome에서는 완벽하고 Firefox에서는 약간 불쾌하며 Internet Explorer에서는 훨씬 더 완벽합니다. 그러나 모두 좋은 해결책입니다.


0

@Mark의 솔루션을 더 일찍 찾았 으면 좋았지만이 SO 질문을보기 전에 직접 작성했습니다.

Mine은 고정 헤더, 바닥 글, 열 스패닝 (colspan), 크기 조정, 가로 스크롤 및 스크롤을 시작하기 전에 표시 할 선택적 행 수를 지원하는 매우 가벼운 jQuery 플러그인입니다.

jQuery.scrollTableBody (GitHub)

만큼 당신이있는 테이블을 가지고 적절한는 <thead>, <tbody>, (옵션) <tfoot>, 당신이해야 할 모든이입니다 :

$('table').scrollTableBody();

0

이 해결 방법을 발견했습니다-데이터가있는 테이블 위의 테이블에서 헤더 행을 이동하십시오.

<html>
<head>
	<title>Fixed header</title>
	<style>
		table td {width:75px;}
	</style>
</head>

<body>
<div style="height:auto; width:350px; overflow:auto">
<table border="1">
<tr>
	<td>header 1</td>
	<td>header 2</td>
	<td>header 3</td>
</tr>
</table>
</div>

<div style="height:50px; width:350px; overflow:auto">
<table border="1">
<tr>
	<td>row 1 col 1</td>
	<td>row 1 col 2</td>
	<td>row 1 col 3</td>		
</tr>
<tr>
	<td>row 2 col 1</td>
	<td>row 2 col 2</td>
	<td>row 2 col 3</td>		
</tr>
<tr>
	<td>row 3 col 1</td>
	<td>row 3 col 2</td>
	<td>row 3 col 3</td>		
</tr>
<tr>
	<td>row 4 col 1</td>
	<td>row 4 col 2</td>
	<td>row 4 col 3</td>		
</tr>
<tr>
	<td>row 5 col 1</td>
	<td>row 5 col 2</td>
	<td>row 5 col 3</td>		
</tr>
<tr>
	<td>row 6 col 1</td>
	<td>row 6 col 2</td>
	<td>row 6 col 3</td>		
</tr>
</table>
</div>


</body>
</html>


작은 테이블에는 작동하지만 가로 스크롤이 있으면이 솔루션이 작동하지 않습니다.
crh225

테이블 열이 정렬되지 않으므로 제대로 작동하지 않습니다. 여기서 당신은 td에 대한 폭을 강요하지만 우리는해서는 안됩니다 ...
Ziggler

0

StickyTableHeaders jQuery 플러그인을 테이블에 적용하면 아래로 스크롤 할 때 열 헤더가 뷰포트 상단에 고정됩니다.

예:

$(function () {
    $("table").stickyTableHeaders();
});

/*! Copyright (c) 2011 by Jonas Mosbech - https://github.com/jmosbech/StickyTableHeaders
	MIT license info: https://github.com/jmosbech/StickyTableHeaders/blob/master/license.txt */

;
(function ($, window, undefined) {
    'use strict';

    var name = 'stickyTableHeaders',
        id = 0,
        defaults = {
            fixedOffset: 0,
            leftOffset: 0,
            marginTop: 0,
            scrollableArea: window
        };

    function Plugin(el, options) {
        // To avoid scope issues, use 'base' instead of 'this'
        // to reference this class from internal events and functions.
        var base = this;

        // Access to jQuery and DOM versions of element
        base.$el = $(el);
        base.el = el;
        base.id = id++;
        base.$window = $(window);
        base.$document = $(document);

        // Listen for destroyed, call teardown
        base.$el.bind('destroyed',
        $.proxy(base.teardown, base));

        // Cache DOM refs for performance reasons
        base.$clonedHeader = null;
        base.$originalHeader = null;

        // Keep track of state
        base.isSticky = false;
        base.hasBeenSticky = false;
        base.leftOffset = null;
        base.topOffset = null;

        base.init = function () {
            base.$el.each(function () {
                var $this = $(this);

                // remove padding on <table> to fix issue #7
                $this.css('padding', 0);

                base.$originalHeader = $('thead:first', this);
                base.$clonedHeader = base.$originalHeader.clone();
                $this.trigger('clonedHeader.' + name, [base.$clonedHeader]);

                base.$clonedHeader.addClass('tableFloatingHeader');
                base.$clonedHeader.css('display', 'none');

                base.$originalHeader.addClass('tableFloatingHeaderOriginal');

                base.$originalHeader.after(base.$clonedHeader);

                base.$printStyle = $('<style type="text/css" media="print">' +
                    '.tableFloatingHeader{display:none !important;}' +
                    '.tableFloatingHeaderOriginal{position:static !important;}' +
                    '</style>');
                $('head').append(base.$printStyle);
            });

            base.setOptions(options);
            base.updateWidth();
            base.toggleHeaders();
            base.bind();
        };

        base.destroy = function () {
            base.$el.unbind('destroyed', base.teardown);
            base.teardown();
        };

        base.teardown = function () {
            if (base.isSticky) {
                base.$originalHeader.css('position', 'static');
            }
            $.removeData(base.el, 'plugin_' + name);
            base.unbind();

            base.$clonedHeader.remove();
            base.$originalHeader.removeClass('tableFloatingHeaderOriginal');
            base.$originalHeader.css('visibility', 'visible');
            base.$printStyle.remove();

            base.el = null;
            base.$el = null;
        };

        base.bind = function () {
            base.$scrollableArea.on('scroll.' + name, base.toggleHeaders);
            if (!base.isWindowScrolling) {
                base.$window.on('scroll.' + name + base.id, base.setPositionValues);
                base.$window.on('resize.' + name + base.id, base.toggleHeaders);
            }
            base.$scrollableArea.on('resize.' + name, base.toggleHeaders);
            base.$scrollableArea.on('resize.' + name, base.updateWidth);
        };

        base.unbind = function () {
            // unbind window events by specifying handle so we don't remove too much
            base.$scrollableArea.off('.' + name, base.toggleHeaders);
            if (!base.isWindowScrolling) {
                base.$window.off('.' + name + base.id, base.setPositionValues);
                base.$window.off('.' + name + base.id, base.toggleHeaders);
            }
            base.$scrollableArea.off('.' + name, base.updateWidth);
        };

        base.toggleHeaders = function () {
            if (base.$el) {
                base.$el.each(function () {
                    var $this = $(this),
                        newLeft,
                        newTopOffset = base.isWindowScrolling ? (
                        isNaN(base.options.fixedOffset) ? base.options.fixedOffset.outerHeight() : base.options.fixedOffset) : base.$scrollableArea.offset().top + (!isNaN(base.options.fixedOffset) ? base.options.fixedOffset : 0),
                        offset = $this.offset(),

                        scrollTop = base.$scrollableArea.scrollTop() + newTopOffset,
                        scrollLeft = base.$scrollableArea.scrollLeft(),

                        scrolledPastTop = base.isWindowScrolling ? scrollTop > offset.top : newTopOffset > offset.top,
                        notScrolledPastBottom = (base.isWindowScrolling ? scrollTop : 0) < (offset.top + $this.height() - base.$clonedHeader.height() - (base.isWindowScrolling ? 0 : newTopOffset));

                    if (scrolledPastTop && notScrolledPastBottom) {
                        newLeft = offset.left - scrollLeft + base.options.leftOffset;
                        base.$originalHeader.css({
                            'position': 'fixed',
                                'margin-top': base.options.marginTop,
                                'left': newLeft,
                                'z-index': 3 // #18: opacity bug
                        });
                        base.leftOffset = newLeft;
                        base.topOffset = newTopOffset;
                        base.$clonedHeader.css('display', '');
                        if (!base.isSticky) {
                            base.isSticky = true;
                            // make sure the width is correct: the user might have resized the browser while in static mode
                            base.updateWidth();
                        }
                        base.setPositionValues();
                    } else if (base.isSticky) {
                        base.$originalHeader.css('position', 'static');
                        base.$clonedHeader.css('display', 'none');
                        base.isSticky = false;
                        base.resetWidth($('td,th', base.$clonedHeader), $('td,th', base.$originalHeader));
                    }
                });
            }
        };

        base.setPositionValues = function () {
            var winScrollTop = base.$window.scrollTop(),
                winScrollLeft = base.$window.scrollLeft();
            if (!base.isSticky || winScrollTop < 0 || winScrollTop + base.$window.height() > base.$document.height() || winScrollLeft < 0 || winScrollLeft + base.$window.width() > base.$document.width()) {
                return;
            }
            base.$originalHeader.css({
                'top': base.topOffset - (base.isWindowScrolling ? 0 : winScrollTop),
                    'left': base.leftOffset - (base.isWindowScrolling ? 0 : winScrollLeft)
            });
        };

        base.updateWidth = function () {
            if (!base.isSticky) {
                return;
            }
            // Copy cell widths from clone
            if (!base.$originalHeaderCells) {
                base.$originalHeaderCells = $('th,td', base.$originalHeader);
            }
            if (!base.$clonedHeaderCells) {
                base.$clonedHeaderCells = $('th,td', base.$clonedHeader);
            }
            var cellWidths = base.getWidth(base.$clonedHeaderCells);
            base.setWidth(cellWidths, base.$clonedHeaderCells, base.$originalHeaderCells);

            // Copy row width from whole table
            base.$originalHeader.css('width', base.$clonedHeader.width());
        };

        base.getWidth = function ($clonedHeaders) {
            var widths = [];
            $clonedHeaders.each(function (index) {
                var width, $this = $(this);

                if ($this.css('box-sizing') === 'border-box') {
                    width = $this[0].getBoundingClientRect().width; // #39: border-box bug
                } else {
                    var $origTh = $('th', base.$originalHeader);
                    if ($origTh.css('border-collapse') === 'collapse') {
                        if (window.getComputedStyle) {
                            width = parseFloat(window.getComputedStyle(this, null).width);
                        } else {
                            // ie8 only
                            var leftPadding = parseFloat($this.css('padding-left'));
                            var rightPadding = parseFloat($this.css('padding-right'));
                            // Needs more investigation - this is assuming constant border around this cell and it's neighbours.
                            var border = parseFloat($this.css('border-width'));
                            width = $this.outerWidth() - leftPadding - rightPadding - border;
                        }
                    } else {
                        width = $this.width();
                    }
                }

                widths[index] = width;
            });
            return widths;
        };

        base.setWidth = function (widths, $clonedHeaders, $origHeaders) {
            $clonedHeaders.each(function (index) {
                var width = widths[index];
                $origHeaders.eq(index).css({
                    'min-width': width,
                        'max-width': width
                });
            });
        };

        base.resetWidth = function ($clonedHeaders, $origHeaders) {
            $clonedHeaders.each(function (index) {
                var $this = $(this);
                $origHeaders.eq(index).css({
                    'min-width': $this.css('min-width'),
                        'max-width': $this.css('max-width')
                });
            });
        };

        base.setOptions = function (options) {
            base.options = $.extend({}, defaults, options);
            base.$scrollableArea = $(base.options.scrollableArea);
            base.isWindowScrolling = base.$scrollableArea[0] === window;
        };

        base.updateOptions = function (options) {
            base.setOptions(options);
            // scrollableArea might have changed
            base.unbind();
            base.bind();
            base.updateWidth();
            base.toggleHeaders();
        };

        // Run initializer
        base.init();
    }

    // A plugin wrapper around the constructor,
    // preventing against multiple instantiations
    $.fn[name] = function (options) {
        return this.each(function () {
            var instance = $.data(this, 'plugin_' + name);
            if (instance) {
                if (typeof options === 'string') {
                    instance[options].apply(instance);
                } else {
                    instance.updateOptions(options);
                }
            } else if (options !== 'destroy') {
                $.data(this, 'plugin_' + name, new Plugin(this, options));
            }
        });
    };

})(jQuery, window);
body {
    margin: 0 auto;
    padding: 0 20px;
    font-family: Arial, Helvetica, sans-serif;
    font-size: 11px;
    color: #555;
}
table {
    border: 0;
    padding: 0;
    margin: 0 0 20px 0;
    border-collapse: collapse;
}
th {
    padding: 5px;
    /* NOTE: th padding must be set explicitly in order to support IE */
    text-align: right;
    font-weight:bold;
    line-height: 2em;
    color: #FFF;
    background-color: #555;
}
tbody td {
    padding: 10px;
    line-height: 18px;
    border-top: 1px solid #E0E0E0;
}
tbody tr:nth-child(2n) {
    background-color: #F7F7F7;
}
tbody tr:hover {
    background-color: #EEEEEE;
}
td {
    text-align: right;
}
td:first-child, th:first-child {
    text-align: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div style="width:3000px">some really really wide content goes here</div>
<table>
    <thead>
        <tr>
            <th colspan="9">Companies listed on NASDAQ OMX Copenhagen.</th>
        </tr>
        <tr>
            <th>Full name</th>
            <th>CCY</th>
            <th>Last</th>
            <th>+/-</th>
            <th>%</th>
            <th>Bid</th>
            <th>Ask</th>
            <th>Volume</th>
            <th>Turnover</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>A.P. Møller...</td>
            <td>DKK</td>
            <td>33,220.00</td>
            <td>760</td>
            <td>2.34</td>
            <td>33,140.00</td>
            <td>33,220.00</td>
            <td>594</td>
            <td>19,791,910</td>
        </tr>
        <tr>
            <td>A.P. Møller...</td>
            <td>DKK</td>
            <td>34,620.00</td>
            <td>640</td>
            <td>1.88</td>
            <td>34,620.00</td>
            <td>34,700.00</td>
            <td>9,954</td>
            <td>346,530,246</td>
        </tr>
        <tr>
            <td>Carlsberg A</td>
            <td>DKK</td>
            <td>380</td>
            <td>0</td>
            <td>0</td>
            <td>371</td>
            <td>391.5</td>
            <td>6</td>
            <td>2,280</td>
        </tr>
        <tr>
            <td>Carlsberg B</td>
            <td>DKK</td>
            <td>364.4</td>
            <td>8.6</td>
            <td>2.42</td>
            <td>363</td>
            <td>364.4</td>
            <td>636,267</td>
            <td>228,530,601</td>
        </tr>
        <tr>
            <td>Chr. Hansen...</td>
            <td>DKK</td>
            <td>114.5</td>
            <td>-1.6</td>
            <td>-1.38</td>
            <td>114.2</td>
            <td>114.5</td>
            <td>141,822</td>
            <td>16,311,454</td>
        </tr>
        <tr>
            <td>Coloplast B</td>
            <td>DKK</td>
            <td>809.5</td>
            <td>11</td>
            <td>1.38</td>
            <td>809</td>
            <td>809.5</td>
            <td>85,840</td>
            <td>69,363,301</td>
        </tr>
        <tr>
            <td>D/S Norden</td>
            <td>DKK</td>
            <td>155</td>
            <td>-1.5</td>
            <td>-0.96</td>
            <td>155</td>
            <td>155.1</td>
            <td>51,681</td>
            <td>8,037,225</td>
        </tr>
        <tr>
            <td>Danske Bank</td>
            <td>DKK</td>
            <td>69.05</td>
            <td>2.55</td>
            <td>3.83</td>
            <td>69.05</td>
            <td>69.2</td>
            <td>1,723,719</td>
            <td>115,348,068</td>
        </tr>
        <tr>
            <td>DSV</td>
            <td>DKK</td>
            <td>105.4</td>
            <td>0.2</td>
            <td>0.19</td>
            <td>105.2</td>
            <td>105.4</td>
            <td>674,873</td>
            <td>71,575,035</td>
        </tr>
        <tr>
            <td>FLSmidth &amp; Co.</td>
            <td>DKK</td>
            <td>295.8</td>
            <td>-1.8</td>
            <td>-0.6</td>
            <td>295.1</td>
            <td>295.8</td>
            <td>341,263</td>
            <td>100,301,032</td>
        </tr>
        <tr>
            <td>G4S plc</td>
            <td>DKK</td>
            <td>22.53</td>
            <td>0.05</td>
            <td>0.22</td>
            <td>22.53</td>
            <td>22.57</td>
            <td>190,920</td>
            <td>4,338,150</td>
        </tr>
        <tr>
            <td>Jyske Bank</td>
            <td>DKK</td>
            <td>144.2</td>
            <td>1.4</td>
            <td>0.98</td>
            <td>142.8</td>
            <td>144.2</td>
            <td>78,163</td>
            <td>11,104,874</td>
        </tr>
        <tr>
            <td>Københavns ...</td>
            <td>DKK</td>
            <td>1,580.00</td>
            <td>-12</td>
            <td>-0.75</td>
            <td>1,590.00</td>
            <td>1,620.00</td>
            <td>82</td>
            <td>131,110</td>
        </tr>
        <tr>
            <td>Lundbeck</td>
            <td>DKK</td>
            <td>103.4</td>
            <td>-2.5</td>
            <td>-2.36</td>
            <td>103.4</td>
            <td>103.8</td>
            <td>157,162</td>
            <td>16,462,282</td>
        </tr>
        <tr>
            <td>Nordea Bank</td>
            <td>DKK</td>
            <td>43.22</td>
            <td>-0.06</td>
            <td>-0.14</td>
            <td>43.22</td>
            <td>43.25</td>
            <td>167,520</td>
            <td>7,310,143</td>
        </tr>
        <tr>
            <td>Novo Nordisk B</td>
            <td>DKK</td>
            <td>552.5</td>
            <td>-3.5</td>
            <td>-0.63</td>
            <td>550.5</td>
            <td>552.5</td>
            <td>843,533</td>
            <td>463,962,375</td>
        </tr>
        <tr>
            <td>Novozymes B</td>
            <td>DKK</td>
            <td>805.5</td>
            <td>5.5</td>
            <td>0.69</td>
            <td>805</td>
            <td>805.5</td>
            <td>152,188</td>
            <td>121,746,199</td>
        </tr>
        <tr>
            <td>Pandora</td>
            <td>DKK</td>
            <td>39.04</td>
            <td>0.94</td>
            <td>2.47</td>
            <td>38.8</td>
            <td>39.04</td>
            <td>350,965</td>
            <td>13,611,838</td>
        </tr>
        <tr>
            <td>Rockwool In...</td>
            <td>DKK</td>
            <td>492</td>
            <td>0</td>
            <td>0</td>
            <td>482</td>
            <td>492</td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td>Rockwool In...</td>
            <td>DKK</td>
            <td>468</td>
            <td>12</td>
            <td>2.63</td>
            <td>465.2</td>
            <td>468</td>
            <td>9,885</td>
            <td>4,623,850</td>
        </tr>
        <tr>
            <td>Sydbank</td>
            <td>DKK</td>
            <td>95</td>
            <td>0.05</td>
            <td>0.05</td>
            <td>94.7</td>
            <td>95</td>
            <td>103,438</td>
            <td>9,802,899</td>
        </tr>
        <tr>
            <td>TDC</td>
            <td>DKK</td>
            <td>43.6</td>
            <td>0.13</td>
            <td>0.3</td>
            <td>43.5</td>
            <td>43.6</td>
            <td>845,110</td>
            <td>36,785,339</td>
        </tr>
        <tr>
            <td>Topdanmark</td>
            <td>DKK</td>
            <td>854</td>
            <td>13.5</td>
            <td>1.61</td>
            <td>854</td>
            <td>855</td>
            <td>38,679</td>
            <td>32,737,678</td>
        </tr>
        <tr>
            <td>Tryg</td>
            <td>DKK</td>
            <td>290.4</td>
            <td>0.3</td>
            <td>0.1</td>
            <td>290</td>
            <td>290.4</td>
            <td>94,587</td>
            <td>27,537,247</td>
        </tr>
        <tr>
            <td>Vestas Wind...</td>
            <td>DKK</td>
            <td>90.15</td>
            <td>-4.2</td>
            <td>-4.45</td>
            <td>90.1</td>
            <td>90.15</td>
            <td>1,317,313</td>
            <td>121,064,314</td>
        </tr>
        <tr>
            <td>William Dem...</td>
            <td>DKK</td>
            <td>417.6</td>
            <td>0.1</td>
            <td>0.02</td>
            <td>417</td>
            <td>417.6</td>
            <td>64,242</td>
            <td>26,859,554</td>
        </tr>
    </tbody>
</table>
<div style="height: 4000px">lots of content down here...</div>


0

같은 I 맥시 HILS ' 대답하지만 난 몇 가지 문제가 있었다 :

  1. 일에 적용하지 않으면 Edge 또는 IE에서 변환이 작동하지 않습니다.
  2. Edge 및 IE에서 스크롤하는 동안 헤더가 깜박입니다.
  3. 내 테이블은 아약스를 사용하여로드되므로 래퍼의 스크롤 이벤트가 아닌 창 스크롤 이벤트에 첨부하고 싶었습니다.

깜박임을 제거하기 위해 타임 아웃을 사용하여 사용자가 스크롤을 마칠 때까지 기다린 다음 변환을 적용하므로 스크롤 중에 헤더가 표시되지 않습니다.

또한 jQuery를 사용하여 이것을 작성했습니다. jQuery가 벤더 접두사를 처리해야한다는 이점

    var isScrolling, lastTop, lastLeft, isLeftHidden, isTopHidden;

    //Scroll events don't bubble https://stackoverflow.com/a/19375645/150342
    //so can't use $(document).on("scroll", ".table-container-fixed", function (e) {
    document.addEventListener('scroll', function (event) {
        var $container = $(event.target);
        if (!$container.hasClass("table-container-fixed"))
            return;    

        //transform needs to be applied to th for Edge and IE
        //in this example I am also fixing the leftmost column
        var $topLeftCell = $container.find('table:first > thead > tr > th:first');
        var $headerCells = $topLeftCell.siblings();
        var $columnCells = $container
           .find('table:first > tbody > tr > td:first-child, ' +
                 'table:first > tfoot > tr > td:first-child');

        //hide the cells while returning otherwise they show on top of the data
        if (!isLeftHidden) {
            var currentLeft = $container.scrollLeft();
            if (currentLeft < lastLeft) {
                //scrolling left
                isLeftHidden = true;
                $topLeftCell.css('visibility', 'hidden');
                $columnCells.css('visibility', 'hidden');
            }
            lastLeft = currentLeft;
        }

        if (!isTopHidden) {
            var currentTop = $container.scrollTop();
            if (currentTop < lastTop) {
                //scrolling up
                isTopHidden = true;
                $topLeftCell.css('visibility', 'hidden');
                $headerCells.css('visibility', 'hidden');
            }
            lastTop = currentTop;
        }

        // Using timeout to delay transform until user stops scrolling
        // Clear timeout while scrolling
        window.clearTimeout(isScrolling);

        // Set a timeout to run after scrolling ends
        isScrolling = setTimeout(function () {
            //move the table cells. 
            var x = $container.scrollLeft();
            var y = $container.scrollTop();

            $topLeftCell.css('transform', 'translate(' + x + 'px, ' + y + 'px)');
            $headerCells.css('transform', 'translateY(' + y + 'px)');
            $columnCells.css('transform', 'translateX(' + x + 'px)');

            isTopHidden = isLeftHidden = false;
            $topLeftCell.css('visibility', 'inherit');
            $headerCells.css('visibility', 'inherit');
            $columnCells.css('visibility', 'inherit');
        }, 100);

    }, true);

테이블은 클래스와 함께 div로 래핑됩니다 table-container-fixed.

.table-container-fixed{
    overflow: auto;
    height: 400px;
}

변환 중에 테두리가 없어지기 때문에 border-collapse를 분리하도록 설정하고 스크롤하는 동안 테두리 위에 있던 셀 바로 위에 내용이 표시되지 않도록 테이블에서 테두리를 제거합니다.

.table-container-fixed > table {
   border-collapse: separate;
   border:none;
}

th배경을 흰색으로 만들어 셀을 덮고 표 테두리와 일치하는 테두리를 추가합니다.이 테두리는 부트 스트랩을 사용하여 스타일이 지정되고 스크롤되지 않습니다.

 .table-container-fixed > table > thead > tr > th {
        border-top: 1px solid #ddd !important;
        background-color: white;        
        z-index: 10;
        position: relative;/*to make z-index work*/
    }

            .table-container-fixed > table > thead > tr > th:first-child {
                z-index: 20;
            }

.table-container-fixed > table > tbody > tr > td:first-child,
.table-container-fixed > table > tfoot > tr > td:first-child {
    background-color: white;        
    z-index: 10;
    position: relative;
}

0

최신 버전의 jQuery를 사용하고 다음 JavaScript 코드를 포함하십시오.

$(window).scroll(function(){
  $("id of the div element").offset({top:$(window).scrollTop()});
});

1
작동하지 않는 것 같습니다. 어쩌면 우리가 원하는 것을 분명히 할 수 있습니까?
Chris

1
어떤 사업부? 우리는 여기 테이블에 대해 이야기하고 있습니다
isapir

0

이것은 고정 헤더 행에 대한 정확한 해결책은 아니지만 긴 테이블 전체에서 헤더 행을 반복하면서 정렬 기능을 유지하는 다소 독창적 인 방법을 만들었습니다.

이 깔끔한 작은 옵션에는 jQuery 플러그인이 필요합니다.tablesorter . 작동 방식은 다음과 같습니다.

HTML

<table class="tablesorter boxlist" id="pmtable">
    <thead class="fixedheader">
        <tr class="boxheadrow">
            <th width="70px" class="header">Job Number</th>
            <th width="10px" class="header">Pri</th>
            <th width="70px" class="header">CLLI</th>
            <th width="35px" class="header">Market</th>
            <th width="35px" class="header">Job Status</th>
            <th width="65px" class="header">Technology</th>
            <th width="95px;" class="header headerSortDown">MEI</th>
            <th width="95px" class="header">TEO Writer</th>
            <th width="75px" class="header">Quote Due</th>
            <th width="100px" class="header">Engineer</th>
            <th width="75px" class="header">ML Due</th>
            <th width="75px" class="header">ML Complete</th>
            <th width="75px" class="header">SPEC Due</th>
            <th width="75px" class="header">SPEC Complete</th>
            <th width="100px" class="header">Install Supervisor</th>
            <th width="75px" class="header">MasTec OJD</th>
            <th width="75px" class="header">Install Start</th>
            <th width="30px" class="header">Install Hours</th>
            <th width="75px" class="header">Revised CRCD</th>
            <th width="75px" class="header">Latest Ship-To-Site</th>
            <th width="30px" class="header">Total Parts</th>
            <th width="30px" class="header">OEM Rcvd</th>
            <th width="30px" class="header">Minor Rcvd</th>
            <th width="30px" class="header">Total Received</th>
            <th width="30px" class="header">% On Site</th>
            <th width="60px" class="header">Actions</th>
        </tr>
    </thead>
        <tbody class="scrollable">
            <tr data-job_id="3548" data-ml_id="" class="odd">
                <td class="c black">FL-8-RG9UP</td>
                <td data-pri="2" class="priority c yellow">M</td>
                <td class="c">FTLDFLOV</td>
                <td class="c">SFL</td>
                <td class="c">NOI</td>
                <td class="c">TRANSPORT</td>
                <td class="c"></td>
                <td class="c">Chris Byrd</td>
                <td class="c">Apr 13, 2013</td>
                <td class="c">Kris Hall</td>
                <td class="c">May 20, 2013</td>
                <td class="c">May 20, 2013</td>
                <td class="c">Jun 5, 2013</td>
                <td class="c">Jun 7, 2013</td>
                <td class="c">Joseph Fitz</td>
                <td class="c">Jun 10, 2013</td>
                <td class="c">TBD</td>
                <td class="c">123</td>
                <td class="c revised_crcd"><input readonly="true" name="revised_crcd" value="Jul 26, 2013" type="text" size="12" class="smInput r_crcd c hasDatepicker" id="dp1377194058616"></td>
                <td class="c">TBD</td>
                <td class="c">N/A</td>
                <td class="c">N/A</td>
                <td class="c">N/A</td>
                <td class="c">N/A</td>
                <td class="c">N/A</td>
                <td class="actions"><span style="float:left;" class="ui-icon ui-icon-folder-open editJob" title="View this job" s="" details'=""></span></td>
            </tr>
            <tr data-job_id="4264" data-ml_id="2959" class="even">
                <td class="c black">MTS13009SF</td>
                <td data-pri="2" class="priority c yellow">M</td>
                <td class="c">OJUSFLTL</td>
                <td class="c">SFL</td>
                <td class="c">NOI</td>
                <td class="c">TRANSPORT</td>
                <td class="c"></td>
                <td class="c">DeMarcus Stewart</td>
                <td class="c">May 22, 2013</td>
                <td class="c">Ryan Alsobrook</td>
                <td class="c">Jun 19, 2013</td>
                <td class="c">Jun 27, 2013</td>
                <td class="c">Jun 19, 2013</td>
                <td class="c">Jul 4, 2013</td>
                <td class="c">Randy Williams</td>
                <td class="c">Jun 21, 2013</td>
                <td class="c">TBD</td>
                <td class="c">95</td>
                <td class="c revised_crcd"><input readonly="true" name="revised_crcd" value="Aug 9, 2013" type="text" size="12" class="smInput r_crcd c hasDatepicker" id="dp1377194058632"></td><td class="c">TBD</td>
                <td class="c">0</td>
                <td class="c">0.00%</td>
                <td class="c">0.00%</td>
                <td class="c">0.00%</td>
                <td class="c">0.00%</td>
                <td class="actions"><span style="float:left;" class="ui-icon ui-icon-folder-open editJob" title="View this job" s="" details'=""></span><input style="float:left;" type="hidden" name="req_ship" class="reqShip hasDatepicker" id="dp1377194058464"><span style="float:left;" class="ui-icon ui-icon-calendar requestShip" title="Schedule this job for shipping"></span><span class="ui-icon ui-icon-info viewOrderInfo" style="float:left;" title="Show material details for this order"></span></td>
            </tr>
            .
            .
            .
            .
            <tr class="boxheadrow repeated-header">
                <th width="70px" class="header">Job Number</th>
                <th width="10px" class="header">Pri</th>
                <th width="70px" class="header">CLLI</th>
                <th width="35px" class="header">Market</th>
                <th width="35px" class="header">Job Status</th>
                <th width="65px" class="header">Technology</th>
                <th width="95px;" class="header">MEI</th>
                <th width="95px" class="header">TEO Writer</th>
                <th width="75px" class="header">Quote Due</th>
                <th width="100px" class="header">Engineer</th>
                <th width="75px" class="header">ML Due</th>
                <th width="75px" class="header">ML Complete</th>
                <th width="75px" class="header">SPEC Due</th>
                <th width="75px" class="header">SPEC Complete</th>
                <th width="100px" class="header">Install Supervisor</th>
                <th width="75px" class="header">MasTec OJD</th>
                <th width="75px" class="header">Install Start</th>
                <th width="30px" class="header">Install Hours</th>
                <th width="75px" class="header">Revised CRCD</th>
                <th width="75px" class="header">Latest Ship-To-Site</th>
                <th width="30px" class="header">Total Parts</th>
                <th width="30px" class="header">OEM Rcvd</th>
                <th width="30px" class="header">Minor Rcvd</th>
                <th width="30px" class="header">Total Received</th>
                <th width="30px" class="header">% On Site</th>
                <th width="60px" class="header">Actions</th>
            </tr>

분명히 내 테이블에는 이것보다 많은 행이 있습니다. 193은 정확하지만 헤더 행이 반복되는 위치를 볼 수 있습니다. 반복 헤더 행은이 기능에 의해 설정됩니다.

jQuery

// Clone the original header row and add the "repeated-header" class
var tblHeader = $('tr.boxheadrow').clone().addClass('repeated-header');

// Add the cloned header with the new class every 34th row (or as you see fit)
$('tbody tr:odd:nth-of-type(17n)').after(tblHeader);

// On the 'sortStart' routine, remove all the inserted header rows
$('#pmtable').bind('sortStart', function() {
    $('.repeated-header').remove();
    // On the 'sortEnd' routine, add back all the header row lines.
}).bind('sortEnd', function() {
    $('tbody tr:odd:nth-of-type(17n)').after(tblHeader);
});

0

많은 사람들이이 답변을 찾고있는 것 같습니다. 다른 질문에 대한 답에 묻혔습니다. 두 개의 다른 프레임에서 테이블 사이의 열 너비 동기화 등

내가 시도한 수십 가지 방법 중 이것이 내가 찾은 유일한 방법은 헤더 테이블이 동일한 너비를 갖는 스크롤 맨 아래 테이블을 가질 수있게하는 것입니다.

여기에 내가 그것을 어떻게이다, 첫째 나는 모두에서 작동하는이 기능을 생성하는 위의 jsfiddle에 개선 tdth(사용 다른 사람까지 여행하는 경우에 th자신의 헤더 행의 스타일링을).

var setHeaderTableWidth= function (headertableid,basetableid) {
            $("#"+headertableid).width($("#"+basetableid).width());
            $("#"+headertableid+" tr th").each(function (i) {
                $(this).width($($("#"+basetableid+" tr:first td")[i]).width());
            });
            $("#" + headertableid + " tr td").each(function (i) {
                $(this).width($($("#" + basetableid + " tr:first td")[i]).width());
            });
        }

다음으로 두 개의 테이블을 만들어야합니다. 참고 헤더 테이블에는 TD다음과 같이 스크롤 막대의 최상위 테이블에 여유 공간이 있어야합니다.

 <table id="headertable1" class="input-cells table-striped">
        <thead>
            <tr style="background-color:darkgray;color:white;"><th>header1</th><th>header2</th><th>header3</th><th>header4</th><th>header5</th><th>header6</th><th></th></tr>
        </thead>
     </table>
    <div id="resizeToBottom" style="overflow-y:scroll;overflow-x:hidden;">
        <table id="basetable1" class="input-cells table-striped">
            <tbody >
                <tr>
                    <td>testdata</td>
                    <td>2</td>
                    <td>3</td>
                    <td>4</span></td>
                    <td>55555555555555</td>
                    <td>test</td></tr>
            </tbody>
        </table>
    </div>

그런 다음 다음과 같이하십시오.

        setHeaderTableWidth('headertable1', 'basetable1');
        $(window).resize(function () {
            setHeaderTableWidth('headertable1', 'basetable1');
        });

이것은 스택 오버플로에서 발견 된 유일한 많은 솔루션으로 게시 된 많은 유사한 질문에서 작동하며 모든 경우에 작동합니다.

예를 들어 durandal에서는 작동하지 않는 jQuery stickytables 플러그인을 사용해 보았습니다 .Google 코드 프로젝트는 https://code.google.com/p/js-scroll-table-header/issues/detail?id=2입니다.

테이블 복제와 관련된 다른 솔루션, 성능이 저하되거나 모든 경우에 빨라지고 작동하지 않습니다.

지나치게 복잡한 솔루션이 필요하지 않습니다. 아래 예제와 같이 두 개의 테이블을 만들고 here 및 boom 과 같이 setHeaderTableWidth 함수를 호출 하면 완료됩니다 .

이것이 효과가 없다면 CSS 상자 크기 속성을 사용하고 있었을 것이므로 올바르게 설정해야합니다. 우연히 CSS 내용을 망칠 수 있습니다. 잘못 될 수있는 많은 것들이 있으므로, 그 점을 알고 /주의하십시오. 이 방법은 저에게 효과적입니다 .


0

여기에 우리가 일한 해결책이 있습니다 (일부 경우와 이전 버전의 Internet Explorer를 처리하기 위해 결국 스크롤에서 제목 표시 줄을 희미하게 한 다음 스크롤이 끝나면 다시 사라졌습니다.하지만 Firefox 및 WebKit 브라우저에서는 이 솔루션 은 작동합니다. 하지만 border-collapse : collapse로 가정합니다.

이 솔루션의 핵심은 당신이 적용되면 경계 붕괴 , CSS의 변환을 그냥 스크롤 이벤트를 차단하고 올바르게 변환 설정의 문제, 그래서 헤더에서 작동합니다. 아무것도 복제 할 필요가 없습니다. 브라우저에서 이러한 동작이 제대로 구현되지 않으면 더 가벼운 솔루션을 상상하기 어렵습니다.

JSFiddle : http://jsfiddle.net/podperson/tH9VU/2/

간단한 jQuery 플러그인으로 구현됩니다. $ ( 'thead'). sticky ()와 같은 호출로 단순히 thead를 끈적 거리게 만들면 매달릴 것입니다. 페이지의 여러 테이블과 헤드 섹션의 절반 아래에있는 큰 테이블에서 작동합니다.

$.fn.sticky = function(){
    $(this).each( function(){
        var thead = $(this),
            tbody = thead.next('tbody');

        updateHeaderPosition();

        function updateHeaderPosition(){
            if(
                thead.offset().top < $(document).scrollTop()
                && tbody.offset().top + tbody.height() > $(document).scrollTop()
            ){
                var tr = tbody.find('tr').last(),
                    y = tr.offset().top - thead.height() < $(document).scrollTop()
                        ? tr.offset().top - thead.height() - thead.offset().top
                        : $(document).scrollTop() - thead.offset().top;

                thead.find('th').css({
                    'z-index': 100,
                    'transform': 'translateY(' + y + 'px)',
                    '-webkit-transform': 'translateY(' + y + 'px)'
                });
            } else {
                thead.find('th').css({
                    'transform': 'none',
                    '-webkit-transform': 'none'
                });
            }
        }

        // See http://www.quirksmode.org/dom/events/scroll.html
        $(window).on('scroll', updateHeaderPosition);
    });
}

$('thead').sticky();

좋은 해결책이지만 열 사이에 열 경계를 어떻게 포함합니까 (고정 헤더에서 td 데이터에 정렬)?
user5249203

나는 당신의 문제를 이해하지 못합니다. border-collapse는 테두리, 여백 등을 사용하지 못하게하는 것이 아니라 yore의 부두 테이블 메트릭을 제거합니다.
podperson

1
에 추가 border: 2px solid red;하고 th스크롤하면 문제가 나타납니다. :이 더 염기성 용액 자신을 함께했다 jsfiddle.net/x6pLcor9/19
calandoa

td에 동일한 치수의 테두리를 추가하면 아무런 문제가 없습니다. 나는 당신의 요점이 보이지 않습니다. 귀하의 버전은 훨씬 깨끗하고 jQuery를 사용하지 않으므로 오늘과 같은 것을 사용하십시오. (솔직히, 나는 오늘 테이블을 전혀 사용하지 않을 것이라고 생각합니다.)
podperson

0

Maximilian Hils가 게시 한 답변에 대한 향상된 답변이 있습니다.

이것은 깜박임없이 Internet Explorer 11에서 작동합니다.

var headerCells = tableWrap.querySelectorAll("thead td");
for (var i = 0; i < headerCells.length; i++) {
    var headerCell = headerCells[i];
    headerCell.style.backgroundColor = "silver";
}
var lastSTop = tableWrap.scrollTop;
tableWrap.addEventListener("scroll", function () {
    var stop = this.scrollTop;
    if (stop < lastSTop) {
        // Resetting the transform for the scrolling up to hide the headers
        for (var i = 0; i < headerCells.length; i++) {
            headerCells[i].style.transitionDelay = "0s";
            headerCells[i].style.transform = "";
        }
    }
    lastSTop = stop;
    var translate = "translate(0," + stop + "px)";
    for (var i = 0; i < headerCells.length; i++) {
        headerCells[i].style.transitionDelay = "0.25s";
        headerCells[i].style.transform = translate;
    }
});

0

올바른 형식의 HTML 테이블을 고정 테이블 헤더 및 열이있는 스크롤 가능한 테이블로 변환하기위한 간단한 경량 jQuery 플러그인을 개발했습니다.

플러그인은 고정 섹션을 스크롤 가능한 섹션과 픽셀 단위로 배치하는 데 적합합니다. 또한 가로로 스크롤 할 때 항상 표시되는 열 수를 고정 할 수도 있습니다.

데모 및 문서 : http://meetselva.github.io/fixed-table-rows-cols/

GitHub 리포지토리 : https://github.com/meetselva/fixed-table-rows-cols

다음은 고정 헤더가있는 간단한 테이블의 사용법입니다.

$(<table selector>).fxdHdrCol({
    width:     "100%",
    height:    200,
    colModal: [{width: 30, align: 'center'},
               {width: 70, align: 'center'}, 
               {width: 200, align: 'left'}, 
               {width: 100, align: 'center'}, 
               {width: 70, align: 'center'}, 
               {width: 250, align: 'center'}
              ]
});

"잘 HTML 테이블" 은 무엇입니까 ?
Peter Mortensen

@PeterMortensen "잘 포맷 된 HTML"이어야합니다. 고마워요
Selvakumar Arumugam

0
<html>
<head>
    <script src="//cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js"></script>
    <script>
        function stickyTableHead (tableID) {
            var $tmain = $(tableID);
            var $tScroll = $tmain.children("thead")
                .clone()
                .wrapAll('<table id="tScroll" />')
                .parent()
                .addClass($(tableID).attr("class"))
                .css("position", "fixed")
                .css("top", "0")
                .css("display", "none")
                .prependTo("#tMain");

            var pos = $tmain.offset().top + $tmain.find(">thead").height();


            $(document).scroll(function () {
                var dataScroll = $tScroll.data("scroll");
                dataScroll = dataScroll || false;
                if ($(this).scrollTop() >= pos) {
                    if (!dataScroll) {
                        $tScroll
                            .data("scroll", true)
                            .show()
                            .find("th").each(function () {
                                $(this).width($tmain.find(">thead>tr>th").eq($(this).index()).width());
                            });
                    }
                } else {
                    if (dataScroll) {
                        $tScroll
                            .data("scroll", false)
                            .hide()
                        ;
                    }
                }
            });
        }

        $(document).ready(function () {
            stickyTableHead('#tMain');
        });
    </script>
</head>

<body>
    gfgfdgsfgfdgfds<br/>
    gfgfdgsfgfdgfds<br/>
    gfgfdgsfgfdgfds<br/>
    gfgfdgsfgfdgfds<br/>
    gfgfdgsfgfdgfds<br/>
    gfgfdgsfgfdgfds<br/>

    <table id="tMain" >
        <thead>
        <tr>
            <th>1</th> <th>2</th><th>3</th> <th>4</th><th>5</th> <th>6</th><th>7</th> <th>8</th>

        </tr>
        </thead>
        <tbody>
            <tr><td>11111111111111111111111111111111111111111111111111111111</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
        </tbody>
    </table>
</body>
</html>

0

@Daniel Waltrip 답변 추가. position: relative작업하려면 테이블을 div로 묶어야 position:sticky합니다. 샘플 코드를 여기에 게시하고 싶습니다.

CSS

/* Set table width/height as you want.*/
div.freeze-header {
  position: relative;
  max-height: 150px;
  max-width: 400px;
  overflow:auto;
}

/* Use position:sticky to freeze header on top*/
div.freeze-header > table > thead > tr > th {
  position: sticky;
  top: 0;
  background-color:yellow;
}

/* below is just table style decoration.*/
div.freeze-header > table {
  border-collapse: collapse;
}

div.freeze-header > table td {
  border: 1px solid black;
}

HTML

<html>
<body>
  <div>
   other contents ...
  </div>
  <div>
   other contents ...
  </div>
  <div>
   other contents ...
  </div>

  <div class="freeze-header">
    <table>
       <thead>
         <tr>
           <th> header 1 </th>
           <th> header 2 </th>
           <th> header 3 </th>
           <th> header 4 </th>
           <th> header 5 </th>
           <th> header 6 </th>
           <th> header 7 </th>
           <th> header 8 </th>
           <th> header 9 </th>
           <th> header 10 </th>
           <th> header 11 </th>
           <th> header 12 </th>
           <th> header 13 </th>
           <th> header 14 </th>
           <th> header 15 </th>
          </tr>
       </thead>
       <tbody>
         <tr>
           <td> data 1 </td>
           <td> data 2 </td>
           <td> data 3 </td>
           <td> data 4 </td>
           <td> data 5 </td>
           <td> data 6 </td>
           <td> data 7 </td>
           <td> data 8 </td>
           <td> data 9 </td>
           <td> data 10 </td>
           <td> data 11 </td>
           <td> data 12 </td>
           <td> data 13 </td>
           <td> data 14 </td>
           <td> data 15 </td>
          </tr>         
         <tr>
           <td> data 1 </td>
           <td> data 2 </td>
           <td> data 3 </td>
           <td> data 4 </td>
           <td> data 5 </td>
           <td> data 6 </td>
           <td> data 7 </td>
           <td> data 8 </td>
           <td> data 9 </td>
           <td> data 10 </td>
           <td> data 11 </td>
           <td> data 12 </td>
           <td> data 13 </td>
           <td> data 14 </td>
           <td> data 15 </td>
          </tr>         
         <tr>
           <td> data 1 </td>
           <td> data 2 </td>
           <td> data 3 </td>
           <td> data 4 </td>
           <td> data 5 </td>
           <td> data 6 </td>
           <td> data 7 </td>
           <td> data 8 </td>
           <td> data 9 </td>
           <td> data 10 </td>
           <td> data 11 </td>
           <td> data 12 </td>
           <td> data 13 </td>
           <td> data 14 </td>
           <td> data 15 </td>
          </tr>         
         <tr>
           <td> data 1 </td>
           <td> data 2 </td>
           <td> data 3 </td>
           <td> data 4 </td>
           <td> data 5 </td>
           <td> data 6 </td>
           <td> data 7 </td>
           <td> data 8 </td>
           <td> data 9 </td>
           <td> data 10 </td>
           <td> data 11 </td>
           <td> data 12 </td>
           <td> data 13 </td>
           <td> data 14 </td>
           <td> data 15 </td>
          </tr>         
         <tr>
           <td> data 1 </td>
           <td> data 2 </td>
           <td> data 3 </td>
           <td> data 4 </td>
           <td> data 5 </td>
           <td> data 6 </td>
           <td> data 7 </td>
           <td> data 8 </td>
           <td> data 9 </td>
           <td> data 10 </td>
           <td> data 11 </td>
           <td> data 12 </td>
           <td> data 13 </td>
           <td> data 14 </td>
           <td> data 15 </td>
          </tr>         
         <tr>
           <td> data 1 </td>
           <td> data 2 </td>
           <td> data 3 </td>
           <td> data 4 </td>
           <td> data 5 </td>
           <td> data 6 </td>
           <td> data 7 </td>
           <td> data 8 </td>
           <td> data 9 </td>
           <td> data 10 </td>
           <td> data 11 </td>
           <td> data 12 </td>
           <td> data 13 </td>
           <td> data 14 </td>
           <td> data 15 </td>
          </tr>         
         <tr>
           <td> data 1 </td>
           <td> data 2 </td>
           <td> data 3 </td>
           <td> data 4 </td>
           <td> data 5 </td>
           <td> data 6 </td>
           <td> data 7 </td>
           <td> data 8 </td>
           <td> data 9 </td>
           <td> data 10 </td>
           <td> data 11 </td>
           <td> data 12 </td>
           <td> data 13 </td>
           <td> data 14 </td>
           <td> data 15 </td>
          </tr>         
         <tr>
           <td> data 1 </td>
           <td> data 2 </td>
           <td> data 3 </td>
           <td> data 4 </td>
           <td> data 5 </td>
           <td> data 6 </td>
           <td> data 7 </td>
           <td> data 8 </td>
           <td> data 9 </td>
           <td> data 10 </td>
           <td> data 11 </td>
           <td> data 12 </td>
           <td> data 13 </td>
           <td> data 14 </td>
           <td> data 15 </td>
          </tr>         
       </tbody>
    </table>
  </div>
</body>
</html>

데모

여기에 이미지 설명을 입력하십시오

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.