• Das Erstellen neuer Accounts wurde ausgesetzt. Bei berechtigtem Interesse bitte Kontaktaufnahme über die üblichen Wege. Beste Grüße der Admin

Tabellen Kopfzeile stehen lassen beim scrollen

mikdoe

Moderator
Guten Morgen!
Angenommen folgender Seitenaufbau: Oben ein etwa 200 Pixel hoher Header, darunter eine Tabelle mit einer Kopfzeile und darunter der Tabelleninhalt. Tabelle ist eine echte <table>
Die Tabelle enthält soviele Zeilen, dass ein vertikaler Scrollbalken entsteht.

Nun hätte ich den Traum, dass beim Runterscrollen folgendes passiert: Erst scrollt das gesamte Bild (ganz normales Browserverhalten). Wenn aber der obere Rand der Tabellenkopfzeile an den oberen Anzeigerand des Browsers anstößt, soll ab dann die Kopfzeile der Tabelle statisch stehen bleiben und nur noch der Tabelleninhalt weiter scrollen.
Effekt ist, dass man immer die Kopfzeile mit den Spaltenbeschriftungen und Sortierbuttons sieht.

Und beim Hochscrollen analog: Sobald die erste Tabellenzeile am unteren Rand der Kopfzeile anstößt scrollt ab dann die Kopfzeile und der restliche Anzeigeinhalt wieder mit runter.

Hat jemand Tipps für mich, wie ich sowas anfange bzw. wie soetwas heißt? jQuery zu nutzen wäre in Ordnung, ist vorhanden.
Es braucht nicht in alten Browsern zu funktionieren. Wichtig sind IE8 für XP und dann alle neuesten Versionen von IE, Firefox, Opera und Chrome.

Vielen Dank für jeden Hinweis
 
Du kannst doch einfach den thead die CSS Eigenschaft position: fixed geben oder verstehe ich gerade dein Problem falsch?
 
Du kannst doch einfach den thead die CSS Eigenschaft position: fixed geben oder verstehe ich gerade dein Problem falsch?
Die Kopfzeile soll ja beim Runterscrollen erst mal den Seitenheader nach oben weg schieben. Und erst dann soll sie am oberen Anzeigerand fixed bleiben.
 
Basierend auf position: fixed, hier mal eine Idee
HTML:
<!DOCTYPE HTML>
<html lang="de">
<head>
    <title>Table with fixed header</title>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <style>
    .static_header {
        background-color: white;
        border: 2px solid blue;
        border-collapse: collapse;
        position: relative;
    }
    .static_header th, .static_header td {
        border: 1px solid blue;
        white-space: nowrap;
    }
    .static_header thead th {
        background-color: orange;
        border-bottom-width: 2px;
    }
    .static_header tfoot td {
        background-color: orange;
        text-align: center;
        border-top-width: 2px;
    }
    .static_header tbody td {
        background-color: silver;
    }
    </style>
    <script src="jquery-1.7.1.js"></script>
    <script>
    function staticTableHeader() {
        var leftCorrection = 1,
            jqTable = jQuery("table.static_header"),
            jqCaption = jqTable.find("caption"),
            jqHeadline = jqTable.find("thead th"),
            jqFirstDataline = jqTable.find("tbody tr:first td"),
            offsetTop = jqCaption.length > 0 ? jqCaption.height() : 0,
            tableHeight = jqTable.height(),
            theadHeight = jqTable.find("thead").height(),
            oldTableMarginTop = parseInt(jqTable.css('marginTop'), 10);

        leftCorrection += jqTable.offset().left;
        jqFirstDataline.each(function (index) {
            var jqThis = jQuery(this);
            jqHeadline.eq(index).css('width', jqThis.width());
        });
        jQuery(window).scroll(function () {
            var scrollPosTop = jQuery(window).scrollTop(),
                staticPosTop = jqTable.offset().top + offsetTop,
                staticPosBottom = staticPosTop + tableHeight;

            if (scrollPosTop > staticPosTop) {
                if (scrollPosTop < staticPosBottom) {
                    jqTable.css({
                        marginTop: oldTableMarginTop + theadHeight
                    });
                    jqTable.find("thead").css({
                        left: leftCorrection,
                        top: 0,
                        position: 'fixed'
                    });
                } else {
                    jqTable.find("thead").css({
                        top: -1000
                    });
                }
            } else {
                jqTable.css({
                    marginTop: oldTableMarginTop
                });
                jqTable.find("thead").css({
                    position: 'static'
                });
            }
        });
    }

    jQuery(document).ready(function () {
        staticTableHeader();
    });
    </script>
