web-dev-qa-db-fra.com

Faire défiler TBODY dans les navigateurs Webkit

Je suis conscient de de cette question , mais aucune des réponses ne fonctionne dans Safari, Chrome, etc.

La stratégie acceptée ( comme démontré ici ) consiste à définir les propriétés de hauteur et de débordement de tbody comme suit:

<table>
    <thead>
        <tr><th>This is the header and doesn't scroll</th></tr>
    </thead>
    <tbody style="height:100px; overflow:auto;">
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
    </tbody>
</table>

Malheureusement, cela ne fonctionne dans aucun navigateur Webkit. Il y a un rapport de bogue à ce sujet qui ne semble pas être une haute priorité (rapporté le 5 juin).

Ma question est donc la suivante: existe-t-il d’autres stratégies qui fonctionnent réellement? J'ai essayé l'approche à deux tables, mais il est impossible de garantir que l'en-tête s'alignera avec le contenu. Dois-je simplement attendre que Webkit le corrige?

68
Andrew Ensley

Voici un exemple de travail:

http://www.imaputz.com/cssStuff/bigFourVersion.html

Vous devez ajouter l’affichage: block to the thead> tr and tbody

32
Michael Koper

Utilisation de l'affichage: le style de bloc ne fonctionne que si vous avez 1 colonne. Si vous avez plusieurs colonnes de données - avec plusieurs champs -, alors display: block apparaît pour faire défiler toutes les colonnes de données mais sous la 1re colonne (fait de même avec Firefox - qui est le seul navigateur que je connaisse qui défile correctement. Incidemment, sur Firefox, vous pouvez utiliser le style overflow-x: hidden pour supprimer le défilement horizontal.

J'ai réalisé que le problème que je viens de mentionner ne se produit que si vous ne spécifiez pas de largeur pour les éléments th & td - si vous pouvez corriger la largeur des colonnes, cela fonctionne. Le problème pour moi est que je ne peux pas réparer les largeurs de colonne.

17
Martin

Essayez la première méthode de cette page, CSS pur avec une seule table (2 divs autour de la table, et le thead est positionné absolu): http://www.cssplay.co.uk/menu/tablescroll.html Semble fonctionner sur FF4/IE9/IE8 en plus de IE7/FF3.6.

12
lsf

J'ai vu Sean Haddy excellente solution et j'ai pris la liberté de faire quelques modifications :

  • Utilisez des classes à la place de l'ID pour qu'un script jQuery puisse être réutilisé pour plusieurs tables sur une page.
  • Ajout de la prise en charge des éléments de tableau HTML sémantique tels que caption, thead, tfoot et tbody
  • La barre de défilement est facultative et ne s'affiche donc pas pour les tableaux plus "courts" que la hauteur de défilement.
  • Ajustement de la largeur de la barre de défilement pour amener la barre de défilement vers la droite. Bord du tableau
  • Concept rendu accessible par
    • using aria-hidden = "true" sur l'en-tête de table statique injecté
    • et en laissant l'original en place, juste caché avec jQuery et définissez aria-hidden="false"
  • Exemples montrés de plusieurs tables avec différentes tailles

Sean a toutefois fait le gros du travail. Merci également à Matt Burland d’avoir souligné la nécessité de soutenir tFoot.

S'il vous plaît voir par vous-même à http://jsfiddle.net/jhfrench/eNP2N/

5
Jeromy French

J'ai eu le même problème et écrit un script jQuery pour le faire pour moi ... utilise deux éléments de table et formate le css en conséquence. J'espère que cela aide les autres qui ont le même problème ...

http://jsfiddle.net/pe295/1/

5
Sean Haddy

A fait face au même problème il y a longtemps, et j'ai finalement exposé l'approche des deux tables. Voici le résultat: http://jsfiddle.net/bGr4V/3/ , cela fonctionne pour tous les navigateurs (IE6 + incl).

Dans ce jsFiddle vous pouvez jouer avec une version propre.

Ma solution a été d'ajouter une cellule fixe<th class="fix"> </th> dans thead pour remplir l'espace de la barre de défilement dans la tbody, puis de donner à une colonne une largeur variable (<td class="grow">), ainsi l'en-tête cellule fixe ne remettrait pas en cause le redimensionnement.

HTML:

