Pure CSS scrolling UL LI table with fixed header

19,801

Solution 1

You can try this: DEMO

I got these correct in pure css:

  • using table CSS (table, table-row, table-cell, table-header-group...)
  • all cells have to be list items (LI)
  • header has to be fixed when table content is scrolling

The last requirement I had to use some jquery.

Anyway what I did was create two <li class="testRow"> for <div class="testHeader">. One of them has an id with css position:fixed

That trick accomplishes your first 3 requirements. The last one is really tricky for css alone so what I did was add jquery:

$(document).ready(function(e) {
    adjustHeader();
});

function adjustHeader(){
    //get width of the NOT fixed header spans
    var a = $("span#tid").width();
        b = $("span#tname").width();
        c = $("span#tdesc").width();
        d = $("span#tod1").width();
        e = $("span#tod2").width();

    //Change the width of the fixed header spans
    //with the other headers spans
    $("span#fid").width(a);
    $("span#fname").width(b);
    $("span#fdesc").width(c);
    $("span#fod1").width(d);
    $("span#fod2").width(e);
}

Hope it helped!

EDIT

Run function adjustHeader() everytime you add new data so that the headers will realign.

Here is a DEMO

Solution 2

As soon as you specify either position: absolute or position: fixed on .testHeader, it sets display: block which overrides display: table-header-group.

See this thread for details.

Solution 3

I believe I have solved this issue by creating a second header section. To start I duplicated the "testHeader" html:

    <div class="testHeader">
        <li class="testRow">
            <span>ID</span>
            <span>Name</span>
            <span>Description</span>
            <span>Other details 1</span>
            <span>Other details 2</span>
        </li>
    </div>
    <div class="secondHeader">
        <li class="testRow">
            <span>ID</span>
            <span>Name</span>
            <span>Description</span>
            <span>Other details 1</span>
            <span>Other details 2</span>
        </li>
    </div>

Note that the new "secondHeader" has a new class. This class is set to position absolute.

.secondHeader {
  display: table-header-group;
  position: fixed;
  top: 0px;
}

Then set the original header (that gives the table its structure) to visibility hidden.

.testHeader {
  display: table-header-group;
  visibility: hidden;
}

You should now have a list displayed as a table, with a fixed header element that stay in position when you re size. I updated your fiddle as a demo.

Share:
19,801

Related videos on Youtube

OzrenTkalcecKrznaric
Author by

OzrenTkalcecKrznaric

I'm in the software development since 2002, and in the web development (using Microsoft technologies) since 2008. Since I use Microsoft .NET Framework and C# daily, I gues I'm good at it. I've developed quite a few applications and components in .NET, and I have enough practical programming knowledge to solve advanced problems. So, I'm here to help. And I'll be more than happy if I get some help from you as well ;)

Updated on October 09, 2022