</head>

<body>
    1 fill page<br /><br />
    2 fill page<br /><br />
    3 fill page<br /><br />
    4 fill page<br /><br />
    5 fill page<br /><br />
    <div id="table-container">
        <table id="maintable" class="static_header">
            <caption>This table lists only sample entries.</caption>
            <thead>
                <tr>
                    <th scope="col">Col1</th>
                    <th scope="col">Col2</th>
                    <th scope="col">Col3</th>
                </tr>
            </thead>
            <tfoot>
                <tr>
                    <td colspan="3">7th JANUARY 2013</td>
                </tr>
            </tfoot>
            <tbody>
                <tr>
                    <td>info mkdgojgiod</td>
                    <td>info</td>
                    <td>info</td>
                </tr>
                <tr>
                    <td>info</td>
                    <td>info kopekopkpüsektf</td>
                    <td>info</td>
                </tr>
                <tr>
                    <td>info</td>
                    <td>info</td>
                    <td>info tfmopjtgopjwetop</td>
                </tr>
                <tr>
                    <td>info mkdgojgiod</td>
                    <td>info</td>
                    <td>info</td>
                </tr>
                <tr>
                    <td>info</td>
                    <td>info kopekopkpüsektf</td>
                    <td>info</td>
                </tr>
                <tr>
                    <td>info</td>
                    <td>info</td>
                    <td>info tfmopjtgopjwetop</td>
                </tr>
                <tr>
                    <td>info mkdgojgiod</td>
                    <td>info</td>
                    <td>info</td>
                </tr>
                <tr>
                    <td>info</td>
                    <td>info kopekopkpüsektf</td>
                    <td>info</td>
                </tr>
                <tr>
                    <td>info</td>
                    <td>info</td>
                    <td>info tfmopjtgopjwetop</td>
                </tr>
            </tbody>
        </table>
    <div id="bottom_anchor"></div>
    </div>
    <br /><br />
    6 fill page<br /><br />
    7 fill page<br /><br />
    8 fill page<br /><br />
    9 fill page<br /><br />
    10 fill page<br /><br />
    11 fill page<br /><br />
    12 fill page<br /><br />
    13 fill page<br /><br />
    14 fill page<br /><br />
    15 fill page<br /><br />
    16 fill page<br /><br />
    17 fill page<br /><br />
    18 fill page<br /><br />
    19 fill page<br /><br />
    20 fill page<br /><br />
    21 fill page<br /><br />
    22 fill page<br /><br />
    23 fill page<br /><br />
    24 fill page<br /><br />
    25 fill page<br /><br />
    26 fill page<br /><br />
    27 fill page<br /><br />
    28 fill page<br /><br />
    29 fill page<br /><br />
    30 fill page
</body>
</html>
 
Basierend auf position: fixed, hier mal eine Idee
Der Effekt ist zu 150 % wie gewünscht. Du hattest sogar daran gedacht was passiert, wenn unter der Tabelle noch Footer kommt. Wirklich gut!
Aber: Wenn man während des Scrollens gerade mit dem Tabellenheader an die obere Anzeigegrenze stößt gibt es sowohl im IE als auch im Firefox ein Flackern der Tabellenkopfzeile.
Im FF hört das erst auf, sobald die erste Inhaltszeile vollständig hinter der Kopfzeile verschwunden ist.
Im IE 9 auch und zusätzlich bleibt hier manchmal die Kopfzeile nicht am oberen Anzeigerand stehen sondern etwas versetzt, siehe Screenshot:
scrolltab.jpg

