web-dev-qa-db-ja.com

大きなテーブルを表示するときに、ウィンドウの上部にHTMLテーブルヘッダーが常に表示される

HTMLテーブルのプレゼンテーションを「微調整」して単一の機能を追加できるようにしたいと思います。ページをスクロールダウンしてテーブルを画面上に表示し、ヘッダー行を画面外に表示する場合、ヘッダーはそのままにしておきます表示領域の上部に表示されます。

これは、概念的にはExcelの「ペインの固定」機能に似ています。ただし、HTMLページにはいくつかのテーブルが含まれている可能性があり、表示中の場合にのみ、現在表示されているテーブルに対してのみ発生させたいと考えています。

注:ヘッダーはスクロールせずに、テーブルデータ領域をスクロール可能にする解決策を見てきました。それは私が探している解決策ではありません。

165
Craig McQueen

チェックアウトjQuery.floatTheadデモ利用可能)これは非常にクールで、 DataTables でも機能し、overflow: autoコンテナー内でも機能します。

65
Hendy Irawan

jQuery を使用して、概念実証ソリューションを作成しました。

サンプルをここに表示します。

このコードは Mercurial bitbucket repository にあります。メインファイルは tables.html です。

私はこれに関する1つの問題を認識しています:テーブルにアンカーが含まれている場合、ブラウザで指定されたアンカーでURLを開くと、ページがロードされると、おそらくアンカーのある行がフローティングヘッダーによって隠されます。

2017-12-11の更新:これは現在のFirefox(57)およびChrome(63)では機能しないことがわかります。これがいつ、なぜ機能しなくなったのか、またはそれを修正する方法がわかりません。しかし今、私は Hendy Irawanが受け入れた回答 が優れていると思います。

135
Craig McQueen

クレイグ、私はあなたのコードを少し洗練し(現在、position:fixedを使用している他のいくつかのことの中で)、jQueryプラグインとしてラップしました。

ここで試してみてください: http://jsfiddle.net/jmosbech/stFcx/

ここでソースを取得します: https://github.com/jmosbech/StickyTableHeaders

67
jmosbech

