I am doing some manipulations on td tags using jQuery - I'm setting their width to be the same as the width of a td in another table (actually this is a fixed-header-table plugin, so I have to tables - one for the header and one for the main content. The corresponding ths and tds should have the same width).
The problem
All calculatinos work fine if I look at 'Computed style' in Chrome - the widths are set properly.
However, the real width is different than the 'computed width'!
See this picture of the computed style of the td element:
Now you may think that the actual width of the element will be 1+1+96+1+1 = 100, but it is 99!
I found this question - Computed column width is different than css declared width for column. How does browser decide width? and following the advice I used table-layout: fixed;. I used border-collapse: collapse;, either, in order to remove the space between the columns, so I don't expect this will be the problem.
The code
Here is a part of my code which sets the td widths:
$('thead th, tbody tr:first td').each(function(i, el){
i %= col_count; // I'm using because we go through 2 lines.
// It shows at which td we are. */
// col_width is an array with already calculated
// widths (using .outerWidth()) for each column */
// if the needed width is the same as the current td's,
// we can go to the next td */
if(col_width[i] == $(this).outerWidth()) return 1;
// the width to be set with substracted borders and paddings
// (here we don't have margins)
var new_width = col_width[i] - ($(this).outerWidth() - $(this).width());
$(this).width(new_width);
// I have also tried this, but the result was the same:
// $(this).css('width', new_width + 'px');
});
I should notice that thead th and tbody td are from different tables (as I mentioned before)
Another try
Another thing I tried - adding one pixel to each column - $(this).width(new_width + 1);. And on the demo page it worked. I copied the new code to the real page and on the almost all tables it worked! There was only one table where there was a problem.
It proved that the container (where the table was in), was not wide enough, so the scrollbar "made" the columns shorter. Of course, I expanded the container's width. The problem disappeared.
The real question
And while asking (writing) this long question, I solved it! So now it is changing a little bit: why?
Why when I added one extra pixel, the problem disappeared? Why the computed width is different from the real width?
Of course, I will be happy if you provide me another, more professional solution :)
JSFIDDLE (with already set widths, copied from the chrome console). Resize the result box to see the whole table properly.
The difference in computed width and real width is due to the use of border-collapse: collapse.
border-collapse: collapse
Borders are collapsed into a single border when possible (border-spacing and empty-cells properties will be ignored)
This reduces the width by 1px for each of the td elements, since each has had its border reduced to a single border.
Computed width is different from real width because every element has 1px border and 1 px white space in left and right, same as top and bottom.
Related
I have a <table> element with a lot of rows and a max-height attribute.
I need to find the real height displayed for the <tbody> element. Normally I can just take the difference between <table> height and <thead> height
var tbodyDispalyHeight = $("table").height() - $("thead").height();
This works unless horizontal content is too much and an horizontal scrollbar appears (and can't remove it because... I need it!). I should remove its height from tbodyDispalyHeight but... how can I do?
First problem: I don't really know when this bar is displayed
Second prolbem: Each browser implement scrollbar in a different way
Here is a JSBIN example to understand what I mean. Try to resize page horizontally until the scrollbar appears, there the dislayed tbody height should be lower...
Sounds like you are looking for the clientHeight.
(But this seems to be to easy.)
Have a look to MDN
The Element.clientHeight read-only property is zero for elements with no CSS or inline layout boxes, otherwise it's the inner height of an element in pixels, including padding but not the horizontal scrollbar height, border, or margin.
You may try:
$("table")[0].clientHeight
Currently you have your table with overflow:auto. But you could wrap it with a DIV with "overflow:auto". Then you can simply determine if you have a horizontal scrollbar by comparing the width of your div with the width of your table.
I have a fluid table that now needs a fixed thead. The issue being when you make the thead fixed the th-s don't respect the width of the tbody's td-s. The sizing of the columns are all handled with BootStrap. I have read quite a bit on this subject and seen two solutions. For argument's sake both will not work for me.
Lock down widths on the table, th, and tds. So no responsive widths - hence horizontal scrolling.
Use jquery to find the window width and return the height to the table. Then do a inner table scroll with a locked header. (example of found solution http://www.bootply.com/JnOYtO9xzn#)
What I would like to try is find the width on all the td and pass those width to the corresponding th (if I need to apply classes like th1, td1 so be it). Essentially I am trying to binding the td widths to the th. Also, on window width change update.
Table example: http://jsfiddle.net/u2xZU/165/ or https://jsfiddle.net/5hozvm5d/4/
This will ensure that the ths in thead always equal the widths of the tds in their column:
var timer;
$(window).resize(function() {
clearTimeout(timer);
timer= setTimeout(function() {
$('.table tbody tr:first td').each(function(idx) { //get the first row of tds
$('.table thead tr:first th').eq(idx)
.width($(this).width()); //set corresponding th width
});
},10);
}).resize();
Using setTimeout() prevents the function from running constantly as the window is resized.
Fiddle
It's pretty complicated. You might consider using the DataTable plug-in referenced here
Scrollable table with fixed header in bootstrap
I am trying to replicate the functionality of a basic HTML table with divs, css, and jQuery. The main requirement is to allow each row to start at the same location, regardless of where the other columns in the row end. They all need to start together.
I am using the code in this fiddle, and so far it is working great.
The problem is that due to the nature of my application, the width of my columns need to shrink to fit more columns. Many of these columns contain text from other languages, making it possible that the word is wider than the column width that I assign the column (I do this by dividing the width of the view (100%) by the number of columns).
The fiddle shows an example of this problem, a long word going wider than the column. While preserving all of the other functionality I have built up so far, is it possible to make it so that the div's width is at least X, but in the event that there is a really wide word, it expands and becomes as wide as that word?
It is perfectly fine if the content grows wider than the view width, meaning that if it had to grow to be 120% or whatever, scrolling to the side is no problem.
EDIT: Updated fiddle link
The only way I've found to do this is to use a bit of a hack.
1. Create a temporary div
//place in new element
$("body").append("<div id='testParent'></div>");
2. Add each word into the temp div as a span
var words = $(this).html().split(" ");
for(var i = 0; i < words.length; i++)
{
$("#testParent").append("<span>"+words[i]+"</span>");
}
3. Set the CSS:
div#testParent
{
display: inline-block;
width: auto;
}
div#testParent span{
display:block;
}
4. Get the temp div's width and set the parent div's width accordingly
var width = $("#testParent").width();
$("#testParent").remove();
if(width > $(this).width())
$(this).parent(".td-outer").width(width);
I applied the above code to the first element in your fiddle:
JSFiddle
I generally set fixed column widths via CSS with flawless results:
#tableID thead tr th:nth-child(1){width: 75px;}
#tableID thead tr th:nth-child(2){width: 75px;}
/* etc… */
But now I'm in a situation where I won't know the desired column widths until runtime. Here's an excerpt from the code I'm using to dynamically set the column widths:
var tr=$("<tr>");
var colArr=Home.ColDefs[this.statBatchType].colArr;
for(var i=0;i<colArr.length;i++){
var col=colArr[i];
tr.append(
$("<th>")
.html(col.title)
.css("width",col.width)
);
}
this.jqTHead.append(tr);
Sorry this code is a bit out of context but the bottom line is that I'm adding columns, represented by <th> elements, to a table header and setting each one's width.
What ACTUALLY happens, however, is that Firefox is treating the column width as a minimum and then automatically expanding the column width as the user expands his browser window. Consider a case where my JavaScript code sets the width of each column to 75px. Firefox will ensure each column is at least 75px wide, but if the user maximizes (or enlarges) his browser, provided there is sufficient room, each column will be automatically widened.
This is odd to me since the JavaScript code would seem to be the functional equivalent of what I was doing in CSS. Yet the CSS approach doesn't cause this odd behavior.
Any thoughts?
Fix the width of the <table> this will ensure the table does not take the available size and bump the layout.
table-layout: fixed; on the table does exactly this: columns never expand to fit their contents, and if you give the table itself a width, the extra space is divided equally. The contents of cells don't come into play at all.
I have a html table and I want to freeze the header row th tag for scrolling the data. How I can do that? Does I need to use the Dom?
Thanks !!
My solution is to use two tables and fix the column widths. The lower table is in a scrollable div and has no header.
If you take Accessibility seriously, two tables is not the way to go since it breaks rules.
There are ways to do it in pure CSS, but it is a headache to get it to work in all browsers. There are a few examples out on the net, but they do not all work 100% with IE without tweaks.
I am currently working on a CSS only version, this is getting pretty close: http://www.coderanch.com/t/431995/HTML-JavaScript/Table-with-fixed-header-scolling#1918825
Does not work in IE8rc1 yet, IE6/7 has a border issue and you have to live with the scrollbar looking different in FF vs IE.
With FireFox, you can put style="height: 200px; overflow-y: auto" But to have a pure CSS version compatible with all major browsers, I've use this example since IE doesn't support syles in tbody or thead.
I have come up with a solution that sort of combines two previously mentioned ones. It uses jQuery and two tables , one for the header and one for the content. The header table is set to a width of 100% with no column widths set. At the bottom of the content table there is a row defined to match the header table with the column widths set. This row is hidden so that it is not shown, but retains the column widths.
For this example I gave my header row an ID of 'Header1' and the bottom row and ID of 'Header2'. Also I wrapped the content table inside a div with an ID of 'scrollTable'.
I set styles in my CSS file for the scrollTable ID, see below:
#scrollTable {
height:250px;
overflow-x:hidden;
overflow-y:scroll;
}
Now for the jQuery part. Basically what I'm doing here is taking the widths of the bottom row columns and setting the header columns to match. I stretch the width of the last column of the header so that it fits over the top of the scroll bar. See code below:
$(document).ready(function(){
var maxWidth = $('#Header1').width(); // Get max row Width
$('#Header2 th').each(function(i) { // Set col headers widths to to match col widths
var width = $(this).width();
$('#Header1 th').eq(i).width(width);
});
var blankSpace = maxWidth - $('#Header1').width(); // Calculate extra space
$('#Header1 th:last').width( $('#Header1 th:last').width() + blankSpace ); // Stretch last header column to fill remaining space
});
I have tested this successfully on IE 6, 7 & 8, Firefox 3.0.1.4, Chrome 3.0.195.25, Opera 10, and Safari 3.2.2 on Windows XP.
I've done it in the past using CSS by defining a height for the <TBODY> tag on my table, and using overflow:auto. This was a while ago, and I think there were some compatability problems. I don't remember precisely what they were, but this solution may work for your problem.
the best solution (the one that scales with lots of data) is to use 2 tables like aaron said, the top table has the headers, and the bottom table should have the headers as the last row (or the footer), but with opacity of 0, so that you cannot see them.
This the headers at the bottom make the bottom table have the same column widths as the top table, making things line up. make sure you style both header and footer the same.
you will also have to create a seperate scroll bar for vertical scrolling to the right of the table, because otherwise the scroll bar will mess up your widths. add a scroll event listener to set the scrolltop of the table to the scrolltop of the scrollbar, and resize the scroll bar to be the same height as the table.
its pretty easy, actually =)
Create a single table as you normally would to meet accessibility concerns. Dynamically create a new table based on the thead using jQuery (copy the thead) and inject it into the page above the first table and give it the fixed position. It should stay in place while the rest of the table scrolls, but it will still remain accessible and work with JavaScript disabled.
Have you tried this plugin from JQuery ? http://plugins.jquery.com/project/floatobject
I believe this does what you want. Check out the demo # http://amirharel.com/labs/fo/float_demo.html
Cheers!