Tabela HTML ze stałymi nagłówkami?

231

Czy istnieje technika CSS / JavaScript dla różnych przeglądarek, która wyświetla długą tabelę HTML, tak aby nagłówki kolumn pozostały nieruchome na ekranie i nie przewijały się wraz z treścią tabeli. Pomyśl o efekcie „zamrożenia okien” w programie Microsoft Excel.

Chcę móc przewijać zawartość tabeli, ale zawsze widzieć nagłówki kolumn u góry.

Cheekysoft
źródło
3
Spróbuj to: Czysta CSS przewijalnych tabela z Fixed Header EDIT : To powinno działać w programie Internet Explorer 7, jak widać na przykładzie : Przewijanie HTML tabela z Poprawiono nagłówek EDIT 2: Znalazłem kilka dodatkowych linków, które mogą być użyteczne: - Głupia naprawiony nagłówek - Wtyczka jQuery z pewnymi ograniczeniami. - [Naprawiono nagłówki tabeli] ( cross-browser.com/x/examp
gcores
Natknąłem się na wiele rozwiązań, które na ogół działają, ale żadne z nich nie działało przewijanie div. Mam na myśli, że twój stół jest wewnątrz przewijalnego div i nadal chcesz nagłówek tabeli wciąż wewnątrz tego div. Rozwiązałem to i udostępniłem rozwiązanie tutaj .
Yogee
9
W 2018 roku, wszystkie przeglądarki mogą korzystać następujące proste rozwiązanie: thead th { position: sticky; top: 0; }. Safari potrzebuje prefiksu dostawcy:-webkit-sticky
Daniel Waltrip
1
@DanielWaltrip powinieneś dodać tę odpowiedź, aby uzyskać awans na najwyższe miejsce - wszystkie inne odpowiedzi są zbędne z pozycją: lepka jest lepszym wsparciem w dzisiejszych czasach
Peter Kerr
1
Gotowe! stackoverflow.com/a/52637779/111635
Daniel Waltrip

Odpowiedzi:

88

Przez jakiś czas szukałem rozwiązania tego problemu i stwierdziłem, że większość odpowiedzi nie działa lub nie pasuje do mojej sytuacji, dlatego napisałem proste rozwiązanie w jQuery.

Oto zarys rozwiązania:

  1. Sklonuj tabelę, która musi mieć stały nagłówek, i umieść sklonowaną kopię na oryginale.
  2. Usuń korpus stołu z górnego stołu.
  3. Usuń nagłówek tabeli z dolnej tabeli.
  4. Dostosuj szerokości kolumn. (Śledzimy oryginalne szerokości kolumn)

Poniżej znajduje się kod w uruchomionej wersji demonstracyjnej.

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>

To rozwiązanie działa w Chrome i IE. Ponieważ jest oparty na jQuery, powinno to również działać w innych przeglądarkach obsługiwanych przez jQuery.

Mahes
źródło
4
i jak możemy rozwiązać problem, gdy zawartość jest większa niż szerokość?
Maertz
1
@tetra td {max-width: 30px; } pozwoli to deweloperowi kontrolować sposób wyświetlania wierszy.
Lyuben Todorov
Ale co, jeśli zawartość w jakiejś komórce nagłówka jest dłuższa niż w komórkach td? Próbowałem tego w IE7, a width () wszystko psuje. IE8 i IE9 działają dobrze, ale ...
JustAMartin
4
Niestety, jeśli potrzebujesz wyrównania kolumn w pikselach, to nie działa: jsbin.com/elekiq/1 ( kod źródłowy ). Widać, że niektóre nagłówki są nieznacznie przesunięte względem miejsca, w którym powinny być. Efekt jest bardziej widoczny, jeśli używasz tła: jsbin.com/elekiq/2 ( kod źródłowy ). (Pracowałem według tych samych zasad, natknąłem się na to w moim kodzie, znalazłem twój i pomyślałem: „Och, zastanawiam się, czy on rozwiązał to dla mnie!” Niestety nie. :-)) Przeglądarki są TAKIE z bólu, że chcą kontrolować szerokości komórek ...
TJ Crowder
Wydaje się, że nie działa to z przewijaniem w poziomie - tworzy nagłówek, ale wykracza poza obszar przewijalny (widocznie) i nie przewija się wraz z zawartością.
Zawieszenie
183

Można to rozwiązać w czterech wierszach kodu.

Jeśli zależy Ci tylko na nowoczesnych przeglądarkach, można znacznie łatwiej uzyskać stały nagłówek, używając transformacji CSS. Brzmi dziwnie, ale działa świetnie:

  • HTML i CSS pozostają bez zmian.
  • Brak zewnętrznych zależności JavaScript.
  • Cztery linie kodu.
  • Działa dla wszystkich konfiguracji (układ tabeli: stały itp.).
