HTML-Tabelle mit festen Headern?


230

Gibt es eine browserübergreifende CSS / JavaScript-Technik zum Anzeigen einer langen HTML-Tabelle, sodass die Spaltenüberschriften auf dem Bildschirm fest bleiben und nicht mit dem Tabellenkörper scrollen. Denken Sie an den Effekt "Fenster einfrieren" in Microsoft Excel.

Ich möchte in der Lage sein, durch den Inhalt der Tabelle zu scrollen, aber immer die Spaltenüberschriften oben sehen zu können.


3
Versuchen Sie Folgendes : Reine CSS-Bildlauftabelle mit fester Kopfzeile BEARBEITEN : Diese sollte in Internet Explorer 7 funktionieren, wie im Beispiel gezeigt : Scrollen der HTML-Tabelle mit fester Kopfzeile BEARBEITEN 2: Ich habe einige zusätzliche Links gefunden, die von Nutzen sein könnten: - Dumm fester Header - Ein jQuery-Plugin mit einigen Einschränkungen. - [Feste Tabellenüberschriften] ( cross-browser.com/x/examp
gcores

Ich bin auf viele Lösungen gestoßen, die im Allgemeinen funktionieren, aber keine von ihnen hat Scrolling Div funktioniert. Ich meine, Ihre Tabelle befindet sich in einem scrollbaren Div und Sie möchten trotzdem, dass sich Ihr Tabellenkopf noch in diesem Div befindet. Ich habe das gelöst und teile die Lösung hier .
Yogee

9
Im Jahr 2018 können alle Browser die folgende einfache Lösung verwenden : thead th { position: sticky; top: 0; }. Safari benötigt ein Herstellerpräfix:-webkit-sticky
Daniel Waltrip

1
@ DanielWaltrip Sie sollten dies eine Antwort hinzufügen, damit es an die Spitze gewählt werden kann - alle anderen Antworten sind überflüssig mit Position: klebrig ist heutzutage bessere Unterstützung
Peter Kerr

Antworten:


88

Ich habe eine Weile nach einer Lösung dafür gesucht und festgestellt, dass die meisten Antworten nicht funktionieren oder nicht für meine Situation geeignet sind. Deshalb habe ich mit jQuery eine einfache Lösung geschrieben.

Dies ist die Lösungsübersicht:

  1. Klonen Sie die Tabelle, die einen festen Header haben muss, und legen Sie die geklonte Kopie auf das Original.
  2. Entfernen Sie den Tischkörper vom oberen Tisch.
  3. Entfernen Sie den Tabellenkopf von der unteren Tabelle.
  4. Passen Sie die Spaltenbreiten an. (Wir verfolgen die ursprünglichen Spaltenbreiten)

Unten finden Sie den Code in einer ausführbaren Demo.

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>

Diese Lösung funktioniert in Chrome und IE. Da es auf jQuery basiert, sollte dies auch in anderen von jQuery unterstützten Browsern funktionieren.


4
und wie können wir das Problem lösen, wenn der Inhalt größer als die Breite ist?
Maertz

1
@tetra td {maximale Breite: 30px; } Auf diese Weise kann der Entwickler steuern, wie die Zeilen angezeigt werden.
Lyuben Todorov

Was aber, wenn der Inhalt in einer Header-Zelle länger ist als in td-Zellen? Ich habe das in IE7 versucht und width () bricht alles. IE8 und IE9 funktionieren jedoch
einwandfrei

4
Wenn Sie eine pixelgenaue Ausrichtung der Spalten benötigen, funktioniert dies leider nicht: jsbin.com/elekiq/1 ( Quellcode ). Sie können sehen, dass einige Überschriften nur geringfügig von der Stelle versetzt sind, an der sie sein sollten. Der Effekt ist offensichtlicher, wenn Sie Hintergründe verwenden: jsbin.com/elekiq/2 ( Quellcode ). (Ich habe in die gleiche Richtung gearbeitet, bin in meinem Code darauf gestoßen, habe Ihren gefunden und dachte: "Oh, ich frage mich, ob er das für mich gelöst hat!" Leider nicht .:-)) Browser sind so ein Schmerz, wenn sie das kontrollieren wollen Breiten der Zellen ...
TJ Crowder

Dies scheint beim horizontalen Scrollen nicht zu funktionieren - es erstellt die Kopfzeile, erstreckt sich jedoch (sichtbar) über den scrollbaren Bereich hinaus und scrollt nicht mit dem Inhalt.
Absturz

183

Dies kann in vier Codezeilen sauber gelöst werden.

Wenn Sie sich nur für moderne Browser interessieren, kann ein fester Header durch die Verwendung von CSS-Transformationen viel einfacher erreicht werden. Klingt seltsam, funktioniert aber großartig:

  • HTML und CSS bleiben unverändert.
  • Keine externen JavaScript-Abhängigkeiten.
  • Vier Codezeilen.
  • Funktioniert für alle Konfigurationen (Tabellenlayout: fest usw.).
