Freeze Header until Irrelevant (HTML, CSS and JS)
Asked Answered
D

4

18

I have a few different tables that I want to display vertically down a page. The trouble is, the different tables have different column headings.

In the picture, the dark border represents the viewport. The dotted red border is where the red header belongs but note that it is "frozen" to the top of the viewport. This is true until, in the second image, the green header begins to replace it. http://imagebin.org/172108Concept Picture

Does anyone know how this could be accomplished using very lightweight scripting (In other words, I don't want JQuery or something) and CSS. I have the advantage that I only need it to render on Webkit (which means some css3 is also an option). I don't care if the headers are not actually part of the html <table> - they must obviously just line up properly though.

Dissipation answered 12/9, 2011 at 8:22 Comment(8)
I don't know what iOS does but considering this is (in my opinion) an intuitive design it wouldn't surprise me if they copied my idea in advance :)Dissipation
have a higher z-index on the green bar than the red bar? Or Collision detection?Nephritic
@Nephritic Okay but that doesn't really help fix the headers to the top of the page once they're scrolled past... (it also won't look as nice since green will clearly just overlap red)Dissipation
I'm thinking that right now you are at a desert looking for water. I don't see this happening without javascript.Yapok
He said he doesn't want to have to import a js library. I think js is still in the question thoughBrechtel
@user828584 I didnt want to rule javascript out but I was more or less talking about js in general and I was thinking that jquery might be the way to go.Yapok
I just want lightweight - that's why no library...Dissipation
This might be a duplicate of #7370972Destefano
B
18

edit: http://jsfiddle.net/BCtP8/3/

There, I fixed the hiccuping text. When the header becomes fixed, I change the placholder's height. I also changed it to work with any header height, not just the one I had given them.

OLD POST Here you go man:

http://jsfiddle.net/BCtP8/

Sorry for any problems that might occur, I'm quite new to the whole web developing scene and I don't have the experience to predict what might happen.

I doubt this is the best or most efficient way to do it, so if you find better, please post it here so I can learn. Thanks.

Brechtel answered 12/9, 2011 at 12:0 Comment(13)
Dude - that's awesome. That's exactly the effect I want. I'll get back to you about how you accomplished it...Dissipation
Thanks, I'm going to bed now, but I'll check back tomorrow to make sure it's working.Brechtel
It does seem to have some hiccups with some offsetting of the text under the title when title becomes fixed ( not like i see it as a big obstable anyhow.. ) That is quite awesome.. (+1)Yapok
Ja, that hiccup is because when you change the way that the header is positioned (between static and fixed) it changes whether the header floats over text or not. Know how to fix that?Dissipation
Okay - The solution is to position the fixedheaders 'absolute' rather than 'static' and then put the text in p tags with padding-top of 40px. I also removed the .placeholder{display: none} which seems to have had an effect.Dissipation
Curiously, what is this effect called?Sieracki
Woah, you removed the placeholder? Did you edit the javascript? The point of the placeholder was to know where the header is supposed to be. If you calculate the header's position while it is fixed, it will always stay fixed because it will always be lower than the scroll position. I'll work on something now for the hiccup.Brechtel
Well, that should solve the problem. I guess that's what I was seeing in FF and Opera, but it was less noticeable in Chrome. If you need help using it, let me know.Brechtel
Maybe I missed something, isn't the solution supposed to work on tables?Humankind
@Hemlock, that's true, but I can't stand tables. There's no point in using themBrechtel
I did say I wasn't concerned whether the headers were part of the table - it's easy enough to put the headers into the div. @Walkerneo I didn't remove the placeholder I just removed the styling - I think on Opera with display:none; it was failing to figure out positioning. This is beautiful thanks dude.Dissipation
How would you do such a thing in an AngularJS directive?Pastel
Thanks so much for your solution! I'm still not able to understand what is the logic of this, even though I am looking at this code since 2 days. :-(Culhert
D
3

This will only be possible with Javascript - I can't think of a way of doing it simply with CSS.

The basis of the answer is to use position:fixed on the element. I would suggest cloning the thead of your table to attach in a fixed position at the top of the table, and then add an event listener for the scroll event and check the position of each table against the amount that has been scrolled.

I've put up an example on JSFiddle.

Destefano answered 12/9, 2011 at 14:30 Comment(4)
I find it somewhat weird that you answered 2 hours later with an answer that wasnt the same as the one that the OP had commented on with: That's exactly the effect I want. ..I'm gonna give you mental minus point for that. None the less your answer is quite interesting even though its not what the OP wants.Yapok
I don't think there's anything wrong with that. If anything, they could have said that their solution was an alternative. Regardless, they did contribute something very useful to this question, this site and its users, so +1.Sieracki
I don't have a problem with it. I have a few crits though; I don't like the transition between the headers because you see the wrong one until it covers the right one (Walkerneo's solution looks good in that respect). I also need something lightweight and so didn't want a library like JQuery. I will keep your solution in mind though if I work on something I can use JQuery in. Also, I told the guy whose question I duplicated about this thread, thanks.Dissipation
@Lollero - I started answering the question when it was unanswered, got sidetracked, came back to it and finished it off a bit later. I only noticed afterwards that there was another answer!Destefano
H
1

For what it's worth:

There are a couple of answers here but I don't think they actually answer the question. They don't operate on table headers (thead elements) or they use 3rd party libraries. There are some subtle issues with lifting a thead out of the table - the largest of which is that the cells will collapse down if the header text is wider or narrower than the data in the tbody.

Here is my solution that solves the problem without any libraries and working on table headers. It makes no assumptions about the styling of the table, or the size of the headers; everything is calculated. Only tested in Chrome per the requirements of the OP.

Script:

function initFloatingHeaders() {
  var tables = document.querySelectorAll('table.float-header');
  var i = tables.length;

  while (i--) {
    var table = tables[i];
    var wrapper = document.createElement('div');
    wrapper.className = 'floating-header';
    var clone = table.cloneNode(true);
    wrapper.appendChild(clone);
    table.parentNode.insertBefore(wrapper, table);

    var thead = table.querySelector('thead');
    wrapper.style.width = thead.scrollWidth + 'px';  
    wrapper.style.height = thead.scrollHeight + 'px';
    wrapper.style.left = table.offsetLeft + 'px';     
  }

  window.addEventListener('scroll', function() {
    var headers = document.querySelectorAll('div.floating-header');
    var bodyHeight = document.body.offsetHeight;
    var i = headers.length;
    while (i--) {
      var header = headers[i];
      var tableBounds = header.nextSibling.getBoundingClientRect();
      if (tableBounds.top < 0 && tableBounds.bottom > 0) {
        header.style.display = 'block';
      } else {
        header.style.display = null;
      }
    }
  }, false);
}

Tables should have the class float-header applied and initFloatingHeaders should be called on load or documentReady. Example: http://jsbin.com/ulusit/2 (Old example with bad transitions: http://jsbin.com/ulusit/)

Humankind answered 13/9, 2011 at 1:8 Comment(3)
I wasn't overly concerned by the use of thead floating but I am impressed by your effort and I appreciate it. Your solution suffers the same problem as chris5marsh's though - I just don't like the header transition.Dissipation
@Destefano You're right. Sorry to lump you in there. What yours does, though, is use jQuery which the OP did not want.Humankind
Holy smokes! This is terrific. I have been searching for a solution that did not require fixed column widths, and this is it! Thank you very much.Gotham
R
0

It's possible to achieve the result in pure CSS with position:sticky 🤞

body, dl, dt, dd {
  margin: 0;
}
dl {
  position: relative;
}
dt, dd {
  padding: 1rem;
}
dt {
  background-color: #ddd;
  position: sticky;
  top: 0;
  box-shadow: 0 0 0.25rem rgb(0 0 0 /10%);
}

I got a pen 4 years ago. You can jump in to see how it works: https://codepen.io/patrickliu/full/MGPNgJ

Revere answered 6/6, 2022 at 3:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.