document.getElementById("wrap").addEventListener("scroll", function(){
   var translate = "translate(0,"+this.scrollTop+"px)";
   this.querySelector("thead").style.transform = translate;
});

Obsługa transformacji CSS jest szeroko dostępna, z wyjątkiem przeglądarki Internet Explorer 8-.

Oto pełny przykład w celach informacyjnych:

Maksymilian Hils
źródło
8
Muszę powiedzieć, że pomimo mojego poprzedniego komentarza jest to najbliższe idealne rozwiązanie, jakie widziałem. Nawet przewijanie w poziomie jest idealne (lepsze niż moje własne rozwiązanie). Oto przykład z ramkami (nie można użyć zwinięcia ramki) i paskiem przewijania, który przykleja się do stołu zamiast kontenera: jsfiddle
DoctorDestructo
11
Okazało się, że działa, ale trzeba zastosować transformację th / td, a nie thead.
ruda
5
@AlexAlexeev, twoje rozwiązanie jest niesamowite. Dziękuję Ci. Zauważyłem, że wynikowy stały nagłówek nie ma linii granicznych, które odróżniają kolumny. Domyślny styl CSS został utracony. Nawet kiedy to dołączę ... $(this).addClass('border')zmienia resztę tabeli zawiera czcionki, rozmiar, kolor, który przekazuję w klasie granicznej. Ale nie dodaje wierszy do stałego nagłówka. Doceń, wszelkie dane wejściowe, jak to naprawić
user5249203
5
@ user5249203 wiem pytasz kilka miesięcy temu, ale miałem ten sam problem i to z powodu border-collapse: zobacz to: stackoverflow.com/questions/33777751/... .
archz.
6
To nie działa w żadnej wersji IE ani w Edge. Oto wersja, która działa na podstawie komentarza @ redhead jsfiddle.net/n6o8ocwb/2
rob
58

Właśnie skończyłem układać wtyczkę jQuery, która pobierze prawidłową pojedynczą tabelę przy użyciu prawidłowego HTML (musi mieć thead i tbody) i wyświetli tabelę, która ma stałe nagłówki, opcjonalnie stała stopka, która może być albo sklonowanym nagłówkiem, albo dowolnym wybrane treści (paginacja itp.). Jeśli chcesz skorzystać z większych monitorów, przeskaluje on również tabelę przy zmianie rozmiaru przeglądarki. Kolejną dodaną funkcją jest możliwość przewijania z boku, jeśli kolumny tabeli nie mogą się zmieścić w widoku.

http://fixedheadertable.com/

na github: http://markmalek.github.com/Fixed-Header-Table/

Jest niezwykle łatwy w konfiguracji i możesz tworzyć własne niestandardowe style. Używa również zaokrąglonych rogów we wszystkich przeglądarkach. Pamiętaj, że właśnie ją wypuściłem, więc nadal jest technicznie w wersji beta i jest kilka drobnych problemów, które rozwiązuję.

Działa w Internet Explorer 7, Internet Explorer 8, Safari, Firefox i Chrome.