document.getElementById("wrap").addEventListener("scroll", function(){
   var translate = "translate(0,"+this.scrollTop+"px)";
   this.querySelector("thead").style.transform = translate;
});

Unterstützung für CSS - Transformationen ist weithin verfügbar , außer für den Internet Explorer 8-.

Hier ist das vollständige Beispiel als Referenz:


8
Ich muss sagen, dass dies trotz meines vorherigen Kommentars einer perfekten Lösung, die ich gesehen habe, am nächsten kommt. Auch das horizontale Scrollen ist perfekt (besser als meine eigene Lösung). Hier ist ein Beispiel mit Grenzen (sie können nicht border-collapse) und eine Scrollbar , dass Sticks auf den Tisch anstelle des Behälters: jsfiddle
DoctorDestructo

11
Es hat herausgefunden, dass es funktioniert, aber die Transformation muss auf th / td angewendet werden, nicht auf thead.
Rotschopf

5
@AlexAlexeev, Ihre Lösung ist erstaunlich. Danke dir. Ich habe festgestellt, dass der resultierende feste Header nicht die Grenzlinien enthält, die Spalten unterscheiden. Der Standard-CSS-Stil geht verloren. Selbst wenn ich dies einbeziehe ... $(this).addClass('border')ändert sich der Rest der Tabelle mit Schriftarten, Größe und Farbe, die ich in der Rahmenklasse übergebe. Fügt dem festen Header jedoch keine Zeilen hinzu. Schätzen Sie, alle Eingaben, wie man das behebt
user5249203

5
@ user5249203 Ich weiß, dass Sie vor ein paar Monaten gefragt haben, aber ich hatte das gleiche Problem und es war auf den Zusammenbruch der Grenzen zurückzuführen: siehe dies: stackoverflow.com/questions/33777751/… .
Archz

6
Dies funktioniert in keiner Version von IE oder in Edge. Hier ist eine Version, die auf @ redheads
rob

58

Ich habe gerade ein jQuery-Plugin zusammengestellt, das eine gültige einzelne Tabelle mit gültigem HTML-Code verwendet (muss einen Thead und einen Tbody haben) und eine Tabelle mit festen Kopfzeilen, optionaler fester Fußzeile, die entweder eine geklonte Kopfzeile oder eine beliebige sein kann, ausgeben wird Inhalt, den Sie ausgewählt haben (Paginierung usw.). Wenn Sie größere Monitore nutzen möchten, wird die Größe der Tabelle auch geändert, wenn die Größe des Browsers geändert wird. Eine weitere zusätzliche Funktion ist das seitliche Scrollen, wenn nicht alle Tabellenspalten in die Ansicht passen.

http://fixedheadertable.com/

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

Es ist extrem einfach einzurichten und Sie können Ihre eigenen benutzerdefinierten Stile dafür erstellen. Außerdem werden in allen Browsern abgerundete Ecken verwendet. Denken Sie daran, dass ich es gerade veröffentlicht habe, es ist also technisch immer noch Beta und es gibt nur sehr wenige kleinere Probleme, die ich ausbügele.

Es funktioniert in Internet Explorer 7, Internet Explorer 8, Safari, Firefox und Chrome.


Vielen Dank! Ich füge heute später eine neue Version hinzu, wenn ich von der Arbeit nach Hause komme. Hier ist ein Link zu meinem Blogeintrag mit dem, was ich hinzufüge: fixedheadertable.mmalek.com/2009/10/07/…
Mark

Danke dafür. Ich weiß, dass diese Frage über ein Jahr alt ist, aber selbst wenn die Gefahr besteht, dass sich Schlamm
ansammelt