<div class="fixed_table">
  <div class="head">
    <table>
      <thead>
        <tr>
          <th>Column header</th>
          <th class="grow">Column header</th>
          <th class="fix"> </th>
        </tr>
      </thead>
    </table>
  <div class="body">
    <table class="full_table">
      <caption class="caption">Caption</caption>
      <tbody>
        <tr>
          <td>Data</td>
          <td class="grow">Data</td>
        </tr>
        <tr>
          <td>...</td>
          <td>...</td>
        </tr>
        <tr>
          <td>...</td>
          <td>...</td>
        </tr>
      </tbody>
    </table>
  </div>
</div>

CSS: a * et _ hack pour ie6-7, et un -webkit spécifique à l'en-tête cellule fixe la largeur de défilement correspondante dans chaque cas.

.fixed_table table {
  table-layout: fixed;
  width: auto;
  border-width: 0;
  padding: 0;
  border-collapse: collapse;
}

.fixed_table .body {
  overflow: scroll;
  overflow-x: hidden;
  max-height: 10.75em;
  min-height: 2.5em;
  padding-bottom: 0.8em;
  *padding-right: 17px; /*ie7 & ie6*/
  _padding-right: 0; /*ie6*/
  _height: 10em ;
}

.fixed_table th, .fixed_table td {
  width: 4.7em;
}

.fixed_table .grow {
  width: auto;
}

.fixed_table .fix {
  width: 16px;
  *width: 17px; /*ie7 & ie6*/
  _width: 16px; /*ie6*/
}

/* webkit specific */
@media screen and (-webkit-min-device-pixel-ratio:0) {
  .fixed_table .fix{ width: 17px }
}
3
I.G. Pascual

Je pensais que je mettrais ma solution dans le mélange - http://tjvantoll.com/2012/11/10/creating-cross-browser-scrollable-tbody/ .

Il utilise le même chemin de base que la solution de @Michael Koper mais inclut une solution de contournement afin que le tableau soit correct dans IE et renvoyé à IE6.

Je résous le problème de la largeur en donnant au <table> un table-layout: fixed et en attribuant explicitement la largeur aux cellules de chaque colonne. Ce n’est pas idéal, mais cela produit un tableau sémantique qui aligne tous les navigateurs, qu’une barre de défilement soit nécessaire ou non.

Démo: http://codepen.io/tjvantoll/pen/JEKIu

2
TJ VanToll

C'est peut-être excessif pour cette question, mais YUI fournit toujours le meilleur datatable gratuit pour les navigateurs. Il peut également être utilisé pour des données en lecture seule.

YUI 2 DataTable

YUI 3 DataTable

Cliquez sur les exemples pour voir des exemples à défilement. Depuis, je suis un débutant à stackoverflow, je ne peux poster que ces deux liens.

1
user2030366

C’est vraiment bien hacky, mais peut-être, cela aidera quelqu'un.

http://jsfiddle.net/yUHCq/1/

Il utilise des colonnes au lieu de lignes afin que le traitement soit essentiellement effectué à l'envers.

DOCTYPE de transition ajouté pour la compatibilité IE.

1
Matthew

J'ai développé une solution javascript pour le problème ci-dessus 
qui ne fonctionne que dans Firefox 7+ comme je l’ai testé uniquement dans FF 

Je suis arrivé à ce fil et j'ai trouvé la solution indiquée par Michael Koper

Dans cette solution, trois choses importantes sont accomplies 
1) fixer la largeur de la colonne 
2) thead> tr display est réglé pour bloquer
3) t L’affichage de la machine est réglé pour bloquer 

comme d'autres l'ont mentionné problème pour fixer la largeur, je suis aussi dans la même position; 
même si je ne peux pas fixer la largeur de manière statique 

donc je pensais que je corrigerais la largeur dynamiquement (après que la table soit rendue dans le navigateur).