Kann man das technisch noch etwas feilen?
Nochmal ganz wichtig: Außer IE8 brauchen keine alten und unbekannten Browser funktionieren!
Vielen vielen Dank!
 
Folgendes sollte das Flickern beheben:
Code:
    function staticTableHeader() {
        var leftCorrection = 1,
            jqTable = jQuery("table.static_header"),
            jqCaption = jqTable.find("caption"),
            jqHead = jqTable.find("thead"),
            jqFirstDataline = jqTable.find("tbody tr:first td"),
            jqClone = jqTable.find("thead").clone(),
            offsetTop = jqCaption.length > 0 ? jqCaption.height() : 0,
            tableHeight = jqTable.height(),
            theadHeight = jqTable.find("thead").height();

        leftCorrection += jqTable.offset().left;
        jqFirstDataline.each(function (index) {
            var jqThis = jQuery(this);
            jqHead.find('th').eq(index).css('width', jqThis.width());
        });
        jQuery(window).scroll(function () {
            var scrollPosTop = jQuery(window).scrollTop(),
                staticPosTop = jqTable.offset().top + offsetTop,
                staticPosBottom = staticPosTop + tableHeight;

            if (scrollPosTop > staticPosTop) {
                if (scrollPosTop < staticPosBottom) {
                    jqTable.append(jqClone);
                    jqHead.css({
                        left: leftCorrection,
                        top: 0,
                        position: 'fixed'
                    });
                } else {
                    jqHead.css({
                        top: -1000
                    });
                }
            } else {
                jqClone.remove();
                jqHead.css({
                    position: 'static'
                });
            }
        });
    }
 
Folgendes sollte das Flickern beheben:
Ja, stimmt. Aber man sieht nun im IE und im FF, dass beim Erreichen der Oberkante eine Kopie der Kopfzeile angelegt wird, die stehen bleibt. Und diese Kopie hat nicht die selbe Breite wie die Original Kopfzeile, es gibt eine ganz leichte Überlagerung, siehe Bilder.

scrolltab_ff.jpgscrolltab_ie9.jpgscrolltab_ie8.jpg
Links: FF, Mitte: IE9, Rechts: IE8

Im FF sieht man nur am rechten Rand eine gaaaaanz leichte Breitenverdickung der rechten border.
Im IE sieht man es sehr deutlich, weil sich auch die Spaltenbreiten verschieben.

Bekommt man das noch bündig?

Danke dir
 
Da die ganzen Browser die Rahmenbreiten der einzelnen Tabellenzellen und die Darstellung von collapsed Zellen unterschiedlich handhaben ist das schon etwas schwierig.