znak
źródło
Dzięki! Dodam dzisiaj nowe wydanie, kiedy wrócę z pracy do domu. Oto link do mojego wpisu na blogu z tym, co dodaję
Mark,
Dziękuję Ci za to. Wiem, że to pytanie ma ponad rok, ale nawet ryzykując zamieszanie osiadłego mułu, chciałbym powiedzieć, że twoja praca jest doceniana
sova
W twoim demo szerokości są wyłączone w ie6 :-( nagłówek tabeli i
treść
4
Najnowsza wersja nie działa w IE6. Nie obsługuję już IE6.
Mark
świetna robota Mark - niestety występują pewne problemy z przewijaniem stałego nagłówka i kolumny w urządzeniach mobilnych (iPad, tablet z Androidem) - kiedy przewijam zawartość, te stałe części nie przewijają się - kiedy przestaję przewijać i stukam raz w stół , części stałe „przeskakują” na właściwe pozycje - czy istnieje prosty sposób to naprawić?
Okizb,
23

Stworzyłem również wtyczkę, która rozwiązuje ten problem. Mój projekt - jQuery.floatThead istnieje już od ponad 4 lat i jest bardzo dojrzały.

Nie wymaga zewnętrznych stylów i nie oczekuje, że Twój stół będzie stylizowany w jakikolwiek szczególny sposób. Obsługuje Internet Explorer9 + i Firefox / Chrome.

Obecnie (2018-05) ma:

405 zmian i 998 gwiazdek na GitHub


Wiele (nie wszystkie) odpowiedzi tutaj to szybkie hacki, które mogły rozwiązać problem jednej osoby, ale nie będą działać na każdym stole.

Niektóre inne wtyczki są stare i prawdopodobnie działają świetnie z Internet Explorerem, ale będą działać w Firefox i Chrome.

mkoryak
źródło
1
Świetna wtyczka, obsługuje zagnieżdżone tabele i przesunięcia.
Mihai Alex
2
Wspaniały. Wielkie dzięki. Wtyczka działała dobrze w Firefoksie 45.2, Chromium 51 i IE 11. Ponadto nie koliduje z wieloma kodami JS i jQuery zbudowanymi na tej samej stronie.
Aldo Paradiso
Dziękuję Ci. Z przyjemnością informuję, że w tym momencie projekt otrzymuje około 1 raport o błędach co 4 miesiące. Nie dokonuję wielu przełomowych zmian. Jest dość solidny i działa.
mkoryak
20

TL; DR

Jeśli celujesz w nowoczesne przeglądarki i nie potrzebujesz ekstrawaganckich stylizacji: http://jsfiddle.net/dPixie/byB9d/3/ ... Mimo że wersja z czterema dużymi wersjami jest całkiem słodka, ta wersja lepiej radzi sobie z szerokością płynu.

Dobre wieści wszyscy!

Dzięki postępom HTML5 i CSS3 jest to teraz możliwe, przynajmniej w przypadku nowoczesnych przeglądarek. Lekko hackerską implementację, którą wymyśliłem, można znaleźć tutaj: http://jsfiddle.net/dPixie/byB9d/3/ . Przetestowałem to w FX 25, Chrome 31 i IE 10 ...

Trafny HTML (wstaw dokument HTML5 na górze dokumentu):

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>

Ale jak?!

Mówiąc prosto, masz nagłówek tabeli, który wizualnie ukrywasz, ustawiając go na 0px, który zawiera również div używane jako stały nagłówek. Pojemnik stołu pozostawia wystarczająco dużo miejsca u góry, aby umożliwić umieszczenie nagłówka w absolutnie ustawionej pozycji, a stół z paskami przewijania wygląda tak, jak można się spodziewać.

Powyższy kod wykorzystuje klasę pozycjonowaną do absolutnego pozycjonowania tabeli (używam jej w wyskakującym oknie dialogowym), ale możesz również użyć jej w obiegu dokumentu, usuwając positionedklasę z kontenera.

Ale ...

To nie jest idealne. Firefox nie chce, aby wiersz nagłówka wynosił 0 pikseli (przynajmniej nie znalazłem żadnego sposobu), ale uparcie utrzymuje go na poziomie co najmniej 4 pikseli ... To nie jest duży problem, ale w zależności od stylu będzie bałaganił twoje granice itp.

W tabeli zastosowano również fikcyjną kolumnę, w której kolor tła samego kontenera jest używany jako tło dla div div nagłówka, które są przezroczyste.

Podsumowanie

Podsumowując, mogą występować problemy ze stylizacją w zależności od twoich wymagań, szczególnie obramowania lub skomplikowanego tła. Mogą występować również problemy z obliczalnością, nie sprawdziłem go jeszcze w wielu różnych przeglądarkach (jeśli wypróbujesz, skomentuj swoje doświadczenia), ale nie znalazłem czegoś podobnego, więc pomyślałem, że warto opublikować tak czy siak ...

Jonas Schubert Erlandsson
źródło
Jeśli zmniejszysz szerokość okna, dopóki nie zacznie się przewijanie w poziomie, nagłówek nie będzie przewijał się w poziomie wraz z ciałem. Cerować.
dlaliberte
@dlaliberte - Cóż, ponieważ nagłówek i tabela są w rzeczywistości dwoma różnymi elementami, które możesz, oczywiście, wpaść w dziwność. Ale mój przykład nie pozwala na przepełnienie kolumn tabeli, a nagłówki są zwykle łatwiejsze do kontrolowania niż zawartość tabeli. To powiedziawszy, jeśli spowodujesz „przepełnienie” nagłówka, jeśli będzie wystawał po prawej stronie tabeli i wyglądał na poważnie zepsuty. Możesz to naprawić, ustawiając minimalną szerokość na stole, zmuszając go również do przepełnienia strony ... Ale to hack, więc nigdy nie będzie idealny ...
Jonas Schubert Erlandsson
1
Warto zauważyć, że wymaga to projektu, w którym można określić stół o stałej wysokości.
Cheekysoft
1
@Cheekysoft - Nie, zawartość tabeli i wiersza może swobodnie przepływać. Kontener, w moim przykładzie <section>element, musi być ograniczony wysokością tylko po to, aby zmusić go do przepełnienia i pokazać przewijanie. Każdy układ, który spowoduje przepełnienie kontenera, będzie działał. Jeśli znajdziesz przypadek, w którym go nie ma, opublikuj link do skrzypce.
Jonas Schubert Erlandsson
Zakodowana padding-topwartość oznacza również, że jeśli tekst nagłówka tabeli znajduje się w więcej niż jednym wierszu, pojawi się na górze komórek tabeli. Szkoda, bo przez większość czasu działa to jak urok. Naprawdę fajna sztuczka divw thcelu obejścia problemu zmiany rozmiaru kolumny, który ma większość innych rozwiązań.
Bernhard Hofmann
19

Wszystkie próby rozwiązania tego spoza specyfikacji CSS są bladym cieniem tego, czego naprawdę chcemy: Dostarczenie na podstawie domniemanej obietnicy THEAD.

Ten problem z zawieszonymi nagłówkami przy stole od dłuższego czasu stanowi otwartą ranę w HTML / CSS.

W idealnym świecie rozwiązanie tego problemu byłoby oparte wyłącznie na CSS. Niestety, wydaje się, że nie ma dobrego.

Odpowiednie dyskusje dotyczące standardów na ten temat obejmują:

AKTUALIZACJA : Firefox jest dostarczany position:stickyw wersji 32. Wszyscy wygrywają!

djsadinoff
źródło
Byłoby wspaniale mieć lisy kolumn w ten sam sposób
Csaba Toth
4
Re. Firefox i pozycja: lepka, nie działa w przypadku nagłówków tabel: bugzilla.mozilla.org/show_bug.cgi?id=925259#c8 ... Łatka dla tego błędu wyraźnie stwierdza: „Obecnie nie obsługujemy pozycjonowania względnego wewnętrznych elementów stołu, dlatego też wykluczamy je z lepkiego pozycjonowania. ”
Jonas Schubert Erlandsson,
2
To działa we wszystkich przeglądarkach teraz: thead th { position: sticky; top: 0; }. Czy możemy zaktualizować tę odpowiedź, aby wyraźnie to stwierdzić?
Daniel Waltrip
1
@DanielWaltrip wszystkie przeglądarki? stackoverflow.com/a/37646284/3640407 Wciąż jest więcej MSIE niż Edges
edc65
Uczciwy punkt. Jest obsługiwany dla 86% globalnych użytkowników sieci, zgodnie z caniuse.com/#search=position%3Asticky
Daniel Waltrip
14

Oto wtyczka jQuery do stałych nagłówków tabel. Pozwala przewijać całą stronę, zamrażając nagłówek, gdy osiągnie górę. Działa dobrze z tabelami Bootstrap na Twitterze .

Repozytorium GitHub: https://github.com/oma/table-fixed-header

Robi nie przewijać tylko tabelę zawartości. Spójrz na inne narzędzia do tego, jako jedną z tych innych odpowiedzi. Ty decydujesz, co najlepiej pasuje do Twojej skrzynki.

oma
źródło
1
Bummer - przykładowy link nie działa. „Ups! Denne siden ble ikke funnet ...” Szkoda, że ​​kod nie został tu wklejony.
JosephK
tak ... przepraszam za to. usunął link. Projekt nie jest już obsługiwany
oma
Nie martw się - wypróbowałem kilka z tych wstępnie rzekomych rozwiązań - żadne nie działało z tabelą flex-col-width, która przekraczała szerokość ekranu. Skończyło się na tym, że napisałem własne rozwiązanie.
JosephK
9

Większość zamieszczonych tutaj rozwiązań wymaga jQuery. Jeśli szukasz niezależnego od frameworka rozwiązania, wypróbuj Grid: http://www.matts411.com/post/grid/

Jest hostowany na Github tutaj: https://github.com/mmurph211/Grid

Obsługuje nie tylko stałe nagłówki, ale także między innymi stałe lewe kolumny i stopki.

Matt
źródło
To jest naprawdę fajne, jeśli spełnia twoje potrzeby, po prostu bawiłem się dzisiaj. Niestety jest to raczej prostokątna siatka (jak sama nazwa wskazuje), a nie prawdziwa tabela z wysokością wiersza regulowaną przez zawartość. A stylizacja poszczególnych rzędów wydawała się trudna. Nie udało mi się stworzyć stołu w paski zebry, ale nie bardzo się starałem, ponieważ moje potrzeby były bardziej złożone. W każdym razie, dobra robota.
mplwork
1
Hej, znam cię! Wydaje się, że napisaliśmy bardzo podobne gówno ( github.com/mkoryak/floatThead ) - Misha
mkoryak
9

Właściwość CSS position: stickyma świetne wsparcie w większości nowoczesnych przeglądarek (miałem problemy z Edge, patrz poniżej).

To pozwala nam dość łatwo rozwiązać problem stałych nagłówków:

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

Safari potrzebuje przedrostka dostawcy: -webkit-sticky.

W przypadku przeglądarki Firefox musiałem dodać min-height: 0do jednego elementy nadrzędne. Zapominam dokładnie, dlaczego było to potrzebne.

Niestety, implementacja Microsoft Edge wydaje się działać tylko częściowo. Przynajmniej miałem trochę migotania i niedopasowanych komórek tabeli podczas moich testów. Stół był nadal użyteczny, ale miał poważne problemy estetyczne.

Daniel Waltrip
źródło
Korzystanie position: sticky;z tabelą wewnątrz div, które ma overflow: scroll;, overflow-x: scroll;lub overflow-y: scroll;. wydaje się być najlepszym i najprostszym rozwiązaniem dla stałych nagłówków tabel i kolumn we współczesnych przeglądarkach. Ta odpowiedź musi zostać wybrana na szczyt.
Aberrant
To proste, ale skuteczne. Właśnie tego szukam. Dzięki.
Catbuilts
6

Bardziej dopracowana czysta tabela przewijania CSS

Wszystkie czyste rozwiązania CSS, które do tej pory widziałem - choć mogą być sprytne - nie mają pewnego poziomu dopracowania lub po prostu nie działają poprawnie w niektórych sytuacjach. Postanowiłem więc stworzyć własny ...

Cechy:

  • Jest to czysty CSS, więc nie wymaga jQuery (ani żadnego kodu JavaScript, jeśli o to chodzi)
  • Możesz ustawić szerokość tabeli na wartość procentową (aka „płyn”) lub stałą wartość lub pozwolić, aby treść określała jej szerokość (aka „auto”)
  • Szerokości kolumn mogą być również płynne, stałe lub automatyczne.
  • Kolumny nigdy nie zostaną wyrównane z nagłówkami z powodu przewijania w poziomie (problem, który występuje w każdym innym rozwiązaniu opartym na CSS, które nie wymaga ustalonych szerokości).
  • Kompatybilny ze wszystkimi popularnymi przeglądarkami komputerowymi, w tym Internet Explorer w wersji 8
  • Czysty, dopracowany wygląd; brak niechlujnych luk 1-pikselowych lub źle wyrównanych granic; wygląda tak samo we wszystkich przeglądarkach

Oto kilka skrzypiec, które pokazują opcje płynów i automatycznej szerokości:

  • Płynna szerokość i wysokość (dostosowuje się do rozmiaru ekranu): jsFiddle (Zauważ, że pasek przewijania pojawia się tylko w razie potrzeby w tej konfiguracji, więc może być konieczne zmniejszenie ramki, aby ją zobaczyć)

  • Automatyczna szerokość, stała wysokość (łatwiejsza integracja z innymi treściami): jsFiddle

Konfiguracja automatycznej szerokości i stałej wysokości prawdopodobnie ma więcej przypadków użycia, więc opublikuję poniższy kod.

/* 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]-->

Metoda zastosowana do zamrożenia wiersza nagłówka jest podobna do metody d-Pixie, więc wyjaśnienia znajdziesz w jego poście. W tej technice było mnóstwo błędów i ograniczeń, które można naprawić tylko za pomocą sterty dodatkowego CSS i dodatkowego kontenera div lub dwóch.

DoctorDestructo
źródło
Ta odpowiedź jest niedoceniana! Spędziłem dni próbując znaleźć inne rozwiązania, które mogłyby zadziałać w mojej szczególnie irytującej sprawie. Każdemu z nich nie udało się utrzymać wyrównania w taki czy inny sposób. W końcu to zrobiło! Na początku wydaje się to zbyt skomplikowane, ale kiedy już to zrozumiesz, niesamowite. Możesz usunąć sporo rzeczy, których w końcu nie potrzebujesz, gdy nie używasz szerokości płynu itp.
Justin Sane
1
@JustinSane Cieszę się, że ci się podoba! Sądzę, że brak uznania wynika z faktu, że dzieli on stronę z niesamowitym rozwiązaniem Maximiliana Hilsa . Jeśli nie jesteś przeciwny używaniu odrobiny JS, zdecydowanie powinieneś to sprawdzić.
DoctorDestructo
Cholera, to rzeczywiście prawie idealne rozwiązanie. W każdym razie korzystałem z jQuery, starałem się, aby działał z tym zanim znalazłem twój (poprzez twój komentarz do innego pytania). Nie myślałem o słuchaczu przewijania i tłumaczeniu ... Cóż, mówią, że genialne jest wymyślenie prostych rozwiązań ..;) Skończyłem projekt i działa idealnie bez js, ale pozostanę w tym umysł na przyszłość. Czapki z głów dla ciebie za bycie niesamowitym!
Justin Sane
Mały problem, ale jeśli używasz różnych kolorów systemowych, możesz zobaczyć, że kolor tekstu nie został ustawiony dla niczego oprócz nagłówków, ale tło tabeli ma wyraźny kolor tła. Mam żółty tekst na białym i szarym tle dla tego stołu.
Matt Arnold
1
@MattArnold Naprawiono. Dzięki za wskazówkę!
DoctorDestructo
5

Prosta wtyczka jQuery

Jest to odmiana rozwiązania Mahesa. Możesz to tak nazwać$('table#foo').scrollableTable();

Chodzi o to:

  • Podziel theadi tbodyna osobne tableelementy
  • Dopasuj szerokości komórek ponownie
  • Zawiń drugi tablewdiv.scrollable
  • Użyj CSS, aby div.scrollableprzewijać

CSS może być:

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

Ostrzeżenia

  • Oczywiście podział tych tabel sprawia, że ​​znaczniki są mniej semantyczne. Nie jestem pewien, jaki to ma wpływ na dostępność.
  • Ta wtyczka nie obsługuje stopek, wielu nagłówków itp.
  • Testowałem to tylko w Chrome w wersji 20.

To powiedziawszy, działa dla moich celów i możesz go wziąć i zmodyfikować.

Oto wtyczka:

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);
};
Nathan Long
źródło
1
Fajny skrypt, ten działał najlepiej w moim środowisku. Rozszerzyłem twój skrypt o stałą obsługę stopki, sprawdź mój post poniżej.
gitaarik
4

:)

Nie tak czyste, ale czyste rozwiązanie HTML / CSS.

table {
    overflow-x:scroll;
}

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

Zaktualizowano dla przykładu IE8 + JSFiddle

Anton Matyulkov
źródło
2
Dobrym rozwiązaniem, tylko wspomnieć, że komórki te są płynął a więc zgodnie z treścią mogą mieć różne wysokości, to jest widoczne, jeśli ich ustawienie graniczy: jsfiddle.net/ZdeEH/15
Stano
3

Wsparcie dla stałej stopki

Rozszerzyłem funkcję Nathana, aby obsługiwał również stałą stopkę i maksymalną wysokość. Ponadto funkcja ustawi sam CSS, a Ty musisz jedynie obsługiwać szerokość.

Stosowanie:

Naprawiono wysokość:

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

Maksymalna wysokość (jeśli przeglądarka obsługuje opcję CSS „maksymalna wysokość”):

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

Scenariusz:

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();
};
gitaarik
źródło
3

W jakiś sposób udało mi się Position:Stickydobrze pracować nad moją sprawą:

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>

Munkhdelger Tumenbayar
źródło
1
To najczystsze rozwiązanie, jakie do tej pory widziałem. caniuse pokazuje, że od 5/2/2020, nieokreślona pozycja: lepki cieszy się 90,06% globalnym wsparciem. To rozwiązanie działa dobrze we wszystkich nowoczesnych przeglądarkach.
AlienKevin
2

Dwa divy, jeden dla nagłówka, jeden dla danych. Ustaw przewijanie danych div i użyj JavaScript, aby ustawić szerokość kolumn w nagłówku, aby były takie same jak szerokości w danych. Myślę, że szerokości kolumn danych powinny być ustalone, a nie dynamiczne.

cjk
źródło
3
Jeśli zależy Ci na dostępności, jest to błąd.
epascarello
1
jeśli chodzi o dostępność, możemy zastąpić użycie diva stylem na <thead> i <tbody> ??
Cheekysoft
1

Zdaję sobie sprawę, że pytanie pozwala na JavaScript, ale tutaj opracowałem czyste rozwiązanie CSS, które pozwala również na powiększanie tabeli w poziomie. Został przetestowany z Internet Explorerem 10 i najnowszymi przeglądarkami Chrome i Firefox. Link do jsFiddle znajduje się na dole.

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>

A 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/

bzuillsmith
źródło
1

Dla tych, którzy wypróbowali dobre rozwiązanie podane przez Maximiliana Hilsa i nie udało mu się go uruchomić z Internet Explorerem, miałem ten sam problem (Internet Explorer 11) i dowiedziałem się, na czym polega problem.

W Internet Explorer 11 transformacja stylu (przynajmniej z tłumaczeniem) nie działa <THEAD>. Rozwiązałem to, stosując styl do wszystkich <TH>pętli. To się udało. Mój kod JavaScript wygląda następująco:

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;
  }
});

W moim przypadku tabelą był GridView w ASP.NET. Najpierw myślałem, że dzieje się tak, ponieważ nie ma <THEAD>, ale nawet kiedy zmusiłem go do posiadania, nie działało. Potem dowiedziałem się, co napisałem powyżej.

To bardzo ładne i proste rozwiązanie. W Chrome jest idealny, w Firefoksie nieco nierówny, a w Internet Explorerze jeszcze bardziej gwałtowny. Ale w sumie dobre rozwiązanie.

Magnus
źródło
0

Chciałbym wcześniej znaleźć rozwiązanie @ Mark, ale poszedłem i napisałem własne, zanim zobaczyłem to SO pytanie ...

Mój jest bardzo lekką wtyczką jQuery, która obsługuje stały nagłówek, stopkę, rozpinanie kolumn (colspan), zmianę rozmiaru, przewijanie w poziomie i opcjonalną liczbę wierszy do wyświetlenia przed rozpoczęciem przewijania.

jQuery.scrollTableBody (GitHub)

Dopóki masz tabelę z właściwego <thead>, <tbody>oraz (opcjonalnie) <tfoot>, wszystko co musisz zrobić, to w ten sposób:

$('table').scrollTableBody();
Noah Heldman
źródło
0

Znalazłem to obejście - przenieś wiersz nagłówka do tabeli powyżej tabeli z danymi:

<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>

Leonid Alzhin
źródło
działa dla małych stolików, ale jeśli masz przewijanie w poziomie, to rozwiązanie nie będzie działać.
crh225
To również nie będzie działać poprawnie, ponieważ kolumny tabeli nie zostaną wyrównane. Tutaj wymuszasz szerokość dla td, ale nie wolno nam tego robić ...
Ziggler
0

Dzięki zastosowaniu wtyczki jQuery StickyTableHeaders do tabeli, nagłówki kolumn będą się przesuwać na górze okienka ekranu podczas przewijania w dół.

Przykład:

$(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>

Shilovk
źródło
0

Podoba mi się odpowiedź Maximilliana Hilsa, ale miałem kilka problemów:

  1. transformacja nie działa w Edge ani IE, chyba że zastosujesz ją do th
  2. nagłówek miga podczas przewijania w Edge i IE
  3. moja tabela jest ładowana za pomocą ajax, więc chciałem dołączyć do zdarzenia przewijania okna, a nie zdarzenia przewijania opakowania

Aby pozbyć się migotania, używam limitu czasu, aby poczekać, aż użytkownik zakończy przewijanie, a następnie stosuję transformację - aby nagłówek nie był widoczny podczas przewijania.

Napisałem to również przy użyciu jQuery, jedną zaletą jest to, że jQuery powinno obsługiwać dla Ciebie prefiksy dostawcy

    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);

Stół jest owinięty div z klasą table-container-fixed.

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

Ustawiam zwinięcie obramowania, aby je rozdzielić, ponieważ w przeciwnym razie gubimy obramowania podczas tłumaczenia i usuwam obramowanie z tabeli, aby zawartość nie pojawiła się tuż nad komórką, w której obramowanie było podczas przewijania.

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

Robię thbiałe tło, aby zakryć komórki pod spodem, i dodam ramkę pasującą do ramki tabeli - która jest stylizowana za pomocą Bootstrap i przewijana poza pole widzenia.

 .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;
}
Colin
źródło
0

Użyj najnowszej wersji jQuery i dołącz następujący kod JavaScript.

$(window).scroll(function(){
  $("id of the div element").offset({top:$(window).scrollTop()});
});
Prabhavith
źródło
1
To nie działa. Może mógłbyś wyjaśnić, co chcesz od nas zrobić?
Chris
1
Jaki div? Mówimy tutaj o stołach
isapir
0

To nie jest dokładne rozwiązanie dla stałego wiersza nagłówka, ale stworzyłem dość genialną metodę powtarzania wiersza nagłówka w całej długiej tabeli, ale nadal zachowując możliwość sortowania.

Ta zgrabna mała opcja wymaga wtyczki jQuerytablesorter . Oto jak to działa:

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>

Oczywiście mój stół ma o wiele więcej wierszy niż ten. Dokładnie 193, ale widać, gdzie wiersz nagłówka się powtarza. Powtarzający się wiersz nagłówka jest konfigurowany przez tę funkcję:

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);
});
DevlshOne
źródło
0

Wydaje się, że wiele osób szuka tej odpowiedzi. Znalazłem go w odpowiedzi na inne pytanie tutaj: Synchronizacja szerokości kolumny między tabelami w dwóch różnych ramkach itp

Spośród dziesiątek metod, które wypróbowałem, jest to jedyna metoda, którą znalazłem, która działa niezawodnie, umożliwiając przewijanie dolnej tabeli z tabelą nagłówków o takich samych szerokościach.

Oto jak to zrobiłem. Najpierw ulepszyłem powyższą wersję jsfiddle, aby utworzyć tę funkcję, która działa zarówno na (jak tdi thna wypadek, gdyby wywoływało to u innych, którzy używają thstylizacji swoich wierszy nagłówka).

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());
            });
        }

Następnie musisz utworzyć dwie tabele, UWAGA: tabela nagłówków powinna mieć dodatkową przestrzeń, TDaby zostawić miejsce w górnej tabeli dla paska przewijania, jak poniżej:

 <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>

Następnie zrób coś takiego:

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

Jest to jedyne rozwiązanie, które znalazłem na stosie przepełnienia, które działa z wielu podobnych pytań, które zostały opublikowane, które działa we wszystkich moich przypadkach.

Na przykład wypróbowałem wtyczkę jQuery stickytables, która nie działa z durandal, oraz projekt Google Code tutaj https://code.google.com/p/js-scroll-table-header/issues/detail?id=2

Inne rozwiązania obejmujące klonowanie tabel, mają niską wydajność lub są do niczego i nie działają we wszystkich przypadkach.

Te zbyt złożone rozwiązania nie są potrzebne. Po prostu stwórz dwie tabele jak w poniższych przykładach i wywołaj funkcję setHeaderTableWidth jak opisano tutaj i boom, gotowe .

Jeśli to nie zadziała, prawdopodobnie grałeś ze swoją właściwością CSS i musisz ją poprawnie ustawić. Łatwo jest przypadkowo zepsuć zawartość CSS. Jest wiele rzeczy, które mogą pójść nie tak, więc bądź świadomy / ostrożny. To podejście działa dla mnie .

pilavdzice
źródło
0

Oto rozwiązanie, nad którym ostatecznie pracowaliśmy (aby poradzić sobie z niektórymi przypadkami krawędziowymi i starszymi wersjami Internet Explorera, w końcu również zmniejszyliśmy pasek tytułu podczas przewijania, a następnie przywróciliśmy go po zakończeniu przewijania, ale w przeglądarkach Firefox i WebKit to rozwiązanie po prostu działa . Przyjmuje załamanie granicy: zwinięcie.

Kluczem do tego rozwiązania jest to, że po zastosowaniu border-collapse , transformacje CSS działa w nagłówku, więc jest to tylko kwestia przechwytywania zdarzeń przewijania i ustawienie przekształcić prawidłowo. Nie musisz niczego kopiować. Poza tym, że takie zachowanie jest poprawnie zaimplementowane w przeglądarce, trudno wyobrazić sobie bardziej lekkie rozwiązanie.

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

Jest zaimplementowany jako prosta wtyczka jQuery. Po prostu sprawiasz, że twój thead jest lepki dzięki wywołaniu $ („thead”). Sticky (), a oni będą się trzymać. Działa z wieloma tabelami na stronie i nagłówkami w połowie dużych tabel.

$.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();
podperson
źródło
dobre rozwiązanie, ale jak dołączyć obramowanie kolumn między kolumnami (obie w ustalonym nagłówku, wyrównane do danych TD)?
user5249203
Nie jestem pewien, czy rozumiem twój problem. collapse-border nie uniemożliwia korzystania z ramek, marginesów itp., po prostu usuwa dotychczasowe parametry tabeli voodoo.
podperson
1
Dodaj border: 2px solid red;do th, przewijania i pojawi się problem. Wpadłem tym bardziej zasadowym roztworze sobie: jsfiddle.net/x6pLcor9/19
calandoa
Dodaj tę samą zwymiarowaną ramkę do td i nie ma problemu. Nie rozumiem twojego sensu. Twoja wersja jest znacznie czystsza i nie korzysta z jQuery, więc zdecydowanie wybrałbym coś takiego. (Chociaż, szczerze mówiąc, nie sądzę, bym użyć tabeli w ogóle dzisiaj.)
podperson
0

Oto ulepszona odpowiedź na opublikowaną przez Maximiliana Hilsa .

Ten działa w Internet Explorerze 11 bez migotania:

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;
    }
});
użytkownik4617883
źródło
0

Opracowałem prostą, lekką wtyczkę jQuery do konwertowania dobrze sformatowanej tabeli HTML na przewijaną tabelę ze stałym nagłówkiem i kolumnami.

Wtyczka działa dobrze, aby dopasować ustawienie piksela do piksela ustalonej sekcji z sekcją przewijalną. Ponadto można również zamrozić liczbę kolumn, które będą zawsze widoczne podczas przewijania w poziomie.

Demo i dokumentacja: http://meetselva.github.io/fixed-table-rows-cols/

Repozytorium GitHub: https://github.com/meetselva/fixed-table-rows-cols

Poniżej przedstawiono użycie prostej tabeli ze stałym nagłówkiem,

$(<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'}
              ]
});
Selvakumar Arumugam
źródło
Co to jest „dobrze napisana tabela HTML” ?
Peter Mortensen
@PeterMortensen Powinno być „dobrze sformatowanym HTML”. Edytowane, Dzięki.
Selvakumar Arumugam
0
<html>
<head>
    <script src="//cdn.jsdelivr.net/npm/[email protected]/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>
1,618
źródło
0

Dodatkowo do odpowiedzi @Daniel Waltrip. Tabela musi być dołączona do div position: relative, aby móc z nią pracować position:sticky. Więc chciałbym opublikować mój przykładowy kod tutaj.

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>

Próbny

wprowadź opis zdjęcia tutaj

Piyapan Poomsirivilai
źródło