I am not very familiar with HTML, CSS and Javascript, and yet I am tasked with creating a table system that will allow the user to resize table columns but also have said headers fixed to the top of the section the table is displayed in when the user scrolls the table.
I know this sounds confusing, so i created a Fiddle that can accurately represent what I have currently and hopefully where it needs to be updated.
I have settled on using the plugin JSColResizable found here:
http://www.bacubacu.com/colresizable/
and have set it up in the fiddle allowing the table to be resized. I have also wrapped the table in a div that only allows 300px height to be displayed at any time.
When the user mouses over the table division and scrolls down, the table headers scroll outside of the division making it difficult for users to relate which column was what. I simply need the table entries to continue to work the same way and scroll outside the div, yet allow the headers to remain static at the top of the div so that they can more easily be related to the columns.
If anyone has experience with this issue, I would greatly appreciate any help that can be offered.
You have to write a little jquery for it, and a class in css
Here is the Working Fiddle of what you want.
I have written some jQuery code for it you can use it.
jQuery
$(function(){
$.fn.fixMe = function () {
return this.each(function () {
var $this = $(this),
$t_fixed;
function init() {
$this.wrap('<div class="container" />');
$t_fixed = $this.clone();
$t_fixed.find("tbody").remove().end().addClass("fixed").insertBefore($this);
resizeFixed();
}
function resizeFixed() {
$t_fixed.find("th").each(function (index) {
$(this).css("width", $this.find("th").eq(index).innerWidth() + "px");
});
}
function scrollFixed() {
var offset = $(this).scrollTop(),
tableOffsetTop = $this.offset().top,
tableOffsetBottom = tableOffsetTop + $this.height() - $this.find("thead").height();
if (offset < tableOffsetTop || offset > tableOffsetBottom) {
$t_fixed.hide();
}
else if (offset >= tableOffsetTop && offset <= tableOffsetBottom && $t_fixed.is(":hidden")) {
$t_fixed.show();
}
var tboffBottom = (parseInt(tableOffsetBottom) );
var tboffTop = (parseInt(tableOffsetTop));
if (offset >= tboffBottom && offset <= tableOffsetBottom) {
$t_fixed.find("th").each(function (index) {
$(this).css("width", $this.find("th").eq(index).outerWidth() + "px");
});
}
}
$(window).resize(resizeFixed);
$(window).scroll(scrollFixed);
init();
});
};
$("table").fixMe();
});
Hope this helps you.
There is currently no native way for a table to have sticky headers and footers. All libraries that provide that functionality use divs or other tags to achieve that. That being said, I would probably not try to reinvent the wheel here. You could give SlickGrid a try - it is pretty stable and works great even with huge data-sets
Here is a pure CSS way of making the table scrollable without the use of a plugin or library, it uses table-layout:fixed to make the header fixed. Check out this example, meybe it is what you want.
.fixed_headers {
width: #table_width;
table-layout: fixed;
border-collapse: collapse;
Check out the full code of the tabe in this codepen link
https://codepen.io/tjvantoll/pen/JEKIu
Related
I'm using position:fixed to float some headers in my table when the user scrolls past the top, ala this method: http://css-tricks.com/persistent-headers/
Everything works great on regular pages, but whenever I have a table inside of another div or something with a fixed height and overflow:auto it blows up spectacularly.
What do I need to do to account for not just the page-wide scrolling, but also the scrolling of my container? And to account for scrolling past the 'top' of said container?
Thanks for any direction you guys can point me in.
Here's my existing code:
var mainheader = table.rows[0];
var tableHeight = table.getHeight();
var tableScroll = table.viewportOffset();
var headerHeight = mainheader.getHeight();
// TODO: If we're scrolling a subcontainer, we need to get the offset for that too! Somehow?
// If tableHeight < 1, it means our table his hidden right now, so skip it
if (tableHeight < 1)
continue;
// If we've scroll down past the very tip top of the table, but haven't yet scroll past the end of it, show our floating headers
if (tableScroll.top < 0 && tableHeight + tableScroll.top - headerHeight > 0)
{
table.floatingheader.style.display = '';
// Handle horizontal scrolling too!
table.floatingheader.style.left = (tableScroll.left + 1) + 'px'; // 1px offset for border
}
else
table.floatingheader.style.display = 'none';
NOTE: I have access to prototype.js, but do not have jQuery or any other 3rd party library. :/
I realize you're not using jQuery but you may want to look at this guys code on github and see how he implements it, then modify it for your purposes: http://webpop.github.com/jquery.pin/
I'm using a jQuery plugin from here http://www.tablefixedheader.com/ to make a snazzy table with a fixed heading, sorting and other cool features. Now, I've also looked at jqGrid, which looks ridiculously awesome, but we are doing some funky things with our data source and I don't think it is quite ready to play well with jqGrid.
Anyways, my bosses want the first column of the table I created to be fixed, so they can scroll on the x-axis, but still see the first column. How can I modify this plugin to provide this functionality?
Any help is greatly appreciated
Thanks
EDIT:
I tried adding:
th:first-child
{
position : relative;
}
td:first-child
{
position : relative;
}
As well as "fixed", but it seems to be more complicated than this simple solution...
Doing this does have an effect, it just isn't that pleasing. Making this change causes it to stay static on the left side, but I can't really scroll down, and the th doesn't really seem to work.
EDIT 2:
I've begun implementing the solution given below, although I am not entirely confident in my ability to tinker with this plugin. Anyways, here's the current state of tinkering:
I'll continue updating as I go...
I get an error that says this.offset.top is null or not an object... blah,
This code goes in the document.ready thing:
var currentTop = 0;
var currentLeft = 0;
var currentWidth = 0;
var currentHeight = 0;
var currentContent = "";
var currentDiv = "";
var currentID = "";
$('td:first-child').each(function (index) {
currentTop = $(this).offset.top;
currentLeft = $(this).offset.left;
currentWidth = $(this).width;
currentHeight = $(this).height;
currentContent = $(this).html();
currentID = "fixed_column_cell" + index;
currentDiv = "<div class=\"fixed_column_cells\" id=\"" + currentID + "\">" + currentContent + "</div>";
$('body').append(currentDiv);
$('#' + currentID).offset({ top: currentTop, left: currentLeft });
$('#' + currentID).width(currentWidth);
$('#' + currentID).width(currentHeight);
});
$('fixed_column_cells').css('position', 'fixed');
Currently stuck
Interesting problem. I don't think you'll find that the table cell (TD) element is going to want to behave this way for you. The thing to do might be to loop over all the td:first-childs and copy their content into divs of the same size that overlap the TDs. those divs will let you position them correctly.
I think you're running into a limitation of something with inherent table-cell behavior.
Pseduocode:
For each table cell in the first column
get top left position
get width and height
create new div of same size at same position
copy content into new div
set div to fixed pos
I know you said that you have already gotten the jquery library for the fixed header. There are however some libraries out there for fixed columns as well as headers. One that I have used is Fixed Table which allows you to set the left column as well as the headers to be fixed. Hope this will help you
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/172108
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.
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.
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.
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/)
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
I'm trying to achieve equal height columns on a 'responsive' website.
That means I'm using media queries to provide several layouts for one website depending on the size of the device and window.
I have 2 columns which need to have the same height. It's easy to achieve when the layout is fixed. I found dozens of scripts that do it and it works well.
However when I resize the browser window, that generated height doesn't change. So if the window is smaller, the height of the columns stays the same as before and the contents of the columns overflows. It's ugly.
Is there a way that generated height could change as I resize the window ?
Note : because of what's inside the columns I cannot use any CSS trick with backgrounds images etc. I really REALLY need both columns to truly have the same height at all times.
This question is already pretty old, but I didn't stumble upon a good solution for this myself until now.
A working solution would be a jQuery plugin that does something like setting the height of the columns to 'auto', measuring which one is the highest and set the columns to that height. Something along the lines of this:
$.fn.eqHeights = function (options) {
var $el = $(this),
$window = $(window),
opts = $.extend({}, $.fn.eqHeights.defaults, options);
if ($el.length > 0 && !$el.data('eqHeights')) {
$(window).bind('resize.eqHeights', function () {
$el.eqHeights(opts);
});
$el.data('eqHeights', true);
}
return $el.each(function () {
var children = $(this).find(opts.childrenSelector);
if (!(opts.minWidth) || opts.minWidth < $window.width()) {
var curHighest = 0;
children.each(function () {
var $el = $(this),
elHeight = $el.height('auto').height();
if (elHeight > curHighest) {
curHighest = elHeight;
}
}).height(curHighest);
} else {
children.height('auto');
}
});
};
$.fn.eqHeights.defaults = {
childrenSelector: '*',
minWidth: ''
};
You can see this in action here: demo#codepen.io
The plugin supports two options:
childrenSelector: (Optional) The selector by which children that should get equal height are picked. Defaults to *, so everything in your parent is brought to equal height. Set to > to pick only direct children or something else to get the desired effect.
minWidth: (Optional) The minimum viewport width above width the Plugin is working and calculates equal heights for the seleted children. Below their height is set to auto. This comes in handy if at some point your containers are laid out below each other and shouldn't have an equal height. Empty and inactive by default.
While this is working very good in all browser with which I tested, it is a very hackish solution, so maybe someone here can propose something better. I thought about copying the columns and their wrapper to hidden container in the document, but this isn't any less clean and produces a way bigger footprint.
My favorite trick to creating equal height columns that work almost everywhere is to set "overflow:hidden" on a wrapper div, and setting a huge positive bottom padding and a negative bottom margin on the columns themselves. Now the columns will always be the full height of the wrapper, whatever the height of the wrapper is.
Viz -
<div class="wrapper">
<div class="column"> Column one content </div>
<div class="column"> Column two content </div>
</div>
<style type="text/css">
.wrapper {
overflow:hidden;
}
.column {
margin-bottom: -2000px;
padding-bottom: 2000px;
}
</style>
Here's a JSFiddle example - http://jsfiddle.net/yJYTT/
I wrote a small jQuery plugin for this: http://github.com/jsliang/eqHeight.coffee/
Tested it on Chrome, Firefox and IE9 and it works for me.
This works great! To make it work inside of a responsive layout you'll need to add the # media query so it's only used on screen sizes "larger than" your break point. Otherwise, the sidebar color extends down into the main content on the tablet and phone views. Here's how it looks in a responsive stylesheet:
div.wrapper {
overflow:hidden;
}
.column {
background-color: rgba(193,204,164,.5);
padding:2%;
margin-bottom: -2000px;
padding-bottom: 2000px;
}
#media screen and (max-width:960px){
.column {padding-bottom:2%; margin-bottom:0px;}
}
I hacked the solution even further from boundaryfunctions's answer to take into consideration responsive layouts where the panels reflow above each other.
By checking each one against the first one's offset.top I was able to detect the orientation of the panels and resize their .panel-body element or assign an auto heigh for reflowed panels.
(function($) {
$.fn.eqHeights = function() {
var el = $(this);
if (el.length > 0 && !el.data('eqHeights')) {
$(window).bind('resize.eqHeights', function() {
el.eqHeights();
});
el.data('eqHeights', true);
}
var panels = el.find(".panel-body");
var fistoffset = panels.first().offset();
var curHighest = 0;
return panels.each(function() {
var thisoffset = $(this).offset();
var elHeight = $(this).height('auto').height();
if(thisoffset.top==fistoffset.top){
if (elHeight > curHighest) {
curHighest = elHeight;
}
}else{
curHighest = "auto";
}
}).height(curHighest);
};
}(jQuery));
$('.match_all').eqHeights();
Example here: http://bootply.com/render/104399
Some time after the question I know - but for reference - last time I had to solve this problem I hacked this jquery code to a plugin:
http://css-tricks.com/equal-height-blocks-in-rows/
obviously $(window).resize is the crucial part - as it'll re-conform the heights once the re-size has taken place. Taking it a step further I always meant to look into 'de-bouncing' the column reconform to help with performance:
http://paulirish.com/2009/throttled-smartresize-jquery-event-handler/
but never got that far.
I had the same problem. After some research I selected the faux column technique. Check this blog post that I wrote on how to make it work in a responsive design.
Responsive full height (equal height) columns using the faux columns technique
I have fixed div on bottom of my page that works well. I wonder if there is some simple way to make it "stop" on some place in page when user srolls down to it. I want it to remain fixed on bottom, until user scrolls down to some defined place on page and than stick it to the page and scroll like the rest of content. Any suggestions?
I tried setting something up on jsfiddle. While I was writing it up, I see that others have posted their alternatives. In case mine helps in any way: http://jsfiddle.net/PnUmM/1/
I set the position to relative in the CSS, calculate where it is on document load to keep the info aside and then set it to fixed.
var sticky_offset;
$(document).ready(function() {
var original_position_offset = $('#sticky_for_a_while').offset();
sticky_offset = original_position_offset.top;
$('#sticky_for_a_while').css('position', 'fixed');
});
$(window).scroll(function () {
var sticky_height = $('#sticky_for_a_while').outerHeight();
var where_scroll = $(window).scrollTop();
var window_height = $(window).height();
if((where_scroll + window_height) > sticky_offset) {
$('#sticky_for_a_while').css('position', 'relative');
}
if((where_scroll + window_height) < (sticky_offset + sticky_height)) {
$('#sticky_for_a_while').css('position', 'fixed');
}
});
I made this up for you: http://jsfiddle.net/XCYFG/1/.
$(document).ready(function() {
window._div1 = $('#div1'); //selector is expensive
window._window = $(window);
$(window).scroll(function(e) {
_div1.css("top",
Math.min(_window.height(),
window.scrollY + 100)
+ _window.height() - _div1.height() - 110);
}).scroll();
});
I have a plugin that does the opposite - it's in the flow of the webpage, and when the user scrolls past it, it gets fixed to the viewport. What it actually does though is apply a css class to the element, so you should be able to use it as is.
You can find the plugin here:
https://github.com/hanssonlarsson/jquery-fixedscroll
Then I would suggest you have your element in the flow of your webpage:
<div id="sometimesFixed">content</div>
With css:
#sometimesFixed {
position: fixed;
bottom: 0;
}
#sometimesFixed.scroll {
position: static;
}
And apply the plugin like so, in your JavaScript:
$('#sometimesFixed').fixedscroll({className: 'scroll'});
There is also a more general plugin, very new, called jquery-waypoints. The idea is to bind any code to "waypoints", points on the webpage where, when the user scrolls past them, some code is executed.
https://github.com/imakewebthings/jquery-waypoints
It's probably more optimized and a better fit than my plugin, but YMMV!