Table HTML avec des en-têtes fixes?

y a-t-il une technique de cross-browser CSS/JavaScript pour afficher une longue table HTML telle que les en-têtes de colonne restent fixes sur l'écran et ne font pas défiler avec le corps de la table. Pensez à L'effet" Freeze panes " dans Microsoft Excel.

je veux être en mesure de faire défiler le contenu de la table, mais pour toujours être en mesure de voir les en-têtes de colonne au sommet.

211
demandé sur Termininja 2009-03-23 15:11:12

27 réponses

je cherchais une solution pour cela depuis un certain temps et j'ai trouvé que la plupart des réponses ne fonctionnent pas ou ne conviennent pas à ma situation, donc j'ai écrit une solution simple avec jQuery.

voici le contour de la solution:

  1. clonez la table qui doit avoir un en-tête fixe, et placez le copie clonée sur le dessus de l'original.
  2. retirer le corps de la table supérieure.
  3. Supprimer l'en-tête de la table de bas de tableau.
  4. régler la largeur de la colonne. (Nous gardons la trace de l'origine des largeurs de colonne)

ci-dessous est le code dans une démo exécutable.

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>

cette solution fonctionne en Chrome et IE. Puisqu'il est basé sur jQuery, cela devrait fonctionner dans d'autres jQuery navigateurs pris en charge.

82
répondu Mahes 2018-08-21 14:43:02

cela peut être résolu proprement en quatre lignes de code.

si vous ne vous souciez que des navigateurs modernes, un en-tête fixe peut être obtenu beaucoup plus facile en utilisant CSS transforms. Des sons étranges, mais fonctionne très bien:

  • HTML et CSS rester comme elle est.
  • pas de dépendances externes JS.
  • 4 lignes de code.
  • fonctionne pour toutes les configurations (table-layout: fixe etc).
document.getElementById("wrap").addEventListener("scroll", function(){
   var translate = "translate(0,"+this.scrollTop+"px)";
   this.querySelector("thead").style.transform = translate;
});

prise en charge pour les transformées CSS est largement disponible sauf pour IE8-. Voici l'exemple complet pour référence:

document.getElementById("wrap").addEventListener("scroll",function(){
   var translate = "translate(0,"+this.scrollTop+"px)";
   this.querySelector("thead").style.transform = translate;
});
/* your existing container */
#wrap {
    overflow: auto;
    height: 400px;
}

/* css for demo */
td {
    background-color: green;
    width: 200px;
    height: 100px;
}
<div id="wrap">
    <table>
        <thead>
            <tr>
                <th>Foo</th>
                <th>Bar</th>
            </tr>
        </thead>
        <tbody>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
        </tbody>
    </table>
</div>
159
répondu Maximilian Hils 2018-03-14 15:38:06

je viens de terminer la mise en place d'un plugin jQuery qui va prendre une table simple valide en utilisant un HTML valide (doit avoir un thead et un tbody) et va sortir une table qui a des en-têtes fixes, un pied de page fixe optionnel qui peut être soit un en-tête cloné ou n'importe quel contenu que vous avez choisi (pagination, etc.). Si vous souhaitez profiter de plus grands moniteurs, il sera également redimensionner la table lorsque le navigateur est redimensionné. Une autre fonctionnalité ajoutée est d'être en mesure de faire défiler le côté si les colonnes de la table ne peuvent pas toutes s'adapter etant.

http://fixedheadertable.com /

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

Il est extrêmement facile d'installation et vous pouvez créer vos propres styles personnalisés. Il utilise également des coins arrondis dans tous les navigateurs. Gardez à l'esprit que je viens de le sortir, donc c'est toujours techniquement bêta et il y a très peu de problèmes mineurs que je suis en train de régler.

il fonctionne dans Internet Explorer 7, Internet Explorer 8, Safari, Firefox et Chrome.

57
répondu Mark 2012-09-12 15:24:29

j'ai aussi créé un plugin qui aborde ce problème. Mon projet - jQuery.floatThead a été autour depuis plus d'un an maintenant et est très mature.

il ne nécessite pas de styles externes et ne s'attend pas à ce que votre table soit coiffée d'une manière particulière. Il prend en charge IE8+ et FF/Chrome.

actuellement (5/2018) il a:

405 s'engage et 998 étoiles sur github


plusieurs (pas toutes) des réponses ici sont des piratages rapides qui peuvent avoir résolu le problème une personne avait mais ne fonctionnera pas pour chaque table.

certains des autres plugins sont vieux et fonctionnent probablement très bien avec IE mais vont casser sur FF et chrome.

