Table avec en-tête fixe et colonne fixe sur css pur


100

J'ai besoin de créer une table html (ou quelque chose de similaire) avec un en-tête fixe et une première colonne fixe.

Toutes les solutions que j'ai vues jusqu'à présent utilisent Javascript ou jQuerypour définir scrollTop / scrollLeft, mais cela ne fonctionne pas correctement sur les navigateurs mobiles, donc je recherche une solution CSS pure.

J'ai trouvé une solution pour une colonne fixe ici: jsfiddle.net/C8Dtf/20/ mais je ne sais pas comment je peux l'améliorer pour rendre l'en-tête fixe aussi.

Je veux qu'il fonctionne sur les navigateurs Webkit ou utilise certaines css3fonctionnalités, mais je le répète, je ne veux pas l'utiliser Javascriptpour le défilement.

EDIT: Ceci est un exemple du comportement que je souhaite atteindre: https://web.archive.org/web/20130829032141/http://datatables.net/release-datatables/extras/FixedColumns/css_size.html


Je ne vois pas où <html> <table> avec un en-tête fixe <thead> a à voir avec css-level-3 pour le moment. Qu'avez vous d'autre ? Qu'est-ce que tu as essayé jusque-là ?
Milche Patern

J'ai essayé d'appliquer un positioncomportement complexe aux lignes et aux cellules, mais je ne comprends pas très bien où cela est applicable ou non.
panfil

2
Cette réponse peut vous aider stackoverflow.com/questions/14834198/…
Garry

Réponses:


145

Une véritable solution CSS pure avec une ligne d'en-tête fixe et une première colonne

J'ai dû créer un tableau avec à la fois un en-tête fixe et une première colonne fixe en utilisant du CSS pur et aucune des réponses ici n'était tout à fait ce que je voulais.