In Ihrer Demo sind die Breiten in ie6 :-( Tabellenkopf und Körper nicht ausgerichtet.
Cheekysoft

4
Die neueste Version funktioniert nicht in IE6. Ich unterstütze IE6 nicht mehr.
Mark

großartige Arbeit Mark - leider gibt es einige Probleme beim Scrollen der festen Kopfzeile und Spalte auf Mobilgeräten (iPad, Android-Tablet) - wenn ich den Inhalt scrolle, scrollen diese festen Teile nicht - wenn ich aufhöre zu scrollen und einmal auf die Tabelle tippe , die festen Teile "springen" in die richtigen Positionen - gibt es eine einfache Möglichkeit, dies zu beheben?
Okizb

23

Ich habe auch ein Plugin erstellt, das dieses Problem behebt. Mein Projekt - jQuery.floatThead gibt es seit über 4 Jahren und es ist sehr ausgereift.

Es erfordert keine externen Stile und erwartet nicht, dass Ihre Tabelle auf eine bestimmte Weise gestaltet wird. Es unterstützt Internet Explorer9 + und Firefox / Chrome.

Derzeit (2018-05) hat es:

405 Commits und 998 Sterne auf GitHub


Viele (nicht alle) der Antworten hier sind schnelle Hacks, die möglicherweise das Problem einer Person gelöst haben, aber nicht für jeden Tisch funktionieren.

Einige der anderen Plugins sind alt und funktionieren wahrscheinlich hervorragend mit Internet Explorer, werden aber unter Firefox und Chrome nicht funktionieren.


1
Tolles Plugin, unterstützt verschachtelte Tabellen und Offsets.
Mihai Alex

2
Toll. Vielen Dank. Das Plugin funktionierte gut in Firefox 45.2, Chromium 51 und IE 11. Außerdem stört es nicht viele JS- und jQuery-Codes, die auf derselben Seite erstellt wurden.
Aldo Paradiso

Danke dir. Ich freue mich, Ihnen mitteilen zu können, dass das Projekt zu diesem Zeitpunkt alle 4 Monate etwa 1 Fehlerbericht erhält. Ich mache nicht viele bahnbrechende Änderungen. Es ist ziemlich solide und funktioniert.
Mkoryak

20

TL; DR

Wenn Sie auf moderne Browser abzielen und keine extravaganten Styling-Anforderungen haben: http://jsfiddle.net/dPixie/byB9d/3/ ... Obwohl die Big-Four-Version auch ziemlich süß ist, handhabt diese Version die Flüssigkeitsbreite viel besser.

Gute Neuigkeiten alle zusammen!

Mit den Fortschritten von HTML5 und CSS3 ist dies nun zumindest für moderne Browser möglich. Die leicht hackige Implementierung, die ich mir ausgedacht habe, finden Sie hier: http://jsfiddle.net/dPixie/byB9d/3/ . Ich habe es in FX 25, Chrome 31 und IE 10 getestet ...

Relevantes HTML (fügen Sie jedoch einen HTML5-Doctype oben in Ihr Dokument ein):

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>

Aber wie?!

Einfach ausgedrückt, Sie haben einen Tabellenkopf, den Sie visuell ausblenden, indem Sie ihn auf 0 Pixel hoch machen. Dieser enthält auch Divs, die als fester Kopf verwendet werden. Der Container der Tabelle lässt oben genügend Platz, um die absolut positionierte Kopfzeile zu berücksichtigen, und die Tabelle mit den Bildlaufleisten wird wie erwartet angezeigt.

Der obige Code verwendet die positionierte Klasse, um die Tabelle absolut zu positionieren (ich verwende sie in einem Popup-Dialogfeld), aber Sie können sie auch im Ablauf des Dokuments verwenden, indem Sie die positionedKlasse aus dem Container entfernen .

Aber ...

Es ist nicht perfekt. Firefox weigert sich, die Kopfzeile auf 0px zu setzen (zumindest habe ich keinen Weg gefunden), hält sie aber hartnäckig auf mindestens 4px ... Es ist kein großes Problem, aber abhängig von Ihrem Stil wird es Ihre Ränder usw. durcheinander bringen.

Die Tabelle verwendet auch einen Faux-Column-Ansatz, bei dem die Hintergrundfarbe des Containers selbst als Hintergrund für die transparenten Header-Divs verwendet wird.

Zusammenfassung

Alles in allem kann es je nach Ihren Anforderungen zu Stylingproblemen kommen, insbesondere bei Rahmen oder komplizierten Hintergründen. Es kann auch Probleme mit der Berechenbarkeit geben. Ich habe es noch nicht in einer Vielzahl von Browsern überprüft (bitte kommentieren Sie Ihre Erfahrungen, wenn Sie es ausprobieren), aber ich habe so etwas nicht gefunden, daher dachte ich, dass es sich lohnt, es zu veröffentlichen wie auch immer ...


Wenn Sie die Breite des Fensters verkleinern, bis das horizontale Scrollen einsetzt, wird die Kopfzeile nicht horizontal mit dem Körper gescrollt. Verflixt.
dlaliberte

@dlaliberte - Nun, da der Header und die Tabelle tatsächlich zwei verschiedene Elemente sind, können Sie natürlich in die Verrücktheit geraten. In meinem Beispiel ist jedoch kein Überlauf der Tabellenspalten zulässig, und die Überschriften sind normalerweise einfacher zu steuern als der Tabelleninhalt. Das heißt, wenn Sie den Header "überlaufen" lassen, wenn er rechts von der Tabelle hervorsteht und stark kaputt aussieht. Sie können dies beheben, indem Sie eine Mindestbreite für die Tabelle festlegen und sie dazu zwingen, die Seite ebenfalls zu überlaufen ... Aber es ist ein Hack, so dass es niemals perfekt wird ...
Jonas Schubert Erlandsson

1
Es sei darauf hingewiesen, dass dies ein Design erfordert, bei dem ein Tisch mit fester Höhe angegeben werden kann.
Cheekysoft

1
@Cheekysoft - Nein, die Tabelle und der Zeileninhalt können frei fließen. Der Container, in meinem Beispiel das <section>Element, muss nur höhenbeschränkt sein, um einen Überlauf zu erzwingen und das Scrollen anzuzeigen. Jedes Layout, das den Containerüberlauf verursacht, würde funktionieren. Wenn Sie einen Fall finden, in dem dies nicht der Fall ist, veröffentlichen Sie bitte einen Link zu einer Geige.
Jonas Schubert Erlandsson

Der fest codierte padding-topWert bedeutet auch, dass der Text der Tabellenüberschrift, wenn er sich in mehr als einer Zeile befindet, über den Tabellenzellen angezeigt wird. Schade, denn das funktioniert die meiste Zeit wie ein Zauber. Wirklich schöne Trick mit der divin der thbekommen um die Spalte Sizing Problem den meisten anderen Lösungen haben.
Bernhard Hofmann

19

Alle Versuche, dies von außerhalb der CSS-Spezifikation zu lösen, sind blasse Schatten dessen, was wir wirklich wollen: Lieferung an das implizite Versprechen von THEAD.

Dieses Problem mit eingefrorenen Headern für eine Tabelle ist seit langem eine offene Wunde in HTML / CSS.

In einer perfekten Welt gäbe es eine reine CSS-Lösung für dieses Problem. Leider scheint es keinen guten zu geben.

Relevante Standarddiskussionen zu diesem Thema sind:

UPDATE : Firefox wird position:stickyin Version 32 ausgeliefert. Jeder gewinnt!


Es wäre großartig, wenn die Säulen auf die gleiche Weise gepuffert wären
Csaba Toth,

4
Re. Firefox und Position: Sticky, funktioniert nicht für Tabellenüberschriften: bugzilla.mozilla.org/show_bug.cgi?id=925259#c8 ... Der Patch für diesen Fehler besagt ausdrücklich: "Wir unterstützen derzeit keine relative Positionierung von inneren Tabellenelementen, daher schließen wir sie auch von der klebrigen Positionierung aus. "
Jonas Schubert Erlandsson

2
Dies funktioniert jetzt in allen Browsern : thead th { position: sticky; top: 0; }. Können wir diese Antwort aktualisieren, um dies klar auszudrücken?
Daniel Waltrip

1
@ DanielWaltrip alle Browser? stackoverflow.com/a/37646284/3640407 Es gibt immer noch mehr MSIEs als Edges
edc65

Gutes Argument. Es wird für 86% der globalen Webnutzer unterstützt, laut caniuse.com/#search=position%3Asticky
Daniel Waltrip

14

Hier ist ein jQuery-Plugin für feste Tabellenüberschriften. Dadurch kann die gesamte Seite gescrollt werden, wodurch die Kopfzeile eingefroren wird, wenn sie oben angekommen ist. Es funktioniert gut mit Twitter Bootstrap- Tabellen.

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

Es wird nicht nur der Tabelleninhalt gescrollt. Schauen Sie sich dazu andere Tools an, als eine dieser anderen Antworten. Sie entscheiden, was am besten zu Ihrem Fall passt.


1
Schade - der Beispiellink ist tot. "Ups! Denne siden ble ikke funnet ..." Ich wünschte, der Code wäre hier eingefügt.
JosephK

Ja ... Entschuldigung. Link entfernt. Das Projekt wird nicht mehr gepflegt
oma

Keine Sorge - ich habe mehrere dieser vorgefertigten angeblichen Lösungen ausprobiert - keine funktionierte mit einer Tabelle mit flexibler Breite, die die Bildschirmbreite überschritt. Am Ende habe ich meine eigene Lösung geschrieben.
JosephK

9

Die meisten der hier veröffentlichten Lösungen erfordern jQuery. Wenn Sie nach einer Framework-unabhängigen Lösung suchen, versuchen Sie es mit Grid: http://www.matts411.com/post/grid/

Es wird auf Github hier gehostet: https://github.com/mmurph211/Grid

Es unterstützt nicht nur feste Kopf- und Fußzeilen, sondern unter anderem auch feste linke Spalten und Fußzeilen.


Das ist wirklich ordentlich, wenn es Ihren Bedürfnissen entspricht. Ich habe heute gerade damit gespielt. Leider handelt es sich eher um ein rechteckiges Raster (wie der Name schon sagt) und nicht um eine echte Tabelle, deren Zeilenhöhe durch den Inhalt angepasst wird. Und das Stylen einzelner Reihen schien schwierig. Ich konnte keinen Tisch mit Zebrastreifen erstellen, bemühte mich aber nicht sehr, da meine Bedürfnisse tatsächlich komplexer waren. Wie auch immer, gute Arbeit.
mplwork

1
Hey, ich kenne dich! Wir schienen sehr ähnliche Scheiße geschrieben zu haben ( github.com/mkoryak/floatThead ) - Misha
mkoryak

9

Die CSS-Eigenschaft position: stickywird in den meisten modernen Browsern hervorragend unterstützt (ich hatte Probleme mit Edge, siehe unten).

Auf diese Weise können wir das Problem fester Header ganz einfach lösen:

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

Safari benötigt ein Herstellerpräfix : -webkit-sticky.

Für Firefox musste ich min-height: 0eines der übergeordneten Elemente hinzufügen . Ich vergesse genau, warum das nötig war.

Leider scheint die Microsoft Edge-Implementierung nur teilweise zu funktionieren. Zumindest hatte ich bei meinen Tests einige flackernde und falsch ausgerichtete Tabellenzellen. Der Tisch war noch verwendbar, hatte aber erhebliche ästhetische Probleme.


Unter Verwendung position: sticky;der Tabelle in einem div, der hat overflow: scroll;, overflow-x: scroll;oder overflow-y: scroll;. scheint die beste und einfachste Lösung für feste Tabellenüberschriften und -spalten in modernen Browsern zu sein. Diese Antwort muss nach oben gewählt werden.
Aberrant

Es ist einfach, aber effektiv. Es ist das, wonach ich suche. Vielen Dank.
Catbuilts

6

Eine verfeinerte reine CSS-Bildlauftabelle

Allen reinen CSS-Lösungen, die ich bisher gesehen habe - so klug sie auch sein mögen - fehlt ein gewisses Maß an Politur oder sie funktionieren in manchen Situationen einfach nicht richtig. Also habe ich beschlossen, meine eigenen ...

Eigenschaften:

  • Es ist reines CSS, daher ist keine jQuery erforderlich (oder überhaupt kein JavaScript-Code).
  • Sie können die Tabellenbreite auf einen Prozentwert (auch bekannt als "Fluid") oder einen festen Wert festlegen oder den Inhalt seine Breite bestimmen lassen (auch bekannt als "Auto").
  • Spaltenbreiten können auch flüssig, fest oder automatisch sein.
  • Spalten werden aufgrund des horizontalen Bildlaufs niemals falsch mit Überschriften ausgerichtet (ein Problem, das bei jeder anderen CSS-basierten Lösung auftritt, die keine festen Breiten erfordert).
  • Kompatibel mit allen gängigen Desktop-Browsern, einschließlich Internet Explorer bis Version 8
  • Sauberes, poliertes Aussehen; keine schlampig aussehenden 1-Pixel-Lücken oder falsch ausgerichteten Ränder; sieht in allen Browsern gleich aus

Hier sind ein paar Geigen, die die Optionen für Flüssigkeit und automatische Breite zeigen:

  • Flüssigkeitsbreite und -höhe (passt sich der Bildschirmgröße an): jsFiddle (Beachten Sie, dass die Bildlaufleiste in dieser Konfiguration nur bei Bedarf angezeigt wird, sodass Sie den Rahmen möglicherweise verkleinern müssen, um ihn anzuzeigen. )

  • Automatische Breite, feste Höhe (einfacher in andere Inhalte zu integrieren): jsFiddle

Die Konfiguration "Automatische Breite, feste Höhe" hat wahrscheinlich mehr Anwendungsfälle, daher werde ich den folgenden Code veröffentlichen.

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

Die Methode, mit der ich die Kopfzeile eingefroren habe, ähnelt der von d-Pixie. Eine Erklärung finden Sie in seinem Beitrag. Es gab eine Reihe von Fehlern und Einschränkungen bei dieser Technik, die nur mit Haufen zusätzlichen CSS und ein oder zwei zusätzlichen Div-Containern behoben werden konnten.


Diese Antwort wird viel zu wenig geschätzt! Ich habe tagelang versucht, andere Lösungen für meinen besonders nervigen Fall zu finden. Jeder einzelne von ihnen konnte nicht auf die eine oder andere Weise ausgerichtet bleiben. Das hat es endlich geschafft! Scheint zunächst zu kompliziert, aber sobald Sie den Dreh raus haben, ist es großartig. Sie können eine Menge Dinge entfernen, die Sie am Ende nicht benötigen, wenn Sie keine Flüssigkeitsbreite usw. verwenden.
Justin Sane

1
@ JustinSane Schön, dass es dir gefällt! Ich würde vermuten, dass der Mangel an Wertschätzung auf die Tatsache zurückzuführen ist, dass die Seite mit Maximilian Hils 'erstaunlicher Lösung geteilt wird . Wenn Sie nicht dagegen sind, ein kleines bisschen JS zu verwenden, sollten Sie es auf jeden Fall ausprobieren.
DoctorDestructo

Verdammt, das ist in der Tat eine fast perfekte Lösung. Ich habe sowieso jQuery verwendet und versucht, es damit zum Laufen zu bringen, bevor ich deins gefunden habe (über deinen Kommentar zu einer anderen Frage). Ich habe nicht an einen Scroll-Listener gedacht und übersetzt ... Nun, sie sagen, es braucht ein Genie, um einfache Lösungen zu finden ..;) Ich habe das Projekt beendet und es funktioniert perfekt ohne js, aber ich werde das beibehalten Geist für die Zukunft. Trotzdem, Hut ab vor dir, dass du großartig bist!
Justin Sane