Comments

  • OzrenTkalcecKrznaric
    OzrenTkalcecKrznaric over 1 year

    I'm trying to implement a pure CSS scrolling UL-LI table with fixed header.

    My requirements:

    • using table CSS (table, table-row, table-cell, table-header-group...)
    • all cells have to be list items (LI)
    • header has to be fixed when table content is scrolling
    • when table column changes width, appropriate header width should be changed

    Currently I have HTML:

    <ul class="testTable">
        <div class="testHeader">
            <li class="testRow">
                <span>ID</span>
                <span>Name</span>
                <span>Description</span>
                <span>Other details 1</span>
                <span>Other details 2</span>
            </li>
        </div>
        <div class="testBody">
            <li class="testRow">
                <span>1</span>
                <span>2</span>
                <span>3</span>
                <span>4</span>
                <span>5</span>
            </li>
            <li class="testRow">
                <span>1</span>
                <span>2</span>
                <span>3</span>
                <span>4</span>
                <span>5</span>
            </li>
        </div>
    </ul>
    

    ...and CSS...

    .testTable {
      display: table;
      margin: 0px;
      padding: 0px;
    }
    
    .testRow {
      display: table-row;
    }
    
    .testRow > span {
      list-style:none;
      display: table-cell;
      border: 1px solid #000;
      padding: 2px 6px;
    }
    
    .testHeader {
      display: table-header-group;
      /*position: absolute;*/
    }
    
    .testHeader span {
      background-color: #ccc;
    }
    
    .testBody {
      display: table-row-group;
    }
    

    Fiddle is here: http://jsfiddle.net/ozrentk/QUqyu/1/

    BUT! The moment I try to fix position of the header using position: absolute or fixed, the table falls apart. I tried several techniques, but to no avail. Also, there is zero to none examples how to do this using pure table CSS.

    This was close, but not exactly what I require.

    Is there a CSS guru that can help me?

    EDIT

    Now, why the hell did I want to display this list as a table?

    In my dynamic ASP.NET MVC driven site I have a number of places where I return unordered lists to the browser. Browser will then take this markup and display it to the reader. But the display format itself can actually depend on context, like users display-related preferences or the device format itself. CSS is used for the display formatting, as it should be. At last, if there is some display-light-n-magic-effect to be used, jQuery and/or a plugin should be used for that, and hopefully only for that.

    You see, I want my server to remain display-format agnostic. That is, I don't want my server to care about how the particular client want his display to look like. I don't want if-blocks that return unordered-list-items in one case and table-cells in the other. Of course I could have two return points, one which returns ul/li/span format and the other which returns table/tr/td, but that would be violating DRY principle.

    Another thing is that I'm using a really nice jQuery plugin that displays tabular data and can be fed with list-items, but not table markup. And I decided to stick with the plugin. because I like it, it's great and supports the way my site should work.

    I hope this sorts things out. You see, using one paradigm can be in contrast with the other. It turns out I have to give away general-tabular-data-semantics to have a DRY code.

    P.S. The more I think about this situation, the more it looks like a pragmatic, not a semantic problem.

    • Danield
      Danield over 10 years
      Why do you need to use tables if there are other ways of doing this?
    • andi
      andi over 10 years
      Your data looks like tabular data, so I think it's more semantic in this case to use <table> for it.
    • cimmanon
      cimmanon over 10 years
      Anything other than a table for this content would be a misuse of markup.
    • OzrenTkalcecKrznaric
      OzrenTkalcecKrznaric over 10 years
      I see lot of people are concerned of why am I using HTML list-items to display tabular data. I don't have time to explain everything now, but I promise I will do it tomorrow.
  • OzrenTkalcecKrznaric
    OzrenTkalcecKrznaric almost 11 years
    Ok, but how can I get this functionality then with CSS 'table-' attributes?
  • OzrenTkalcecKrznaric
    OzrenTkalcecKrznaric almost 11 years
    This is a problem because I'm using MVC and jQery plugin that relies on Ajaxed li's from server, which i then stuff as table cells. It doesn't work with td's. And as I understand, CSS gurus say table is so last year... hm...
  • André Dion
    André Dion almost 11 years
    Tables are intended for tabular data. You're trying to reinvent the wheel here in a very inappropriate way. If you have control over what your server is responding with, abstract your data into a layout-agnostic format such as JSON and then render it however you want.
  • OzrenTkalcecKrznaric
    OzrenTkalcecKrznaric almost 11 years
    I already told you that there is jQuery plugin that lays out items and expects LIs, not TDs. It fails on TDs. I can't change the plugin. What would you do in my place?
  • André Dion
    André Dion almost 11 years
    I would ditch the plugin as it doesn't seem to fit the needs of your application.
  • OzrenTkalcecKrznaric
    OzrenTkalcecKrznaric over 10 years
    Although it doesn't satisfy all the requirements, this is the best solution so far. One problem I found is when I add additional items after it's displayed, header gets misaligned.
  • Jo E.
    Jo E. over 10 years
    @OzrenTkalcecKrznaric I added the code to a function adjustHeader() and ran it on document.ready. If you add new code just add adjustHeader so that the headers will realign again. Check my edit
  • Martyn0627
    Martyn0627 over 10 years
    @OzrenTkalcecKrznaric was this of any use?
  • OzrenTkalcecKrznaric
    OzrenTkalcecKrznaric over 10 years
    I believe this is it. I'm sorry I haven't had time to take a look at this until now, but tomorrow if tests pass, I will incorporate it into the solution we're implementing.
  • Jo E.
    Jo E. over 10 years
    @OzrenTkalcecKrznaric you do know that the correct answer is NOT the correct answer right? :|
  • OzrenTkalcecKrznaric
    OzrenTkalcecKrznaric over 10 years
    Why do you think so? I gave the sample for testing and received no objections. And it worked for me.
  • Jo E.
    Jo E. over 10 years
    @OzrenTkalcecKrznaric haha ok. I thought the header should adjust to the content his code in this fiddle jsfiddle.net/QUqyu/25 with different values :) well its your question. you know what you need. Cheers!
  • OzrenTkalcecKrznaric
    OzrenTkalcecKrznaric over 10 years
    Great. Obviously we tested this code like this: http://jsfiddle.net/ozrentk/umNGj/1/. It behaves well when header labels are wide enough and there are whitespace candidates for page breaks. Otherwise, it gets ugly and I dont like it. I believe we failed while testing.
  • OzrenTkalcecKrznaric
    OzrenTkalcecKrznaric over 10 years
    Your solution passed the test, but we didn't count in the case when content is wider than the label and there are no whitespaces for page breaks. Then header gets misaligned, like this. Another problem is when content with ordinary whitespace gets wider than the label, and table is not in constant-width container, like this. Is there a possibility to solve these two problems?
  • Jo E.
    Jo E. over 10 years
    So the correct answer is incorrect? (Sorry if I misunderstood your comment my brain is tired at the moment) . . anyway I'm pretty sure its still incorrect because you said One problem I found is when I add additional items after it's displayed, header gets misaligned and the code of the checked answer alone can't do the dynamic requirement.
  • OzrenTkalcecKrznaric
    OzrenTkalcecKrznaric over 10 years
    Yes, the correct answer is as a matter of fact incorrect :( It happened because I was testing YOUR solution properly, and somebody else was tesiting Martyn0627 solution while I was 4 days on vacation. I have to try get things right with Martyn0627 solution now first.
  • Jo E.
    Jo E. over 10 years
    @OzrenTkalcecKrznaric check this fiddle.jshell.net/QUqyu/28/show (its the source of the fiddle iframe). I tried using your headers and data sample. In a big window its fine. But in a smaller window it could create problems. How small is the page window?
  • Muneem Habib
    Muneem Habib almost 9 years
    I am unable to set height of ul. How to set height of ul?
  • Johann
    Johann over 5 years
    If you resize the width of the table by resizing your browser, the header columns don't align with the data in the scrollable area. Not good.