Wie wäre es denn hiermit:
Code:
    function staticTableHeader() {
        var leftCorrection = 1,
            IE,
            arrWidth = [],
            fixedHeader = false,
            jqTable = jQuery("table.static_header"),
            jqCaption = jqTable.find("caption"),
            jqHead = jqTable.find("thead"),
            jqFirstDataline = jqTable.find("tbody tr:first td"),
            jqClone = jqTable.find("thead").clone(),
            staticPosTop = jqCaption.length > 0 ? jqCaption.height() + jqTable.offset().top : jqTable.offset().top,
            staticPosBottom = staticPosTop + jqTable.height();

        leftCorrection += jqTable.offset().left;
        IE = document.documentElement.style;
        IE = IE.scrollbar3dLightColor !== undefined ? true : false;
        jQuery(window).scroll(function () {
            var lastIndex,
                scrollPosTop = jQuery(window).scrollTop();

            if (scrollPosTop > staticPosTop) {
                if (!fixedHeader) {
                    arrWidth = [];
                    jqTable.append(jqClone);
                    jqHead.css({
                        left: leftCorrection,
                        top: 0,
                        position: 'fixed'
                    });
                    jqClone.find('th').each(function () {
                        arrWidth.push(jQuery(this).width());
                    });
                    if (IE) {
                        arrWidth[0] = arrWidth[0] - 1;
                    }
                    lastIndex = arrWidth.length - 1;
                    jqHead.find('th').each(function (index) {
                        jQuery(this).css('width', arrWidth[index]);
                    });
                    jqHead.find('th').each(function (index) {
                        if (index !== lastIndex) {
                            jQuery(this).css('width', arrWidth[index] + arrWidth[index] - jQuery(this).width());
                        } else {
                            jQuery(this).css('width', arrWidth[index] + arrWidth[index] - jQuery(this).width() - 1);
                        }
                    });
                    fixedHeader = true;
                }
                if (scrollPosTop < staticPosBottom) {
                    jqHead.css('top', 0);
                } else {
                    jqHead.css('top', -1000);
                }
            } else {
                jqHead.find('th').each(function () {
                    jQuery(this).css('width', '');
                });
                jqClone.remove();
                jqHead.css({
                    position: 'static'
                });
                fixedHeader = false;
            }
        });
    }
 
Opera, Maxthon, Chrome und IE8 sollten aber jetzt schonmal passen.
Opera+Chrome: Kurz bevor die Tabelle komplett unter der Kopfzeile verschwindet sieht man auch einen winzigen Streifen der äußeren border rechts und links.
scrolltab_opera+chrome.jpg
Das ist aber OK für mich. Wollte es nur nicht unerwähnt lassen, vielleicht hilft das.

Maxthon ist für mich unwichtig und IE8 habe ich im Moment nicht zur Hand.
Sehr wichtig wären FF und IE9.
 
Hier nochmal ein anderer Ansatz:
HTML:
<!DOCTYPE HTML>
<html lang="de">
<head>
    <title>Table with fixed header</title>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <style>
/*  also support border definition thin, medium and thick */
    .static_header {
        background-color: white;
        border: 2px solid blue;
        border-collapse: collapse;
    }
    .static_header th, .static_header td {
        border: 1px solid blue;
        white-space: nowrap;
    }
    .static_header thead th {
        background-color: orange;
        border-bottom-width: 2px;
    }
    .static_header tfoot td {
        background-color: orange;
        text-align: center;
        border-top-width: 2px;
    }
    .static_header tbody td {
        background-color: silver;
    }
    </style>
    <script src="jquery-1.7.1.js"></script>
    <script>
    function staticTableHeader() {
        var arrWidth,
            fixedHeader = true,
            jqTable = jQuery('#maintable'),
            jqCaption = jqTable.find('caption'),
            jqHead = jqTable.find('thead'),
            jqClone = jqHead.clone(),
            jqWrapper = jqTable.clone(),
            staticPosTop = jqCaption.length > 0 ? jqCaption.height() + jqTable.offset().top : jqTable.offset().top,
            staticPosBottom = staticPosTop + jqTable.height();

        jqTable.after(jqWrapper);
        jqWrapper.children().remove();
        jqWrapper.css({
            borderBottomWidth: 0,
            top: 0,
            position: 'fixed'
        });

        jQuery(window).scroll(function () {
            var scrollPosTop = jQuery(window).scrollTop();

            if (scrollPosTop > staticPosTop) {
                if (!fixedHeader) {
                    fixedHeader = true;
                    arrWidth = [];
                    jqWrapper.append(jqHead);
                    jqTable.prepend(jqClone);
                    jqClone.find('th').each(function () {
                        arrWidth.push(jQuery(this).width());
                    });
                    jqWrapper.find('th').each(function (index) {
                        jQuery(this).css('width', arrWidth[index]);
                    });
                    jqWrapper.find('th').each(function (index) {
                        jQuery(this).css('width', arrWidth[index] + arrWidth[index] - jQuery(this).width());
                    });
                }
                if (scrollPosTop < staticPosBottom) {
                    jqWrapper.css('top', 0);
                } else {
                    jqWrapper.css('top', -1000);
                }
            } else {
                jqClone.remove();
                jqTable.prepend(jqWrapper.find('thead'));
                jqHead.find('th').each(function () {
                    jQuery(this).css('width', '');
                });
                fixedHeader = false;
            }
        });
    }

    jQuery(document).ready(function () {
        var i;

        for (i = 1; i < 6; i += 1) {
            jQuery('#maintable').before(i + ' fill page <br /><br />');
        }
        for (i = 30; i > 5; i -= 1) {
            jQuery('#maintable').after(i + ' fill page <br /><br />');
        }
        jQuery('#maintable').after('<br /><br />');
        for (i = 0; i < 6; i += 1) {
            jQuery('#maintable tbody').append(jQuery('#maintable tbody').contents().clone());
        }
        staticTableHeader();
    });
    </script>