Ein kleines Problem, aber wenn Sie andere Systemfarben verwenden, können Sie sehen, dass die Textfarbe nur für die Überschriften festgelegt wurde, der Tabellenhintergrund jedoch eine explizite Hintergrundfarbe hat. Ich habe gelben Text auf weißem und grauem Hintergrund für diese Tabelle.
Matt Arnold

1
@ MattArnold behoben. Danke für den Tipp!
DoctorDestructo

5

Ein einfaches jQuery-Plugin

Dies ist eine Variation von Mahes 'Lösung. Sie können es so nennen$('table#foo').scrollableTable();

Die Idee ist:

  • Teilen Sie die thead und tbodyin separate tableElemente
  • Passen Sie die Zellenbreiten wieder an
  • Wickeln Sie die zweite table in adiv.scrollable
  • Verwenden Sie CSS, um zu machen div.scrollable tatsächlich zu scrollen

Das CSS könnte sein:

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

Vorsichtsmaßnahmen

  • Durch das Aufteilen dieser Tabellen wird das Markup offensichtlich weniger semantisch. Ich bin mir nicht sicher, welche Auswirkungen dies auf die Zugänglichkeit hat.
  • Dieses Plugin behandelt keine Fußzeilen, mehrere Kopfzeilen usw.
  • Ich habe es nur in Chrome Version 20 getestet.