最新のcss3準拠のブラウザーをターゲットにしている場合(ブラウザーサポート:https://caniuse.com/#feat=css-stickyposition:stickyを使用できます。これは、JSを必要とせず、同じ列のthとtdをミスアライメントするテーブルレイアウトを壊しません。また、適切に機能するために固定列幅も必要ありません。

単一のヘッダー行の例:

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

1行または2行のtheadの場合、次のようなものを使用できます:

thead > :last-child th
{
    position: sticky;
    top: 30px; /* This is for all the the "th" elements in the second row, (in this casa is the last child element into the thead) */
}

thead > :first-child th
{
    position: sticky;
    top: 0px; /* This is for all the the "th" elements in the first child row */
}

最後の子のtopプロパティを使用して、最初の行の高さに合わせてピクセル数を変更する必要がある場合があります(+マージン+ボーダー+パディング(存在する場合)。したがって、2番目の行は最初の行のすぐ下に貼り付けられます。

また、同じページに複数のテーブルがある場合でも、両方のソリューションが機能します:各テーブルのth要素は、最上位がcss定義に示されている位置である場合にスティッキーになり、すべてのテーブルが下にスクロールすると消えます。したがって、より多くのテーブルがある場合、すべて同じように美しく機能します。

で最後の子beforeと最初の子afterを使用する理由css?

CSSルールはCSSファイルに書き込むのと同じ順序でブラウザによってレンダリングされるため、このため、thead要素に1行しかない場合、最初の行も同時に最後の行であり、first-childルールが必要です最後の子をオーバーライドします。そうでない場合、上余白から30ピクセルの行のオフセットがありますが、これはしたくないと思います。

位置の既知の問題:スティッキーは、thead要素またはテーブル行では機能しないことです。th要素をターゲットにする必要があります。この問題は、将来のブラウザバージョンで解決されることを期待しています。

7
willy wonka

可能な選択肢

js-floating-table-headers

js-floating-table-headers (Google Code)

Drupalで

Drupal 6サイトがあります。私は管理者の「モジュール」ページにいて、テーブルにこの正確な機能があることに気付きました!

コードを見ると、 tableheader.js というファイルによって実装されているようです。クラスsticky-enabledを持つすべてのテーブルに機能を適用します。

Drupalサイトの場合、ユーザーコンテンツに tableheader.js モジュールをそのまま使用できるようにしたいと思います。 tableheader.js は、Drupalのユーザーコンテンツページに存在しないようです。 フォーラムメッセージ を投稿して、Drupalテーマを変更して利用可能にする方法を尋ねました。応答によると、次のように、テーマのtableheader.jsdrupal_add_js()を使用して、template.phpをDrupalテーマに追加できます。

drupal_add_js('misc/tableheader.js', 'core');
5
Craig McQueen

私はごく最近この問題に遭遇しました。残念ながら、ヘッダー用と本文用の2つのテーブルを作成する必要がありました。これはおそらく最高のアプローチではありませんが、ここにあります:

<html>
<head>
    <title>oh hai</title>
</head>
<body>
    <table id="tableHeader">
        <tr>
            <th style="width:100px; background-color:#CCCCCC">col header</th>
            <th style="width:100px; background-color:#CCCCCC">col header</th>
        </tr>
    </table>
    <div style="height:50px; overflow:auto; width:250px">
        <table>
            <tr>
                <td style="height:50px; width:100px; background-color:#DDDDDD">data1</td>
                <td style="height:50px; width:100px; background-color:#DDDDDD">data1</td>
            </tr>
            <tr>
                <td style="height:50px; width:100px; background-color:#DDDDDD">data2</td>
                <td style="height:50px; width:100px; background-color:#DDDDDD">data2</td>
            </tr>
        </table>
    </div>
</body>
</html>

これは私にとってはうまくいきました。おそらくエレガントな方法ではありませんが、うまくいきます。調査しますので、もっと良いことができるかどうかを確認しますが、複数のテーブルを使用できます。

オーバーフロー の適切性を読んで、ニーズに合っているかどうかを確認します

4
Gab Royer

テーブルにスティッキーヘッダーを付けるのは本当に難しいことです。私は同じ要件を持っていましたが、asp:GridViewを使用して、gridviewにヘッダーが粘着していると本当に思ったことがわかりました。多くの解決策があり、すべての解決策を試すのに3日かかりましたが、どれも満足できませんでした。

私がこれらのソリューションのほとんどで直面した主な問題は、アライメントの問題でした。ヘッダーをフローティングにしようとすると、何らかの理由でヘッダーセルとボディセルの配置がずれます。

いくつかの解決策では、ヘッダーが本文の最初の数行に重なるという問題もありました。これにより、本文の行がフローティングヘッダーの後ろに隠れてしまいます。

そのため、これを達成するために独自のロジックを実装する必要がありましたが、これを完璧なソリューションとは考えていませんが、これは誰かにとっても役立つかもしれません

以下にサンプルテーブルを示します。

<div class="table-holder">
        <table id="MyTable" cellpadding="4" cellspacing="0" border="1px" class="customerTable">
            <thead>
                <tr><th>ID</th><th>First Name</th><th>Last Name</th><th>DOB</th><th>Place</th></tr>
            </thead>
            <tbody>
                <tr><td>1</td><td>Customer1</td><td>LastName</td><td>1-1-1</td><td>Sun</td></tr>
                <tr><td>2</td><td>Customer2</td><td>LastName</td><td>2-2-2</td><td>Earth</td></tr>
                <tr><td>3</td><td>Customer3</td><td>LastName</td><td>3-3-3</td><td>Mars</td></tr>
                <tr><td>4</td><td>Customer4</td><td>LastName</td><td>4-4-4</td><td>Venus</td></tr>
                <tr><td>5</td><td>Customer5</td><td>LastName</td><td>5-5-5</td><td>Saturn</td></tr>
                <tr><td>6</td><td>Customer6</td><td>LastName</td><td>6-6-6</td><td>Jupitor</td></tr>
                <tr><td>7</td><td>Customer7</td><td>LastName</td><td>7-7-7</td><td>Mercury</td></tr>
                <tr><td>8</td><td>Customer8</td><td>LastName</td><td>8-8-8</td><td>Moon</td></tr>
                <tr><td>9</td><td>Customer9</td><td>LastName</td><td>9-9-9</td><td>Uranus</td></tr>
                <tr><td>10</td><td>Customer10</td><td>LastName</td><td>10-10-10</td><td>Neptune</td></tr>
            </tbody>
        </table>
    </div>

:テーブルは、「table-holder」に等しいクラス属性を持つDIVにラップされます。

以下は、htmlページヘッダーに追加したJQueryスクリプトです。

<script src="../Scripts/jquery-1.7.2.min.js" type="text/javascript"></script>
<script src="../Scripts/jquery-ui.min.js" type="text/javascript"></script>
<script type="text/javascript">
    $(document).ready(function () {
        //create var for table holder
        var originalTableHolder = $(".table-holder");
        // set the table holder's with
        originalTableHolder.width($('table', originalTableHolder).width() + 17);
        // Create a clone of table holder DIV
        var clonedtableHolder = originalTableHolder.clone();

        // Calculate height of all header rows.
        var headerHeight = 0;
        $('thead', originalTableHolder).each(function (index, element) {
            headerHeight = headerHeight + $(element).height();
        });

        // Set the position of cloned table so that cloned table overlapped the original
        clonedtableHolder.css('position', 'relative');
        clonedtableHolder.css('top', headerHeight + 'px');

        // Set the height of cloned header equal to header height only so that body is not visible of cloned header
        clonedtableHolder.height(headerHeight);
        clonedtableHolder.css('overflow', 'hidden');

        // reset the ID attribute of each element in cloned table
        $('*', clonedtableHolder).each(function (index, element) {
            if ($(element).attr('id')) {
                $(element).attr('id', $(element).attr('id') + '_Cloned');
            }
        });

        originalTableHolder.css('border-bottom', '1px solid #aaa');

        // Place the cloned table holder before original one
        originalTableHolder.before(clonedtableHolder);
    });
</script>

最後に、少し色付けするためのCSSクラスを示します。

.table-holder
{
    height:200px;
    overflow:auto;
    border-width:0px;    
}

.customerTable thead
{
    background: #4b6c9e;        
    color:White;
}

したがって、このロジックの全体的な考えは、テーブルをテーブルホルダーdivに配置し、ページの読み込み時にクライアント側でそのホルダーのクローンを作成することです。クローンホルダー内のテーブルの本体を非表示にし、残りのヘッダー部分を元のヘッダーの上に配置します。

同じソリューションはasp:gridviewでも機能します。gridviewでこれを実現するには、さらに2つのステップを追加する必要があります。

  1. WebページのgridviewオブジェクトのOnPrerenderイベントで、ヘッダー行のテーブルセクションをTableHeaderに設定します。

    if (this.HeaderRow != null)
    {
        this.HeaderRow.TableSection = TableRowSection.TableHeader;
    }
    
  2. そして、グリッドを<div class="table-holder"></div>にラップします。

:ヘッダーにクリック可能なコントロールがある場合、クローンヘッダーで発生したイベントを元のヘッダーに渡すために、さらにjQueryスクリプトを追加する必要があります。このコードは、jQuery sticky-headerプラグインで既に利用可能です jmosbech

3
Prasoon

全画面テーブルを使用する場合、thをdisplay:fixedに設定することに興味があるかもしれません。およびtop:0;またはcssを介して非常に類似したアプローチを試してください。

更新

Iframe(html4.0)を使用して実用的なソリューションをすぐに構築します。この例はIS標準に準拠していませんが、簡単に修正できます:

outer.html

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">   
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">     
    <head>      
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />   
        <title>Outer</title>
  <body>
    <iframe src="test.html" width="200" height="100"></iframe>
    </body>
</html> 

test.html

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">   
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">     
    <head>      
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />   
        <title>Floating</title>
    <style type="text/css">
      .content{
        position:relative; 
      }

      thead{
        background-color:red;
        position:fixed; 
        top:0;
      }
    </style>
  <body>
    <div class="content">      
      <table>
        <thead>
          <tr class="top"><td>Title</td></tr>
        </head>
        <tbody>
          <tr><td>a</td></tr>
          <tr><td>b</td></tr>
          <tr><td>c</td></tr>
          <tr><td>d</td></tr>
          <tr><td>e</td></tr>
          <tr><td>e</td></tr>
          <tr><td>e</td></tr>
          <tr><td>e</td></tr>
          <tr><td>e</td></tr>
          <tr><td>e</td></tr>
        </tbody>
      </table>
    </div>
    </body>
</html> 
2
merkuro

theadセクションでdisplay: fixedを使用しても機能しますが、ビュー内の現在のテーブルでのみ機能するため、JavaScriptの助けが必要になります。また、ブラウザの非互換性の主要な領域の1つであるビューポートに対する要素のスクロール位置と位置を把握する必要があるため、注意が必要です。

人気のあるJavaScriptフレームワーク(jQuery、MooTools、YUIなど)を見て、希望することを実行できるか、希望することを簡単に行えるかを確認してください。

2
staticsan

あるブラウザでうまく機能するものが、他のブラウザでは機能しないのはイライラします。以下はFirefoxで動作しますが、ChromeまたはIEでは動作しません:

<table width="80%">

 <thead>

 <tr>
  <th>Column 1</th>
  <th>Column 2</th>
  <th>Column 3</th>
 </tr>

 </thead>

 <tbody style="height:50px; overflow:auto">

  <tr>
    <td>Cell A1</td>
    <td>Cell B1</td>
    <td>Cell C1</td>
  </tr>

  <tr>
    <td>Cell A2</td>
    <td>Cell B2</td>
    <td>Cell C2</td>
  </tr>

  <tr>
    <td>Cell A3</td>
    <td>Cell B3</td>
    <td>Cell C3</td>
  </tr>

 </tbody>

</table>
0
Peter Dow

それは 概念実証 あなたが作った素晴らしい!ただし、 このjQueryプラグイン も非常にうまく機能しているようです。それが役に立てば幸い!

0
Marco