La position: stickypropriété prend en charge à la fois le maintien en haut (comme je l'ai vu le plus utilisé) et sur le côté dans les versions modernes de Chrome, Firefox et Edge. Cela peut être combiné avec un divqui a la overflow: scrollpropriété de vous donner un tableau avec des en-têtes fixes qui peuvent être placés n'importe où sur votre page:

Placez votre table dans un récipient:

<div class="container">
  <table></table>
</div>

Utilisez overflow: scrollsur votre conteneur pour activer le défilement:

div.container {
  overflow: scroll;
}

Comme Dagmar l'a souligné dans les commentaires, le conteneur nécessite également un max-widthet un max-height.

Utilisez position: stickypour avoir des cellules de table en tenir à bord et top, rightou leftde choisir le bord de coller à:

thead th {
  position: -webkit-sticky; /* for Safari */
  position: sticky;
  top: 0;
}

tbody th {
  position: -webkit-sticky; /* for Safari */
  position: sticky;
  left: 0;
}

Comme MarredCheese l'a mentionné dans les commentaires, si votre première colonne contient des <td>éléments au lieu d' <th>éléments, vous pouvez utiliser tbody td:first-childdans votre CSS au lieu detbody th

Pour que l'en-tête de la première colonne reste à gauche, utilisez:

thead th:first-child {
  left: 0;
  z-index: 1;
}

https://jsfiddle.net/qwubvg9m/1/


22
Cela semble être la meilleure réponse.
user1190132

9
@PirateApp Si vous connaissez le widthde votre première colonne, vous pouvez utiliser position: stickysur les cellules de votre deuxième colonne avec une leftvaleur égale à celle de votre première colonne width: jsfiddle.net/wvypo83c/794
Matthew Schlachter

4
Cette réponse prouve qu'il vaut la peine de la lire jusqu'en bas!
mlerley

4
Cela ne fonctionne pas sans une largeur maximale et une hauteur maximale définies sur le conteneur.
Dagmar

9
Cette réponse est un phare qui nous guide à la maison à travers la mer infinie de réponses défectueuses, surchargées et chronophages provenant d'affiches étonnamment confiantes et déconcertantes ici sur SO et sur le Web. Notez que si votre première colonne contient des <td>éléments au lieu d' <th>éléments, vous pouvez utiliser tbody td:first-childdans votre CSS au lieu de tbody th.
MarredCheese

33

De nos jours, cela est possible en utilisant le CSS uniquement avec la position: stickypropriété.

Voici un extrait:

(jsFiddle: https://jsfiddle.net/hbqzdzdt/5/ )

.grid-container {
  display: grid; /* This is a (hacky) way to make the .grid element size to fit its content */
  overflow: auto;
  height: 300px;
  width: 600px;
}
.grid {
  display: flex;
  flex-wrap: nowrap;
}
.grid-col {
  width: 150px;
  min-width: 150px;
}

.grid-item--header {
  height: 100px;
  min-height: 100px;
  position: sticky;
  position: -webkit-sticky;
  background: white;
  top: 0;
}

.grid-col--fixed-left {
  position: sticky;
  left: 0;
  z-index: 9998;
  background: white;
}
.grid-col--fixed-right {
  position: sticky;
  right: 0;
  z-index: 9998;
  background: white;
}

.grid-item {
  height: 50px;
  border: 1px solid gray;
}
<div class="grid-container">
  <div class="grid">
    <div class="grid-col grid-col--fixed-left">
      <div class="grid-item grid-item--header">
        <p>HEAD</p>
      </div>
      <div class="grid-item">
        <p>Hello</p>
      </div>
      <div class="grid-item">
        <p>Hello</p>
      </div>
      <div class="grid-item">
        <p>Hello</p>
      </div>
      <div class="grid-item">
        <p>Hello</p>
      </div>
      <div class="grid-item">
        <p>Hello</p>
      </div>
      <div class="grid-item">
        <p>Hello</p>
      </div>
      <div class="grid-item">
        <p>Hello</p>
      </div>
      <div class="grid-item">
        <p>Hello</p>
      </div>
      <div class="grid-item">
        <p>Hello</p>
      </div>
      <div class="grid-item">
        <p>Hello</p>
      </div>
    </div>

    <div class="grid-col">
      <div class="grid-item grid-item--header">
        <p>HEAD</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
    </div>

    <div class="grid-col">
      <div class="grid-item grid-item--header">
        <p>HEAD</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
    </div>

    <div class="grid-col">
      <div class="grid-item grid-item--header">
        <p>HEAD</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
    </div>

    <div class="grid-col">
      <div class="grid-item grid-item--header">
        <p>HEAD</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
    </div>

    <div class="grid-col">
      <div class="grid-item grid-item--header">
        <p>HEAD</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
    </div>

    <div class="grid-col">
      <div class="grid-item grid-item--header">
        <p>HEAD</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
    </div>

    <div class="grid-col">
      <div class="grid-item grid-item--header">
        <p>HEAD</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
    </div>

    <div class="grid-col">
      <div class="grid-item grid-item--header">
        <p>HEAD</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
    </div>

    <div class="grid-col">
      <div class="grid-item grid-item--header">
        <p>HEAD</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
    </div>

    <div class="grid-col">
      <div class="grid-item grid-item--header">
        <p>HEAD</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
      <div class="grid-item">
        <p>P</p>
      </div>
    </div>

    <div class="grid-col grid-col--fixed-right">
      <div class="grid-item grid-item--header">
        <p>HEAD</p>
      </div>
      <div class="grid-item">
        <p>9</p>
      </div>
      <div class="grid-item">
        <p>9</p>
      </div>
      <div class="grid-item">
        <p>9</p>
      </div>
      <div class="grid-item">
        <p>9</p>
      </div>
      <div class="grid-item">
        <p>9</p>
      </div>
      <div class="grid-item">
        <p>9</p>
      </div>
      <div class="grid-item">
        <p>9</p>
      </div>
      <div class="grid-item">
        <p>9</p>
      </div>
      <div class="grid-item">
        <p>9</p>
      </div>
      <div class="grid-item">
        <p>9</p>
      </div>
    </div>

  </div>
</div>

Concernant la compatibilité. Cela fonctionne dans tous les principaux navigateurs, mais pas dans IE. Il y a un polyfill pour position: stickymais je ne l'ai jamais essayé.


2
C'est génial, j'adore!
Captain Lu

3
n'importe quel moyen d'y parvenir avec <table> -tags et non <div>
Andreas

1
Je pense que cela n'aura pas de bonnes performances si vous développez une application et que vous devez parcourir les enregistrements pour imprimer ce tableau, car pour chaque colonne du tableau, vous devez parcourir l'ensemble du tableau de l'enregistrement. Ce HTML fonctionne colonne par colonne.
igasparetto

@igasparetto Vous pouvez en fait organiser les lignes / colonnes dans l'autre sens et la solution fonctionnerait toujours. Si j'ai un peu de temps plus tard, je peux créer un extrait de code avec la ligne ordonnée par grille -> colonne.
Alvaro

2
Je déconseille d'afficher des données tabulaires sans utiliser <table> et les balises associées. Il y a plusieurs problèmes avec la rupture de l'utilisation prévue du HTML de cette manière, y compris l'accessibilité. Voir aussi: w3.org/WAI/tutorials/tables
Ben Morris

15

Ce n'est pas un exploit facile.

Le lien suivant est vers une démo fonctionnelle:

Lien mis à jour selon le commentaire de lanoxx

http://jsfiddle.net/C8Dtf/366/

N'oubliez pas d'ajouter ceux-ci:

<script type="text/javascript" charset="utf-8" src="http://datatables.net/release-datatables/media/js/jquery.js"></script>
<script type="text/javascript" charset="utf-8" src="http://datatables.net/release-datatables/media/js/jquery.dataTables.js"></script>
<script type="text/javascript" charset="utf-8" src="http://datatables.net/release-datatables/extras/FixedColumns/media/js/FixedColumns.js"></script>

je ne vois pas d'autre moyen d'y parvenir. Surtout pas en utilisant uniquement css.

C'est beaucoup de choses à traverser. J'espère que cela t'aides :)


Pour changer le filtre, utilisez: "bFilter": false
lanoxx

6
Il est possible d'y parvenir avec css uniquement. Pas facile mais possible.
Jimmy T.

parmi environ 10 solutions, c'était la seule qui fonctionnait. Btw, pour supprimer le "Affichage de 1 à 57 entrées sur 57", ajoutez "bInfo" : falseà l' .dataTable()appel
hansaplast

datatables == "awesome"
billynoah

voter contre cette solution parce qu'elle est mauvaise. le theadest dans son propre tableau qui n'est pas lié aux changements d' tdéléments, donc si le texte d'une cellule est long, la thlargeur ne s'ajustera pas en conséquence.
vsync

14

Toutes ces suggestions sont excellentes et toutes, mais elles ne corrigent que l'en-tête ou une colonne, pas les deux, ou elles utilisent du javascript. La raison - il ne pense pas que cela puisse être fait en CSS pur. La raison:

S'il était possible de le faire, vous auriez besoin d'imbriquer plusieurs divs scrollables les uns dans les autres, chacun avec un défilement dans une direction différente. Ensuite, vous devrez diviser votre tableau en trois parties: l'en-tête fixe, la colonne fixe et le reste des données.

Bien. Mais maintenant le problème - vous pouvez faire en sorte que l'un d'eux reste en place lorsque vous faites défiler, mais l'autre est imbriqué dans la zone de défilement du premier et est donc sujet au défilement hors de vue lui-même, donc ne peut pas être fixé en place sur l'écran. «Ah-ha» vous dites «mais je peux en quelque sorte utiliser une position absolue ou fixe pour faire ça» - non, vous ne pouvez pas. Dès que vous faites cela, vous perdez la possibilité de faire défiler ce conteneur. C'est une situation de poule et d'oeuf - vous ne pouvez pas avoir les deux, ils s'annulent.

Je pense que la seule solution consiste à utiliser javascript. Vous devez séparer complètement les trois éléments et garder leurs positions synchronisées via javascript. Il y a de bons exemples dans d'autres articles sur cette page. Celui-ci vaut également le coup d'œil:

http://tympanus.net/codrops/2014/01/09/sticky-table-headers-columns/


9

J'ai fait quelques changements dans jsfiddle. C'est peut-être ce que vous essayez de faire.

http://jsfiddle.net/C8Dtf/81/

J'ai codé en dur les titres comme ceci:

<table id="left_table" class="freeze_table">
    <tr class='tblTitle'>
         <th>Title 1</th>
         <th>Title 2</th>
    </tr>
</table>

Et j'ai aussi ajouté quelques styles.

.tblTitle{
   position:absolute;
    top:0px;
    margin-bottom:30px;
    background:lightblue;
}
td, th{
    padding:5px;
    height:40px;
    width:40px;
    font-size:14px;
}

J'espère que c'est ce que tu veux :)


1
J'ai besoin d'un en-tête de la bonne table pour faire défiler avec son contenu.
panfil

Voici l'URL: jsfiddle.net/C8Dtf/84 . Il vous suffit de jouer avec le style de la table de droite pour aligner les deux tables.
Phillip-juan

Non, vous ne comprenez pas très bien. J'ai besoin que l'en-tête du tableau de droite soit fixé en haut pour qu'il soit toujours visible lorsque le tableau défile de haut en bas, mais lorsque le tableau défile à droite ou à gauche, l'en-tête doit défiler vers la droite ou la gauche mais toujours être fixé en haut. Désolé moi pour mes mauvaises compétences en anglais.
panfil le

Voulez-vous donc que l'en-tête du tableau de droite soit fixe lors du défilement vertical et qu'il défile lors du défilement horizontal?
Phillip-juan

Voici un exemple du comportement que je souhaite atteindre: datatables.net/release-datatables/extras/FixedColumns/…
panfil

9

Un exemple utilisant uniquement CSS:

.table {
  table-layout: fixed;
  width: 500px;
  border-collapse: collapse;
}

.header th {
  font-family: Calibri;
  font-size: small;
  font-weight: lighter;
  border-left: 1px solid #000;
  background: #d0d0d0;
}

.body_panel {
  display: inline-block;
  width: 520px;
  height: 300px;
  overflow-y: scroll;
}

.body tr {
  border-bottom: 1px solid #d0d0d0;
}

.body td {
  border-left: 1px solid #d0d0d0;
  padding-left: 3px;
  font-family: Calibri;
  font-size: small;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
<body>

  <table class="table">

    <thead class="header">

      <tr>
        <th style="width:20%;">teste</th>
        <th style="width:30%;">teste 2</th>
        <th style="width:50%;">teste 3</th>
      </tr>

    </thead>
  </table>

  <div class="body_panel">

    <table class="table">
      <tbody class="body">

        <tr>
          <td style="width:20%;">asbkj k kajsb ksb kabkb</td>
          <td style="width:30%;">2</td>
          <td style="width:50%;">3</td>
        </tr>

        <tr>
          <td style="width:20%;">2</td>
          <td style="width:30%;">2</td>
          <td style="width:50%;">3</td>
        </tr>

        <tr>
          <td style="width:20%;">2</td>
          <td style="width:30%;">2</td>
          <td style="width:50%;">3</td>
        </tr>

        <tr>
          <td style="width:20%;">2</td>
          <td style="width:30%;">2</td>
          <td style="width:50%;">3</td>
        </tr>

        <tr>
          <td style="width:20%;">2</td>
          <td style="width:30%;">2</td>
          <td style="width:50%;">3</td>
        </tr>

        <tr>
          <td style="width:20%;">2</td>
          <td style="width:30%;">2</td>
          <td style="width:50%;">3</td>
        </tr>

        <tr>
          <td style="width:20%;">2</td>
          <td style="width:30%;">2</td>
          <td style="width:50%;">3</td>
        </tr>

        <tr>
          <td style="width:20%;">2</td>
          <td style="width:30%;">2</td>
          <td style="width:50%;">3</td>
        </tr>

        <tr>
          <td style="width:20%;">2</td>
          <td style="width:30%;">2</td>
          <td style="width:50%;">3</td>
        </tr>

        <tr>
          <td style="width:20%;">2</td>
          <td style="width:30%;">2</td>
          <td style="width:50%;">3</td>
        </tr>

        <tr>
          <td style="width:20%;">2</td>
          <td style="width:30%;">2</td>
          <td style="width:50%;">3</td>
        </tr>

        <tr>
          <td style="width:20%;">2</td>
          <td style="width:30%;">2</td>
          <td style="width:50%;">3</td>
        </tr>

        <tr>
          <td style="width:20%;">2</td>
          <td style="width:30%;">2</td>
          <td style="width:50%;">3</td>
        </tr>

        <tr>
          <td style="width:20%;">2</td>
          <td style="width:30%;">2</td>
          <td style="width:50%;">3</td>
        </tr>

        <tr>
          <td style="width:20%;">2</td>
          <td style="width:30%;">2</td>
          <td style="width:50%;">3</td>
        </tr>

        <tr>
          <td style="width:20%;">2</td>
          <td style="width:30%;">2</td>
          <td style="width:50%;">3</td>
        </tr>

        <tr>
          <td style="width:20%;">2</td>
          <td style="width:30%;">2</td>
          <td style="width:50%;">3</td>
        </tr>

        <tr>
          <td style="width:20%;">2</td>
          <td style="width:30%;">2</td>
          <td style="width:50%;">3</td>
        </tr>

      </tbody>
    </table>

  </div>

</body>


3
J'avais besoin non seulement de réparer le heder, mais aussi de la première colonne.
panfil

Cet exemple montre une approche avec deux tables dans le html: une table rend uniquement l'en-tête; la deuxième table restitue les lignes uniquement mais le fait dans un fichier div. C'est le divqui permet le défilement des lignes tandis que l'en-tête reste au même endroit. Cette approche a fonctionné pour mes besoins.
David Tansey

S'il y a également un défilement horizontal, vous avez besoin de JS pour synchroniser les positions de défilement des tableaux.
Zoltán Tamási

4

J'ai trouvé une excellente solution par Paul O'Brien pour le problème et je voudrais partager le lien: https://codepen.io/paulobrien/pen/LBrMxa

J'ai supprimé le style du pied de page:

html {
  box-sizing: border-box;
}
*,
*:before,
*:after {
  box-sizing: inherit;
}
.intro {
  max-width: 1280px;
  margin: 1em auto;
}
.table-scroll {
  position: relative;
  width:100%;
  z-index: 1;
  margin: auto;
  overflow: auto;
  height: 350px;
}
.table-scroll table {
  width: 100%;
  min-width: 1280px;
  margin: auto;
  border-collapse: separate;
  border-spacing: 0;
}
.table-wrap {
  position: relative;
}
.table-scroll th,
.table-scroll td {
  padding: 5px 10px;
  border: 1px solid #000;
}
.table-scroll thead th {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
}

th:first-child {
  position: -webkit-sticky;
  position: sticky;
  left: 0;
  z-index: 2;
  background: #ccc;
}
thead th:first-child {
  z-index: 5;
}

4

Pour corriger à la fois les en-têtes et les colonnes, vous pouvez utiliser le plugin suivant:


Mis à jour en juillet 2019

Récemment, est également apparue une solution CSS pure basée sur la propriété CSS position: sticky;( ici pour plus de détails à ce sujet) appliquée sur chaque THélément (au lieu de leur conteneur parent)


1
Le premier lien est rompu. Le second utilise jQuery.
PussInBoots

Réponse mise à jour pour supprimer le lien mort
Luca Detomi

2

J'ai récemment dû créer une solution avec un groupe d'en-tête fixe et une première colonne fixe. J'ai divisé ma table en div et utilisé jquery pour capturer le défilement de la fenêtre.

http://jsfiddle.net/TinT/EzXub/2346/

var prevTop = 0;
var prevLeft = 0;

$(window).scroll(function(event){
  var currentTop = $(this).scrollTop();
  var currentLeft = $(this).scrollLeft();

  if(prevLeft !== currentLeft) {
    prevLeft = currentLeft;
    $('.header').css({'left': -$(this).scrollLeft()})
  }
  if(prevTop !== currentTop) {
    prevTop = currentTop;
    $('.leftCol').css({'top': -$(this).scrollTop() + 40})
  }
});

1

Un collègue et moi venons de publier un nouveau projet GitHub qui fournit une directive Angular que vous pouvez utiliser pour décorer votre table avec des en-têtes fixes: https://github.com/objectcomputing/FixedHeader

Il s'appuie uniquement sur css et angular, avec une directive qui ajoute quelques divs. Il n'y a pas de jQuery requis.

Cette implémentation n'est pas aussi complète que certaines autres implémentations, mais si votre besoin est simplement d'ajouter des tables fixes, nous pensons que cela pourrait être une bonne option.


1

Après deux jours de combat avec Internet Explorer 9 + Chrome + Firefox (Windows) et Safari (Mac), j'ai trouvé un système qui est

  • Compatible avec tous ces navigateurs
  • Sans utiliser javascript
  • Utiliser seulement une div et une table
  • En-tête et pied de page fixes (sauf pour IE), avec un corps déroulant. En-tête et corps avec les mêmes largeurs de colonne

Résultat: entrez la description de l'image ici

HTML:

  <thead>
    <tr>
      <th class="nombre"><%= f.label :cost_center %></th>
      <th class="cabecera cc">Personal</th>
      <th class="cabecera cc">Dpto</th>
    </tr>
  </thead>
  <tbody>
    <% @cost_centers.each do |cc| %>
    <tr>
      <td class="nombre"><%= cc.nombre_corto %></td>
      <td class="cc"><%= cc.cacentrocoste %></td>
      <td class="cc"><%= cc.cacentrocoste_dpto %></td>
    </tr>
    <% end %>
  </tbody>
  <tfoot>
    <tr>
      <td colspan="3"><a href="#">Mostrar mas usuarios</a></td>
    </tr>
  </tfoot>
</table>

CSS:

div.cost_center{
  width:320px;
  font-size:75%;
  margin-left:5px;
  margin-top:5px;
  margin-bottom: 2px;
  float: right;
  display: inline-block;
  overflow-y: auto;
  overflow-x: hidden;
  max-height:300px;  
}

div.cost_center label { 
  float:none;
  font-size:14px;
}

div.cost_center table{
  width:300px;
  border-collapse: collapse; 
  float:right;
  table-layout:fixed;
}

div.cost_center table tr{
  height:16px;
}
div.cost_center th{
  font-weight:normal;
}

div.cost_center table tbody{
  display: block;
  overflow: auto;
  max-height:240px;
}

div.cost_center table thead{
  display:block;
}

div.cost_center table tfoot{
  display:block;
}
div.cost_center table tfoot td{
  width:280px;
}
div.cost_center .cc{
  width:60px;
  text-align: center; 
  border: 1px solid #999;
}

div.cost_center .nombre{
  width:150px;
}
div.cost_center tbody .nombre{
  border: 1px solid #999;
}

div.cost_center table tfoot td{
 text-align:center;  
 border: 1px solid #999; 
} 

div.cost_center table th, 
div.cost_center table td { 
  padding: 2px;
  vertical-align: middle; 
}

div.cost_center table tbody td {
  white-space: normal;
  font:  .8em/1.4em Verdana, sans-serif;
  color: #000;
  background-color: white;
}
div.cost_center table th.cabecera { 
  font:  0.8em/1.4em Verdana, sans-serif;
  color: #000;
  background-color: #FFEAB5;
}

Bien essayé, mais ne fonctionne pas très bien pour moi. Dans cet exemple ( jsfiddle.net/5ka6e ), l'en-tête ne se redimensionne pas correctement. Ce type d'erreur pourrait éventuellement entraîner une incompatibilité des données et des en-têtes.
darkzangel

1
Vous oubliez d'ajouter div.cost_center table{border-collapse: collapse;}et la troisième légende doit être quelque chose qui rentre dans le 60px (dans cet exemple)
Albert Català

1

Les réponses existantes conviendront à la plupart des gens, mais pour ceux qui cherchent à ajouter des ombres sous l'en-tête fixe et à droite de la première colonne (fixe), voici un exemple fonctionnel (css pur):

http://jsbin.com/nayifepaxo/1/edit?html,output

L'astuce principale pour que cela fonctionne consiste ::afterà ajouter des ombres à droite de chacun des premiers tdde chacun tr:

tr td:first-child:after {
  box-shadow: 15px 0 15px -15px rgba(0, 0, 0, 0.05) inset;
  content: "";
  position:absolute;
  top:0;
  bottom:0;
  right:-15px;
  width:15px;
}

Il m'a fallu un certain temps (trop de temps ...) pour que tout fonctionne, alors j'ai pensé que je partagerais pour ceux qui sont dans une situation similaire.


Avez-vous basé cela sur la réponse de quelqu'un d'autre et ajouté l'ombre?
PussInBoots

1

besoin de corriger le pied de page d'en-tête


0

Quelque chose comme cela peut fonctionner pour vous ... Il vous faudra probablement avoir défini des largeurs de colonne pour votre ligne d'en-tête.

thead { 
    position: fixed;
}

http://jsfiddle.net/vkhNC/

Mettre à jour:

Je ne suis pas convaincu que l'exemple que vous avez donné soit possible avec juste CSS. J'aimerais que quelqu'un me prouve le contraire. Voici ce que j'ai jusqu'ici . Ce n'est pas le produit fini mais cela pourrait être un début pour vous. J'espère que cela vous oriente dans une direction utile, où que ce soit.


J'ai besoin non seulement d'un en-tête, mais aussi d'une première colonne fixe.
panfil

5
Le problème est que les en-têtes perdent leur largeur. Cela a l'air moche avec une taille de colonne d'en-tête et une taille de colonne de données différentes.
Akash Kava


0

Exemple de CSS pur:

<div id="cntnr">
    <div class="tableHeader">
        <table class="table-header table table-striped table-bordered">
            <thead>
                <tr>
                    <th>this</th>
                    <th>transmission</th>
                    <th>is</th>
                    <th>coming</th>
                    <th>to</th>
                    <th>you</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>we've got it...</td>
                    <td>alright you are go</td>
                    <td>uh, we see the Earth now</td>
                    <td>we've got it...</td>
                    <td>alright you are go</td>
                    <td>uh, we see the Earth now</td>
                </tr>
            </tbody>
        </table>
    </div>


    <div class="tableBody">
        <table class="table-body table table-striped table-bordered">
            <thead>
                <tr>
                    <th>this</th>
                    <th>transmission</th>
                    <th>is</th>
                    <th>coming</th>
                    <th>to</th>
                    <th>you</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>we've got it...</td>
                    <td>alright you are go</td>
                    <td>uh, we see the Earth now</td>
                    <td>we've got it...</td>
                    <td>alright you are go</td>
                    <td>uh, we see the Earth now</td>
                </tr>
            </tbody>
        </table>
    </div>

</div>

#cntnr {
    width: auto;
    height: 200px;
    border: solid 1px #444;
    overflow: auto;
}

.tableHeader {
    position: fixed;
    height: 40px;
    overflow: hidden;
    margin-right: 18px;
    background: white;
}

.table-header tbody {
    height: 0;
    visibility: hidden;
}

.table-body thead {
    height: 0;
    visibility: hidden;
}

http://jsfiddle.net/cCarlson/L98m854d/

Inconvénient: La structure / logique d' en- tête fixe dépend assez sur les dimensions spécifiques de, de sorte que l' abstraction est probablement pas une option viable .


Besoin d'un en-tête fixe et d'une première colonne fixe.
panfil

Ah ... merci de l'avoir signalé, panfil. Je vais faire une modification. Cheers
Cody

0

Position: sticky ne fonctionne pas pour certains éléments comme (thead) dans Chrome et d'autres navigateurs Webkit comme safari.

Mais ça marche bien avec (th)

body {
  background-color: rgba(0, 255, 200, 0.1);
}

.intro {
  color: rgb(228, 23, 23);
}

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

.sticky {
  position: sticky;
  top: 0;
  color: black;
  background-color: white;
}
<div class="container intro">
  <h1>Sticky Table Header</h1>
  <p>Postion : sticky doesn't work for some elements like (thead) in chrome and other webkit browsers like safari. </p>
  <p>But it works fine with (th)</p>
</div>
<div class="container wrapper">
  <table class="table table-striped">
    <thead>
      <tr>
        <th class="sticky">Firstname</th>
        <th class="sticky">Lastname</th>
        <th class="sticky">Email</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>James</td>
        <td>Vince</td>
        <td>james@example.com</td>
      </tr>
      <tr>
        <td>Jonny</td>
        <td>Bairstow</td>
        <td>jonny@example.com</td>
      </tr>
      <tr>
        <td>James</td>
        <td>Anderson</td>
        <td>james@example.com</td>
      </tr>
      <tr>
        <td>Stuart</td>
        <td>Broad</td>
        <td>stuart@example.com</td>
      </tr>
      <tr>
        <td>Eoin</td>
        <td>Morgan</td>
        <td>eoin@example.com</td>
      </tr>
      <tr>
        <td>Joe</td>
        <td>Root</td>
        <td>joe@example.com</td>
      </tr>
      <tr>
        <td>Chris</td>
        <td>Woakes</td>
        <td>chris@example.com</td>
      </tr>
      <tr>
        <td>Liam</td>
        <td>PLunkett</td>
        <td>liam@example.com</td>
      </tr>
      <tr>
        <td>Jason</td>
        <td>Roy</td>
        <td>jason@example.com</td>
      </tr>
      <tr>
        <td>Alex</td>
        <td>Hales</td>
        <td>alex@example.com</td>
      </tr>
      <tr>
        <td>Jos</td>
        <td>Buttler</td>
        <td>jos@example.com</td>
      </tr>
      <tr>
        <td>Ben</td>
        <td>Stokes</td>
        <td>ben@example.com</td>
      </tr>
      <tr>
        <td>Jofra</td>
        <td>Archer</td>
        <td>jofra@example.com</td>
      </tr>
      <tr>
        <td>Mitchell</td>
        <td>Starc</td>
        <td>mitchell@example.com</td>
      </tr>
      <tr>
        <td>Aaron</td>
        <td>Finch</td>
        <td>aaron@example.com</td>
      </tr>
      <tr>
        <td>David</td>
        <td>Warner</td>
        <td>david@example.com</td>
      </tr>
      <tr>
        <td>Steve</td>
        <td>Smith</td>
        <td>steve@example.com</td>
      </tr>
      <tr>
        <td>Glenn</td>
        <td>Maxwell</td>
        <td>glenn@example.com</td>
      </tr>
      <tr>
        <td>Marcus</td>
        <td>Stoinis</td>
        <td>marcus@example.com</td>
      </tr>
      <tr>
        <td>Alex</td>
        <td>Carey</td>
        <td>alex@example.com</td>
      </tr>
      <tr>
        <td>Nathan</td>
        <td>Coulter Nile</td>
        <td>nathan@example.com</td>
      </tr>
      <tr>
        <td>Pat</td>
        <td>Cummins</td>
        <td>pat@example.com</td>
      </tr>
      <tr>
        <td>Adam</td>
        <td>Zampa</td>
        <td>zampa@example.com</td>
      </tr>
    </tbody>
  </table>
</div>

Ou visitez mon exemple codepen :



-2

Si vous ne souhaitez utiliser que du HTML et du CSS purs, j'ai une solution à votre problème:
dans ce jsFiddle, vous pouvez voir une solution sans script qui fournit un tableau avec un en-tête fixe. L'adaptation du balisage pour une première colonne fixe ne devrait pas poser de problème également. Il vous suffit de créer une table positionnée en absolu pour la première colonne à l'intérieur de hWrapper-div et de repositionner la vWrapper-div.
Fournir du contenu dynamique ne devrait pas être un problème en utilisant des moteurs de tentation côté serveur ou côté navigateur, ma solution fonctionne bien dans tous les navigateurs modernes et les navigateurs plus anciens à partir d'IE8.


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.