Das heißt, es funktioniert für meine Zwecke und Sie können es nehmen und ändern.

Hier ist das Plugin:

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

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

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

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

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

1
Schönes Skript, dieses hat in meiner Umgebung am besten funktioniert. Ich habe Ihr Skript mit Unterstützung für feste Fußzeilen erweitert. Überprüfen Sie meinen Beitrag unten.
Gitaarik

4

:) :)

Nicht so sauber, aber reine HTML / CSS-Lösung.

table {
    overflow-x:scroll;
}

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

Aktualisiert für IE8 + JSFiddle-Beispiel


2
Gute Lösung, nur um zu erwähnen, dass diese Zellen schweben und daher je nach Inhalt unterschiedliche Höhen haben können. Es ist sichtbar, wenn Sie ihnen Grenzen setzen: jsfiddle.net/ZdeEH/15
Stano

3

Unterstützung für feste Fußzeile

Ich habe Nathans Funktion erweitert, um auch eine feste Fußzeile und maximale Höhe zu unterstützen. Außerdem legt die Funktion das CSS selbst fest, und Sie müssen nur eine Breite unterstützen.

Verwendung:

Feste Höhe:

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

Maximale Höhe (wenn der Browser die CSS-Option 'max-height' unterstützt):

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

Skript:

jQuery.fn.scrollableTable = function(options) {

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

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

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

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

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

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

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

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

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

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

3

Irgendwie habe ich Position:Stickygut an meinem Fall gearbeitet:

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

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

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


1
Dies ist die sauberste Lösung, die ich bisher gesehen habe. caniuse zeigt, dass ab dem 02.05.2020 eine nicht festgelegte Position: sticky eine weltweite Unterstützung von 90,06% genießt. Diese Lösung funktioniert also in allen modernen Browsern.
AlienKevin

2

Zwei Divs, einer für Header, einer für Daten. Machen Sie das Daten-Div scrollbar und verwenden Sie JavaScript, um die Breite der Spalten in der Kopfzeile so einzustellen, dass sie mit den Breiten in den Daten übereinstimmt. Ich denke, die Breite der Datenspalten muss fest und nicht dynamisch sein.


3
Wenn Sie sich für die Barrierefreiheit interessieren, ist dies ein Fehler.
Epascarello

1
In Bezug auf die Zugänglichkeit können wir möglicherweise die Verwendung von Divs durch das Styling von <thead> und <tbody> ersetzen.
Cheekysoft

1

Mir ist klar, dass die Frage JavaScript zulässt, aber hier ist eine reine CSS-Lösung, die ich ausgearbeitet habe und die es auch ermöglicht, die Tabelle horizontal zu erweitern. Es wurde mit Internet Explorer 10 und den neuesten Chrome- und Firefox-Browsern getestet. Ein Link zu jsFiddle befindet sich unten.

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

Und das CSS:

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

tbody{
    background-color: #ddf;
}

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

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

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

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

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

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

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


1

Für diejenigen, die die nette Lösung von Maximilian Hils ausprobiert haben und es nicht geschafft haben, sie mit Internet Explorer zum Laufen zu bringen, hatte ich das gleiche Problem (Internet Explorer 11) und fand heraus, was das Problem war.

In Internet Explorer 11 funktioniert die Stilumwandlung (zumindest mit Übersetzen) nicht <THEAD>. Ich habe dies gelöst, indem ich stattdessen den Stil auf alle <TH>in einer Schleife angewendet habe. Das hat funktioniert. Mein JavaScript-Code sieht folgendermaßen aus:

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

In meinem Fall war die Tabelle eine GridView in ASP.NET. Zuerst dachte ich, es sei, weil es keine hatte<THEAD> , aber selbst als ich es zwang, eine zu haben, funktionierte es nicht. Dann habe ich herausgefunden, was ich oben geschrieben habe.

Es ist eine sehr schöne und einfache Lösung. Auf Chrome ist es perfekt, auf Firefox etwas ruckelig und auf Internet Explorer noch ruckeliger. Aber alles in allem eine gute Lösung.


0

Ich wünschte, ich hätte früher die Lösung von @ Mark gefunden, aber ich habe meine eigene geschrieben, bevor ich diese SO-Frage sah ...

Mine ist ein sehr leichtes jQuery-Plugin, das feste Kopf- und Fußzeilen, Spaltenüberspannungen (Colspan), Größenänderung, horizontales Scrollen und eine optionale Anzahl von Zeilen unterstützt, die angezeigt werden sollen, bevor das Scrollen beginnt.

jQuery.scrollTableBody (GitHub)

Solange Sie mit dem richtigen eine Tabelle <thead>, <tbody>und (optional) <tfoot>, alles , was Sie tun müssen, ist dies:

$('table').scrollTableBody();

0

Ich habe diese Problemumgehung gefunden - Kopfzeile in einer Tabelle über Tabelle mit Daten verschieben:

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


funktioniert für kleine Tabellen, aber wenn Sie horizontal scrollen, funktioniert diese Lösung nicht.
Crh225

Es funktioniert auch nicht richtig, da die Tabellenspalten nicht ausgerichtet werden. Hier erzwingen Sie Breite für td, aber wir dürfen nicht tun ...
Ziggler

0

Wenn Sie das jQuery-Plugin von StickyTableHeaders auf die Tabelle anwenden, bleiben die Spaltenüberschriften beim Scrollen am oberen Rand des Ansichtsfensters erhalten.

Beispiel:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        // Run initializer
        base.init();
    }

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

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