22
répondu mkoryak 2018-04-23 18:58:53

TL; DR

si vous ciblez les navigateurs modernes et n'avez pas de besoins extravagants de style: http://jsfiddle.net/dPixie/byB9d/3 / ... Bien que la big four version est assez douce ainsi que cette version gère la largeur du fluide beaucoup mieux.

bonne nouvelle à tous!

avec les avancées de HTML5 et CSS3 c'est maintenant possible, au moins pour les navigateurs modernes. Le légèrement hackish la mise en œuvre que j'ai trouvée peut être trouvée ici: http://jsfiddle.net/dPixie/byB9d/3 / . Je l'ai testé en FX 25, Chrome 31 et IE 10 ...

HTML pertinent (insérez un doctype HTML5 en haut de votre document):

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

avec ce CSS:

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

mais comment?!

simplement mis Vous avez un en-tête de table, que vous cachez visuellement en le faisant 0px de haut, que aussi contient des divs utilisés comme en-tête fixe. Le container de la table laisse assez d'espace au dessus pour permettre l'en-tête absolument positionné, et la table avec des barres de défilement apparaissent comme vous l'attendez.

le code ci-dessus utilise la classe positionnée pour positionner absolument la table (je l'utilise dans une boîte de dialogue popup style) mais vous pouvez l'utiliser dans le flux du document ainsi en enlevant la classe positioned du conteneur.

mais ...

ce n'est pas parfait. Firefox refuse de faire la ligne d'en-tête 0px (au moins je n'ai pas trouvé le moyen) mais s'obstine à la garder au minimum 4px ... Ce n'est pas un énorme problème, mais en fonction de votre style qu'il mess avec vos frontières, etc.

le tableau utilise également une approche de colonne de faux où la couleur de fond du conteneur lui-même est utilisé comme arrière-plan pour les divs d'en-tête, qui sont transparents.

résumé

dans l'ensemble, il peut y avoir des problèmes de style en fonction de vos exigences, en particulier les bordures ou les fonds compliqués. Il pourrait également y avoir des problèmes avec le computabilité, Je n'ai pas vérifié dans une grande variété de navigateurs encore (commentaires s'il vous plaît avec vos expériences si vous l'essayez), mais je n'ai pas trouvé quelque chose comme ça donc j'ai pensé qu'il valait la peine de poster de toute façon ...

20
répondu Jonas Schubert Erlandsson 2013-11-18 09:37:30

toutes les tentatives pour résoudre ce problème à l'extérieur de la spécification CSS sont des ombres pâles de ce que nous voulons vraiment: la livraison sur la promesse implicite de THEAD.

ce numéro de headers-for-a-table gelé est une blessure ouverte dans HTML/CSS depuis longtemps.

dans un monde parfait, il y aurait une solution pure-css pour ce problème. Malheureusement, il ne semble pas être une bonne idée en place.

normes pertinentes-discussions sur ce sujet comprend:

mise à JOUR : Firefox livré position:collant dans la version 32. Tout le monde y gagne!

19
répondu djsadinoff 2014-09-03 04:56:10

voici un plugin jQuery pour l'en-tête de table fixe. Il permet à toute la page de faire défiler, gelant l'en-tête quand il atteint le haut. Il fonctionne bien avec twitter bootstrap tables.

dépôt Github: https://github.com/oma/table-fixed-header

Il ne pas défiler uniquement du contenu de la table. Cherchez d'autres outils pour cela, comme l'une de ces autres réponses. Vous décidez ce qui convient le mieux à votre cas.

14
répondu oma 2017-03-24 21:52:15

la plupart des solutions affichées ici nécessitent jQuery. Si vous êtes à la recherche d'une solution de cadre indépendant try Grid: http://www.matts411.com/post/grid/

il est hébergé sur Github ici: https://github.com/mmurph211/Grid

ne supporte pas seulement des en-têtes fixes, il supporte aussi des colonnes et des pieds de page fixes, entre autres choses.

9
répondu Matt 2012-11-27 18:37:58

Plus Raffiné Pur CSS Défilement de la Table

toutes les solutions CSS pures que j'ai vu jusqu'à présent-- aussi intelligentes soient-elles-- manquent d'un certain niveau de Polonais, ou tout simplement ne fonctionnent pas bien dans certaines situations. Donc, j'ai décidé de créer mon propre...

Dispose:

  • c'est du pur CSS, donc aucun jQuery n'est requis (ou aucun javascript du tout, pour que matière)
  • vous pouvez régler la largeur de la table à un pour cent (un.k.un. "fluide") ou une valeur fixe, ou laisser le contenu de déterminer sa largeur (un.k.un. "auto")
  • La largeur de la colonne
  • peut aussi être fluide, fixe ou automatique.
  • Les colonnes
  • ne seront jamais mal alignées avec les en-têtes en raison du défilement horizontal (un problème qui se produit dans toutes les autres solutions basées sur CSS que j'ai vu qui ne nécessite pas de largeurs fixes).
  • compatible avec tous les navigateurs de bureau populaires, y compris Internet Explorer retour à la version 8
  • apparence propre et polie; pas d'écarts de 1 pixel ou de bordures mal alignées; ressemble au même dans tous les navigateurs

voici quelques fiddles qui montrent les options de fluide et de largeur automatique:

  • Fluid Width and Height (adapts to screen size): jsFiddle (notez que le scrollbar n'apparaît qu'en cas de besoin ) dans cette configuration, donc vous pouvez avoir à rétrécir le cadre pour le voir)

  • auto Width, Fixed Height (plus facile à intégrer avec d'autres contenus): jsFiddle

la largeur automatique, la configuration de hauteur fixe a probablement plus de cas d'utilisation, donc je vais poster le code ci-dessous.

/*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;
}
.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 2 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]-->

la méthode que j'ai utilisée pour geler la ligne d'en-tête est similaire à celle de D-Pixie, donc référez-vous à son post pour une explication. Il y avait un tas de bugs et de limites avec cette technique qui ne pouvaient être corrigés qu'avec des tas de CSS supplémentaires et un ou deux conteneurs div supplémentaires.

6
répondu DoctorDestructo 2018-03-15 12:59:04

un simple plugin jQuery

c'est une variante de la solution de Mahes. Vous pouvez l'appeler comme $('table#foo').scrollableTable();

l'idée est:

  • séparer les thead et tbody en table éléments
  • faire correspondre leurs largeurs de cellules à nouveau
  • envelopper la seconde table dans un div.scrollable
  • utiliser CSS pour faire div.scrollable fait défiler

Le CSS pourrait être:

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

mises en garde

  • évidemment, la division de ces tables rend le markup moins sémantique. Je ne suis pas sûr de l'effet que cela a sur l'accessibilité.
  • ce plugin ne traite pas des pieds de page, des en-têtes multiples, etc.
  • Je ne l'ai testé que dans la version 20 de Chrome.

cela dit, il fonctionne pour mes besoins, et vous êtes libre de prendre et de le modifier.

voici le 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);
};
5
répondu Nathan Long 2012-07-05 15:23:45

:)

Pas-si-propre, mais du pur HTML/CSS solution.

table {
    overflow-x:scroll;
}

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

mise à jour pour IE8+ exemple de JSFiddle

4
répondu Anton Matyulkov 2013-07-19 19:40:24

Support pour pied de page fixe

j'ai étendu la fonction de Nathan pour soutenir également un pied de page fixe et la hauteur maximale. En outre, la fonction définira le css lui-même, vous n'avez qu'à supporter une largeur.

Utilisation:

hauteur fixe:

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

hauteur maximale (si le navigateur supporte l'option css 'hauteur maximale'):

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

Script:

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

    // grap 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
répondu gitaarik 2012-09-27 15:34:37

deux divs, un pour header, un pour data. Faites le DIV de données scrollable, et utilisez JavaScript pour définir la largeur des colonnes dans l'en-tête pour être le même que les largeurs dans les données. Je pense que les largeurs des colonnes de données doivent être fixées plutôt que dynamiques.

2
répondu cjk 2010-12-20 18:57:13

je me rends compte que la question permet JavaScript, mais voici une solution CSS pure que j'ai travaillé qui permet également à la table d'étendre horizontalement. Testé avec les navigateurs IE10 et les derniers Chrome et Firefox. Un lien vers jsFiddle se trouve en bas.

the 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 it's 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>

et la 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
répondu bzuillsmith 2013-06-18 18:00:28

pour ceux qui ont essayé la solution de nice donnée par Maximilian Hils, et n'ont pas réussi à le faire fonctionner avec Internet Explorer, j'ai eu le même problème (IE 11) et trouvé ce qui était le problème.

dans IE 11 le style transform (au moins avec translate) ne fonctionne pas sur <THEAD> . J'ai résolu cela en appliquant le style à tous les <TH> dans une boucle. Qui ont travaillé. Mon javascript ressemble à ceci

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

dans mon cas la table était un GridView ASP.NET. J'ai d'abord pensé que c'était parce qu'il n'avait pas de <THEAD> , mais même quand je l'ai forcé à en avoir un, il n'a pas fonctionné. Puis j'ai découvert ce que j'ai écrit plus haut.

c'est une solution très simple et agréable. Sur Chrome il est parfait, sur Firefox un peu saccadé, et sur IE encore plus saccagé. Mais dans l'ensemble une bonne solution.

1
répondu Magnus 2018-03-19 16:02:50

la propriété CSS position: sticky a un grand support dans la plupart des navigateurs modernes (j'ai eu des problèmes avec Edge, voir ci-dessous).

cela nous permet de résoudre assez facilement le problème des en-têtes fixes:

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

Safari a besoin d'un fournisseur de préfixe: -webkit-sticky .

Pour Firefox, j'ai dû ajouter min-height: 0 à l'un des éléments parents. J'oublie exactement pourquoi c'était nécessaire.

malheureusement, le bord de Microsoft la mise en œuvre ne semble fonctionner qu'à moitié. Au moins, j'ai eu des cellules de table vacillantes et mal alignées dans mes tests. La table était encore utilisable, mais présentait des problèmes esthétiques importants.

1
répondu Daniel Waltrip 2018-10-04 01:37:11

utiliser la dernière version de jQuery, et inclure le code javascript suivant

$(window).scroll(function(){         
  $("id of the div element").offset({top:$(window).scrollTop()});         
}); 
0
répondu Prabhavith 2013-06-18 19:00:01

ce n'est pas une solution exacte à la ligne d'en-tête fixe, mais j'ai créé une méthode assez ingénieuse de répéter la ligne d'en-tête tout au long de la longue table tout en conservant la capacité de trier. Cette jolie petite option nécessite le jQuery tablesorter plugin . Voici comment cela fonctionne:

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>

évidemment, ma table a beaucoup plus de rangées que celle-ci. 193 pour être exact, l'écrou de vous pouvez voir où la ligne d'en-tête se répète. La ligne d'en-tête est configurée par cette fonction:

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
répondu DevlshOne 2013-08-22 18:25:41

j'aurais aimé avoir trouvé la solution de @Mark plus tôt, mais j'y suis allé et j'ai écrit la mienne avant de voir cette question ainsi...

Mine est un plugin jQuery très léger qui prend en charge l'en-tête fixe, le pied de page, la couverture de colonne (colspan), le redimensionnement, le défilement horizontal, et un nombre optionnel de lignes à afficher avant le début du défilement.

jQuery.scrolltablbody (GitHub)

aussi longtemps que vous avez une table avec propre <thead> , <tbody> , et (optionnel) <tfoot> , tout ce que vous devez faire est ceci:

$('table').scrollTableBody();
0
répondu Noah Heldman 2013-10-01 14:39:15

j'ai développé un plug-in léger jQuery simple pour convertir une table HTML bien en une table scrollable avec l'en-tête de table fixe et les colonnes.

le plugin fonctionne bien pour faire correspondre le positionnement pixel à pixel de la section fixe avec la section scrollable. En outre, vous pouvez également geler le nombre de colonnes qui seront toujours en vue lors du défilement horizontal.

Démos Et De La Documentation: http://meetselva.github.io/fixed-table-rows-cols/

Github Repo: https://github.com/meetselva/fixed-table-rows-cols

ci-dessous est l'usage pour une table simple avec en-tête fixe,

$(<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'}
              ]
});
0
répondu Selvakumar Arumugam 2013-12-12 17:07:35

beaucoup de gens semblent être à la recherche de cette réponse, je l'ai trouvé enterré dans une réponse à une autre question ici: la largeur de la colonne de synchronisation d'entre les tables dans deux cadres différents, etc

des dizaines de méthodes que j'ai essayées c'est la seule méthode que j'ai trouvé qui fonctionne de manière fiable pour vous permettre d'avoir une table de bas en-tête avec la table d'en-tête ayant les mêmes largeurs.

Voici comment je l'ai fait, d'abord je me suis amélioré sur le jsfiddle ci-dessus pour créer cette fonction, qui fonctionne à la fois sur td et th (dans le cas où cela déclenche d'autres qui utilisent th pour le style de leurs lignes d'en-tête).

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

ensuite, vous devez créer deux tables, notez que la table d'en-tête devrait avoir un TD supplémentaire pour laisser de la place dans la table supérieure pour le scrollbar, comme ceci:

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

alors faites quelque chose comme:

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

C'est la seule solution que j'ai trouvé sur stackoverflow que de nombreuses questions similaires qui ont été publiés, qui fonctionne dans tous mes cas.

par exemple, j'ai essayé le plugin jQuery stickytables qui ne fonctionne pas avec durandal, et le projet de code google ici https://code.google.com/p/js-scroll-table-header/issues/detail?id=2

autres solutions impliquant le clonage des tables, ont de mauvaises performances, ou sucer et ne fonctionnent pas dans tous les cas.

il n'y a pas besoin de ces SOLUTIONS trop complexes, il suffit de faire deux tableaux comme les exemples ci-dessous et D'appeler la fonction setHeaderTableWidth comme décrit ici et BOOM, vous êtes fait.

si cela ne fonctionne pas pour vous, vous avez probablement joué avec votre propriété CSS box-sizing et vous devez le définir correctement. Il est facile de foirer votre css par accident il y a beaucoup de choses qui peuvent mal tourner alors soyez juste conscient/prudent de cela. CETTE APPROCHE FONCTIONNE POUR MOI. Je suis si ça marche pour les autres, prévenez-moi. Bonne chance!

0
répondu pilavdzice 2017-05-23 11:47:28

Voici une solution avec laquelle nous avons fini par travailler (afin de traiter certains cas de bordures et les versions plus anciennes D'IE nous avons éventuellement effacé la barre de titre sur scroll puis l'effacer quand le défilement se termine, mais dans les navigateurs Firefox et Webkit cette solution fonctionne simplement . Il suppose l'effondrement de la frontière: l'effondrement.

la clé de cette solution est qu'une fois que vous appliquez border-collapse , CSS transforme fonctionne sur l'en-tête, donc il s'agit simplement d'intercepter les événements de scroll et de configurer la transformation correctement. Vous n'avez pas besoin de dupliquer quoi que ce soit. À moins que ce comportement ne soit correctement implémenté dans le navigateur, il est difficile d'imaginer une solution plus légère.

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

il est implémenté comme un simple plugin jQuery. Vous faites tout simplement votre théade collant avec un appel comme $('thead').collant() et ils vont traîner. Fonctionne pour plusieurs tables sur une page et des sections de tête à mi-chemin de grandes tables.

        $.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();
0
répondu podperson 2014-04-07 16:45:40

j'ai trouvé cette solution - déplacer ligne d'en-tête dans un tableau ci-dessus tableau avec les données:

<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>
0
répondu Leonid Alzhin 2015-07-21 18:19:09

en appliquant le Stickytablheaders jQuery plugin à la table, les en-têtes de colonne colleront au haut du viewport que vous faites défiler vers le bas.

exemple:

$(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
répondu shilovk 2016-10-05 15:47:23

Voici une réponse améliorée à celle publiée par Maximilian Hils .

celui-ci travaille dans IE11 sans scintillement que ce soit:

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) {
        // reseting 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
répondu user4617883 2017-09-29 15:23:39

j'aime Maximilien Collines' réponse mais j'ai eu quelques problèmes:

  1. la transformation ne fonctionne pas dans le bord ou IE à moins que vous ne l'appliquiez à la th
  2. l'en-tête clignote pendant le défilement dans Edge et IE
  3. ma table est chargée en utilisant ajax, donc je voulais attacher à l'événement de défilement de la fenêtre plutôt que l'événement de défilement de l'emballage

Pour se débarrasser de la flicker, j'utilise un timeout pour attendre que l'utilisateur ait terminé le défilement, puis j'applique la transform - de sorte que l'en-tête n'est pas visible pendant le défilement.

j'ai aussi écrit ceci en utilisant jQuery, un avantage de cela étant que jQuery devrait manipuler des préfixes de vendeur pour vous

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

la table est enveloppée dans un div de la classe table-container-fixed .

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

j'ai placé frontière-effondrement pour séparer parce que sinon nous perdons frontières lors de la traduction, et je supprime la frontière sur la table pour arrêter le contenu apparaissant juste au-dessus de la cellule où la frontière était pendant le défilement.

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

je fais le fond th blanc pour couvrir les cellules en dessous, et j'ajoute un bord qui correspond au bord de la table - qui est coiffé à L'aide D'un Bootstrap et écaillé hors de la vue.

 .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
répondu Colin 2017-11-27 13:38:49

j'ai fini Position:Sticky fonctionne très bien sur mon cas

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>
0
répondu Munkhdelger Tumenbayar 2018-10-10 09:42:45