8

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.

Community
  • 1
  • 1
OzrenTkalcecKrznaric
  • 5,535
  • 4
  • 34
  • 57

3 Answers3

5

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.

Community
  • 1
  • 1
André Dion
  • 21,269
  • 7
  • 56
  • 60
  • Ok, but how can I get this functionality then with CSS 'table-' attributes? – OzrenTkalcecKrznaric Jul 31 '13 at 14:55
  • 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... – OzrenTkalcecKrznaric Jul 31 '13 at 14:58
  • 1
    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. – André Dion Jul 31 '13 at 15:01
  • 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? – OzrenTkalcecKrznaric Jul 31 '13 at 15:03
  • 1
    I would ditch the plugin as it doesn't seem to fit the needs of your application. – André Dion Jul 31 '13 at 16:02
5

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

Jo E.
  • 7,822
  • 14
  • 58
  • 94
  • 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. – OzrenTkalcecKrznaric Aug 14 '13 at 07:23
  • @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 – Jo E. Aug 14 '13 at 09:48
  • @OzrenTkalcecKrznaric you do know that the correct answer is NOT the correct answer right? :| – Jo E. Aug 20 '13 at 10:45
  • Why do you think so? I gave the sample for testing and received no objections. And it worked for me. – OzrenTkalcecKrznaric Aug 20 '13 at 15:45
  • @OzrenTkalcecKrznaric haha ok. I thought the `header should adjust to the content` **his code** in this fiddle **http://jsfiddle.net/QUqyu/25/** with **different** values :) well its your question. you know what you need. Cheers! – Jo E. Aug 21 '13 at 04:46
  • Great. Obviously we tested this code like this: [http://jsfiddle.net/ozrentk/umNGj/1/](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 Aug 21 '13 at 09:28
  • 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. – Jo E. Aug 21 '13 at 09:47
  • 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. – OzrenTkalcecKrznaric Aug 21 '13 at 09:55
  • @OzrenTkalcecKrznaric check this http://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? – Jo E. Aug 21 '13 at 10:11
  • I am unable to set height of ul. How to set height of ul? – Muneem Habib Jun 23 '15 at 08:15
  • 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. – Johann Dec 12 '18 at 10:48
2

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.

Martyn0627
  • 741
  • 1
  • 4
  • 17
  • @OzrenTkalcecKrznaric was this of any use? – Martyn0627 Aug 18 '13 at 07:57
  • 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. – OzrenTkalcecKrznaric Aug 18 '13 at 20:45
  • 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](http://jsfiddle.net/ozrentk/umNGj/2/). Another problem is when content with ordinary whitespace gets wider than the label, and table is not in constant-width container, like [this](http://jsfiddle.net/ozrentk/umNGj/3/). Is there a possibility to solve these two problems? – OzrenTkalcecKrznaric Aug 21 '13 at 09:40