0

Ich mag die Antwort von Maximillian Hils, aber ich hatte einige Probleme:

  1. Die Transformation funktioniert in Edge oder IE nur, wenn Sie sie auf th anwenden
  2. Der Header flackert beim Scrollen in Edge und IE
  3. Meine Tabelle wird mit Ajax geladen, daher wollte ich eher an das Fenster-Scroll-Ereignis als an das Scroll-Ereignis des Wrappers anhängen

Um das Flackern zu beseitigen, warte ich mit einer Zeitüberschreitung, bis der Benutzer den Bildlauf beendet hat, und wende dann die Transformation an, sodass die Kopfzeile beim Bildlauf nicht sichtbar ist.

Ich habe dies auch mit jQuery geschrieben. Ein Vorteil davon ist, dass jQuery Herstellerpräfixe für Sie verarbeiten sollte

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

Die Tabelle wird mit der Klasse in ein Div eingeschlossen table-container-fixed.

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

Ich habe den Rahmenkollaps so eingestellt, dass er getrennt wird, da sonst während der Übersetzung Rahmen verloren gehen, und ich entferne den Rand in der Tabelle, um zu verhindern, dass Inhalte direkt über der Zelle angezeigt werden, in der sich der Rahmen während des Bildlaufs befand.

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

Ich mache den thHintergrund weiß, um die Zellen darunter zu bedecken, und füge einen Rand hinzu, der dem Tabellenrand entspricht - der mit Bootstrap gestaltet und aus der Ansicht gescrollt wird.

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

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

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