</head>

<body>
    <table id="maintable" class="static_header">
        <caption>This table lists only sample entries.</caption>
        <thead>
            <tr>
                <th scope="col">Col1</th>
                <th scope="col">Col2</th>
                <th scope="col">Col3</th>
            </tr>
        </thead>
        <tfoot>
            <tr>
                <td colspan="3">7th JANUARY 2013</td>
            </tr>
        </tfoot>
        <tbody>
            <tr>
                <td>info mkdgojgiod</td>
                <td>info</td>
                <td>info</td>
            </tr>
            <tr>
                <td>info</td>
                <td>info kopekopkpüsektf</td>
                <td>info</td>
            </tr>
            <tr>
                <td>info</td>
                <td>info</td>
                <td>info tfmopjtgopjwetop</td>
            </tr>
        </tbody>
    </table>
</body>
</html>
 
Hier nochmal ein anderer Ansatz:
Vielen Dank! Die Kopfzeile sieht hier ganz gut aus.
Habe nun mal die Tabelle verbreitert auf 9 Spalten. Wenn du dann den Anzeigebereich schmaler machst, sodass ein horizontaler Scrollbalken entsteht und danach mal hoch scrollst stellst du fest, dass sich sämtliche Spaltenbreiten in der Kopfzeile verändern. Der Browser versucht also, die Kopfzeile auf die Anzeigebreite anzupassen.
Kann man das unterdrücken?
Ich muss dazu sagen, dass ich eine solche überbreite Tabelle mit der alten Lösung noch nicht getestet habe.
scrolltab_ff_neu.jpg
 
Das ist im nachhinein auch ein logisches Verhalten. Da als porition fixed verwendet wird, orientiert sich der Browser an den momentanen viewport (sichtbaren Bereich) und versucht das Beste daraus zu machen.
 
Das ist im nachhinein auch ein logisches Verhalten. Da als porition fixed verwendet wird, orientiert sich der Browser an den momentanen viewport (sichtbaren Bereich) und versucht das Beste daraus zu machen.
Ja, verstehe ich. Aber dieses Verhalten nützt mir nichts. Der Effekt ist ja, dass man jederzeit die Bedeutung der Spalten ablesen soll. Aber wenn die total verrutschen ist es nicht nur optisch unschön sondern auch inhaltlich wenig hilfreich.
Könnte man vielleicht beim Aufbau der gesamten Tabelle alle Spaltenbreiten fixieren? Und bei Änderung der Bildschirmgröße (ein bei mir eher seltener Fall) baut man sie neu auf und fixiert sie auch neu?
 
Könnte man, jedoch besteht dann weiterhin das Problem von position fixed. Denn wenn man dann nach links/rechts scrollen will/muss, müsste man die Position des fixierten Tabellenheaders mit anpassen. Keine Ahnung wie flüssig das dann ausschauen würde.
 
Zurück
Oben