voici la solution en javascript qui ne fonctionne qu'en FF
(Je n'ai testé que dans FF, je n'ai pas accès à d'autres navigateurs) 

       function test1(){                
            var tbodys = document.getElementsByTagName("TBODY");
            for(var i=0;i<tbodys.length;i++){
                do_tbodyscroll(tbodys[i]);
            }
        }


      function do_tbodyscroll(_tbody){
            // get the table node 
            var table = _tbody.parentNode;

            // first row of tbody 
            var _fr = _tbody.getElementsByTagName("TR")[0];

            // first row cells .. 
            var _frcells = _fr.cells;

            // Width array , width of each element is stored in this array 
            var widtharray = new Array(_frcells.length);

            for(var i=0;i<_frcells.length;i++){                    
                widtharray[i] = _frcells[i].scrollWidth;
            }                

            // Apply width to first row                  
            for(var i=0;i<_frcells.length;i++){
                _frcells[i].width = widtharray[i];                   
            }                 

            // Get the Last row in Thead ... 
            // COLGROUPS USING COLSPAN NOT YET SUPPORTED

            var thead = table.getElementsByTagName("THEAD")[0];
            var _rows = thead.getElementsByTagName("TR");
            var tableheader = _rows[_rows.length - 1];
            var headercells = tableheader.cells;

            // Apply width to header ..                                
            for(var i=0;i<headercells.length;i++){
                headercells[i].width = widtharray[i];
            }

            // ADD 16 Pixel of scroll bar to last column ..
            headercells[headercells.length -1 ].width = widtharray[headercells.length -1] + 16;

            tableheader.style.display = "block";
            _tbody.style.display = "block";  
        }

Cette solution découvre quelle est la largeur de la colonne depuis le navigateur 
et redéfinit la même largeur pour les colonnes (en-tête et première ligne de tbody) 
après que la largeur est définie; thead> tr et tbody l’affichage est réglé pour bloquer 

J'espère que cette solution est utile pour vous tous. 
Si vous pouvez l’étendre à d’autres navigateurs, répondez à ce message. 

1
Digambar Sangavkar

Laissez le tableau dessiner à sa guise, calculez la largeur de chaque colonne et réglez-le sur chaque en-tête. Les titres sont faits avec des divisions et nous pouvons ensuite laisser la table défiler librement.

<!DOCTYPE html>
<html>
<head>
<style>
.t_heading{
  margin-top: 20px;
  font-family: Verdana, Geneva, sans-serif;
  background-color: #4CAF50;
}

.heading{
  background-color: #4CAF50;
  color: white;
  float:left;
  padding: 8px 0PX 8PX 0PX;
  border-bottom: 1px solid #ddd;
  height: 20px;
  text-align: left;
}

.t_data{
  overflow-y: scroll;
  overflow-x: hidden;
  height:0px;
  width: 100%;

}

.t_content{
    border-collapse: collapse;
    font-family: Verdana, Geneva, sans-serif;
    width: 100%;
}

.column1,.column2,.column3,.column4{
    padding: 8px 0PX 8PX 0PX;
    text-align: left;
    border-bottom: 1px solid #ddd;
}
.t_row:hover{
  background-color:#f5f5f5;
}
</style>
<script>
function setBody(){
    var body = document.body,
    html = document.documentElement;

    var height = Math.max( body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight );
    height = height-300;
    /*
     ** By changing the subtraction value, You can fit the table in to the screen correctly.
     ** Make sure not to come the hscroll.
     ** Or you can set fixed height with css for the div as your wish.
     */
    document.getElementById("t_data").style.height = height+"px";

    setColumnWidth("column1");
    setColumnWidth("column2");
    setColumnWidth("column3");
    setColumnWidth("column4");
}

function setColumnWidth(o){
        var object = o;
        var x = document.getElementsByClassName(object);
        var y = x[0].clientWidth;
        document.getElementById(object).style.width = y+"px";
 }
</script>
</head>

<body onload="setBody()">
<div class="t_heading">
<div class="heading"  id="column1">Heading 1</div>
<div class="heading"  id="column2">Heading 2</div>
<div class="heading"  id="column3">Heading 3</div>
<div class="heading"  id="column4">Heading 4</div>
</div>
<div class="t_data" id="t_data">
<table class="t_content">
    <tr class='t_row'>
        <td class='column1'>Column1 Row 0</td>
        <td class='column2'>Column2 Row 0</td>
        <td class='column3'>Column3 Row 0</td>
        <td class='column4'>Column4 Row 0</td>
    </tr><tr class='t_row'>
        <td class='column1'>Column1 Row 1</td>
        <td class='column2'>Column2 Row 1</td>
        <td class='column3'>Column3 Row 1</td>
        <td class='column4'>Column4 Row 1</td>
    </tr><tr class='t_row'>
        <td class='column1'>Column1 Row 2</td>
        <td class='column2'>Column2 Row 2</td>
        <td class='column3'>Column3 Row 2</td>
        <td class='column4'>Column4 Row 2</td>
    </tr><tr class='t_row'>
        <td class='column1'>Column1 Row 3</td>
        <td class='column2'>Column2 Row 3</td>
        <td class='column3'>Column3 Row 3</td>
        <td class='column4'>Column4 Row 3</td>
    </tr><tr class='t_row'>
        <td class='column1'>Column1 Row 4</td>
        <td class='column2'>Column2 Row 4</td>
        <td class='column3'>Column3 Row 4</td>
        <td class='column4'>Column4 Row 4</td>
    </tr><tr class='t_row'>
        <td class='column1'>Column1 Row 5</td>
        <td class='column2'>Column2 Row 5</td>
        <td class='column3'>Column3 Row 5</td>
        <td class='column4'>Column4 Row 5</td>
    </tr><tr class='t_row'>
        <td class='column1'>Column1 Row 6</td>
        <td class='column2'>Column2 Row 6</td>
        <td class='column3'>Column3 Row 6</td>
        <td class='column4'>Column4 Row 6</td>
    </tr><tr class='t_row'>
        <td class='column1'>Column1 Row 7</td>
        <td class='column2'>Column2 Row 7</td>
        <td class='column3'>Column3 Row 7</td>
        <td class='column4'>Column4 Row 7</td>
    </tr><tr class='t_row'>
        <td class='column1'>Column1 Row 8</td>
        <td class='column2'>Column2 Row 8</td>
        <td class='column3'>Column3 Row 8</td>
        <td class='column4'>Column4 Row 8</td>
    </tr><tr class='t_row'>
        <td class='column1'>Column1 Row 9</td>
        <td class='column2'>Column2 Row 9</td>
        <td class='column3'>Column3 Row 9</td>
        <td class='column4'>Column4 Row 9</td>
    </tr><tr class='t_row'>
        <td class='column1'>Column1 Row 10</td>
        <td class='column2'>Column2 Row 10</td>
        <td class='column3'>Column3 Row 10</td>
        <td class='column4'>Column4 Row 10</td>
    </tr>
<!--
<?php
$data = array();
for($a = 0; $a<50; $a++)
{
    $data[$a] = array();
    $data[$a][0] = "Column1 Row ".$a;
    $data[$a][1] = "Column2 Row ".$a;
    $data[$a][2] = "Column3 Row ".$a;
    $data[$a][3] = "Column4 Row ".$a;
}
/*
 ** supose you have data in an array.. which red from database. The table will draw using array data. Or you can draw the table manualy.
 ** tip: If using manual table, No need of
 ** 'var x = document.getElementsByClassName(object); var y = x[0].clientWidth;'.
 ** You can just set ID of first row's cells in to some name and use it to read width.
 */
for($i=0;$i<sizeof($data);$i++){
    echo "<tr class='t_row'><td class='column1'>".$data[$i][0]."</td><td class='column2'>".$data[$i][1]."</td><td class='column3'>".$data[$i][2]."</td><td class='column4'>".$data[$i][3]."</td></tr>";
}
?>
-->
</table>
</div>
</body>
</html>
0
Salitha Prasad

Ajouter display:block; Ceci supprimera également le défilement horizontal inutile dans FireFox. Vous savez sans doute également qu'aucun de ces exemples ne fonctionne dans MSIE 8.

<table>
    <thead>
        <tr><th>This is the header and doesn't scroll</th></tr>
    </thead>
    <tbody style="height:100px; overflow:auto;display:block;">
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
        <tr><td>content that scrolls</td></tr>
    </tbody>
</table>
0
mmcglynn

Si quelqu'un a besoin que cela fonctionne en mode IE quirks, voici comment j'ai modifié et simplifié I.G. Le code de Pascual au travail:

.fixed_table{
       overflow: scroll;
       overflow-x: hidden;
       max-height: 300px;
       height: 300px;
       min-height: 50px;
       padding-right:0;
}
#datatable td 
{
       padding:3px;
       text-align: center;
       width: 9%;
       vertical-align: middle;
       background-color: #343435; 
       color: #E0E0E3;
       overflow:hidden;
} 
<div class="head">
    <table>
        <thead>
            <tr>
                <th>Time (GMT)</th>
                <th>Price</th>
            </tr>
        </thead>
    </table>
</div>
<div class="fixed_table">
    <table id="datatable" cellspacing="1" cellpadding="1">
        <tbody></tbody>
    </table>
</div>
0
Ronen Festinger

Il y a un exemple ici qui fonctionne dans IE5 +, Firefox et Chrome. Cependant, il utilise des colonnes de largeur fixe . http://www.cssplay.co.uk/menu/tablescroll.html

0
user1491819