0

Verwenden Sie die neueste Version von jQuery und fügen Sie den folgenden JavaScript-Code hinzu.

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

1
Das scheint nicht zu funktionieren. Vielleicht könnten Sie klarstellen, was wir tun sollen?
Chris

1
Was für ein Div? Wir sprechen hier über Tische
Isapir

0

Dies ist keine exakte Lösung für die feste Kopfzeile, aber ich habe eine ziemlich ausgeklügelte Methode entwickelt, um die Kopfzeile in der langen Tabelle zu wiederholen und dennoch die Sortierfähigkeit beizubehalten.

Diese nette kleine Option erfordert das jQuery- tablesorterPlugin . So funktioniert das:

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>

Offensichtlich hat meine Tabelle viel mehr Zeilen als diese. 193 um genau zu sein, aber Sie können sehen, wo sich die Kopfzeile wiederholt. Die sich wiederholende Kopfzeile wird durch diese Funktion eingerichtet:

jQuery

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

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

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

0

Viele Leute scheinen nach dieser Antwort zu suchen. Ich fand es in einer Antwort auf eine andere Frage begraben: Synchronisieren der Spaltenbreite zwischen Tabellen in zwei verschiedenen Frames usw.

Von den Dutzenden von Methoden, die ich ausprobiert habe, ist dies die einzige Methode, die ich gefunden habe und die zuverlässig funktioniert, damit Sie eine scrollende untere Tabelle mit derselben Headertabelle haben können.

Hier ist, wie ich es gemacht habe. Zuerst habe ich die obige jsfiddle verbessert, um diese Funktion zu erstellen, die sowohl für tdals auch für th(falls dies andere auslöst, die für die Gestaltung thihrer Kopfzeilen verwendet werden) funktioniert .

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

Als Nächstes müssen Sie zwei Tabellen erstellen. HINWEIS: Die Kopfzeilentabelle sollte ein zusätzliches TDElement enthalten, um in der oberen Tabelle Platz für die Bildlaufleiste zu lassen.

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

Dann mach so etwas wie:

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

Dies ist die einzige Lösung, die ich bei Stack Overflow gefunden habe und die sich aus vielen ähnlichen Fragen ergibt, die in allen meinen Fällen gestellt wurden.

Zum Beispiel habe ich das jQuery Stickytables-Plugin ausprobiert, das nicht mit Durandal funktioniert, und das Google Code-Projekt hier https://code.google.com/p/js-scroll-table-header/issues/detail?id=2

Andere Lösungen, bei denen die Tabellen geklont werden, eine schlechte Leistung aufweisen oder saugen und nicht in allen Fällen funktionieren.

Diese übermäßig komplexen Lösungen sind nicht erforderlich. Erstellen Sie einfach zwei Tabellen wie in den folgenden Beispielen und rufen Sie die hier beschriebene Funktion setHeaderTableWidth auf, und schon sind Sie fertig .

Wenn dies bei Ihnen nicht funktioniert, haben Sie wahrscheinlich mit Ihrer CSS-Box-Sizing-Eigenschaft gespielt und müssen sie korrekt einstellen. Es ist leicht, Ihren CSS-Inhalt versehentlich zu vermasseln. Es gibt viele Dinge, die schief gehen können. Seien Sie sich dessen einfach bewusst. Dieser Ansatz funktioniert bei mir .


0

Hier ist eine Lösung, mit der wir letztendlich gearbeitet haben (um einige Randfälle und ältere Versionen von Internet Explorer zu behandeln, haben wir schließlich auch die Titelleiste beim Scrollen ausgeblendet und sie dann wieder eingeblendet, wenn der Bildlauf endet, jedoch in Firefox- und WebKit-Browsern Diese Lösung funktioniert einfach . Sie setzt einen Grenzkollaps voraus: Kollaps.

Der Schlüssel zu dieser Lösung ist , dass , sobald Sie gelten border-collapse , CSS - Transformationen auf dem Kopf arbeiten, so ist es nur eine Frage der Scroll - Ereignisse abfangen und die korrekte Transformation zu setzen. Sie müssen nichts duplizieren. Wenn dieses Verhalten nicht ordnungsgemäß im Browser implementiert wird, kann man sich kaum eine leichtere Lösung vorstellen.

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

Es ist als einfaches jQuery-Plugin implementiert. Sie machen Ihren Thead einfach mit einem Anruf wie $ ('Thead'). Sticky () klebrig, und sie hängen herum. Es funktioniert für mehrere Tabellen auf einer Seite und Kopfabschnitte auf halber Höhe großer Tabellen.

$.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();

Gute Lösung, aber wie fügen Sie Spaltenränder zwischen Spalten ein (beide in fester Überschrift, ausgerichtet an den td-Daten)?
user5249203

Ich bin mir nicht sicher, ob ich dein Problem verstehe. Der Randkollaps hindert Sie nicht daran, Rahmen, Ränder usw. zu verwenden, sondern entfernt lediglich die früheren Voodoo-Tabellenmetriken.
Podperson

1
In border: 2px solid red;zu th, blättern, und Sie werden das Problem sehen. Ich habe mir diese grundlegendere Lösung selbst ausgedacht
calandoa

Fügen Sie td den gleichen dimensionierten Rand hinzu, und es gibt kein Problem. Ich verstehe deinen Standpunkt nicht. Ihre Version ist viel sauberer und verwendet jQuery nicht, daher würde ich heute definitiv so etwas machen. (Obwohl ich ehrlich gesagt nicht glaube, dass ich heute überhaupt einen Tisch benutzen würde.)
Podperson

0

Hier ist eine verbesserte Antwort auf die von Maximilian Hils .

Dieser funktioniert in Internet Explorer 11 ohne Flackern:

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

0

Ich habe ein einfaches, leichtes jQuery-Plug-In entwickelt, mit dem eine gut formatierte HTML-Tabelle in eine scrollbare Tabelle mit festem Tabellenkopf und Spalten konvertiert werden kann.

Das Plugin funktioniert gut, um die Pixel-zu-Pixel-Positionierung des festen Abschnitts mit dem scrollbaren Abschnitt abzugleichen. Darüber hinaus können Sie auch die Anzahl der Spalten einfrieren, die beim horizontalen Scrollen immer angezeigt werden.

Demo & Dokumentation: http://meetselva.github.io/fixed-table-rows-cols/

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

Nachfolgend finden Sie die Verwendung für eine einfache Tabelle mit einem festen Header.

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

Was ist "eine gute HTML-Tabelle" ?
Peter Mortensen

@PeterMortensen Sollte "gut formatiertes HTML" sein. Bearbeitet, danke.
Selvakumar Arumugam

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

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


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

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

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

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

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

0

Zusätzlich zur Antwort von @Daniel Waltrip. Die Tabelle muss mit div eingeschlossen position: relativewerden, um mit arbeiten zu können position:sticky. Deshalb möchte ich hier meinen Beispielcode veröffentlichen.

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>

Demo

Geben Sie hier die Bildbeschreibung ein

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.