aligning columns in two separate (but related) html tables - html

I'm implementing a table with a fixed header using this kind of setup:
<div style="padding-right:18px"><!-- to account for the scrollbar on the other div -->
<table id="head">
<tr>
<th>Col 1</th>
<th>Col 2</th>
</tr>
</table>
</div>
<div style="height:400px; overflow-y:scroll">
<table id="body">
<tr>
<td>Val 1a</td>
<td>Val 2a</td>
</tr>
<tr>
<td>Val 1b</td>
<td>Val 2b - this cell is wide</td>
</tr>
</table>
</div>
I'm using dojo thus to make the column widths the same after the page loads:
dojo.addOnLoad(function(){
var $bodyRow = dojo.query('#body tr')[0];
var $headRow = dojo.query('#head tr')[0];
dojo.forEach($bodyRow.cells, function(item, index){
var w = item.offsetWidth;
dojo.style($headRow.cells[index], 'width', w + "px");
});
});
Unfortunately, although the widths are adjusting, they're not adjusting enough to line up. Anyone know why this isn't working? or a better way?
Note: this must work in IE6.

offsetWidth gets the width of the element, padding and borders.
setting the width using the element style, you are only setting the width of the element
so each column will be off by the sum of all the horizontal borders and paddings of preceding columns
try this
dojo.addOnLoad(function(){
var $bodyRow = dojo.query('#body tr')[0];
var $headRow = dojo.query('#head tr')[0];
dojo.forEach($bodyRow.cells, function(item, index){
var w = dojo.style($bodyRow.cells[index], 'width');
dojo.style($headRow.cells[index], 'width', w + "px");
});
});
-Enrico

Have you tried setting the widths in CSS or do you need to implement column resizing and all that jazz? I'm not sure that javascript is the answer here.
Try something like:
th, td { width: 50%; } // get 2 equal width columns in both tables
PS, in the 'body' table it would be better to use <td> elements as <th> is meant for column/row headings. Also makes it easier to differentiate when you are writing your CSS.

The widths are dynamic and should be rendered based on the content. For some columns, I could add a suggestion in css, but in the end, I need to adjust the sizes to what's actually been rendered in the browser.
(In the real code I am using s. I just forgot to change with I copied-and-pasted for my toy example above.)

Related

How to contain the header within table width when the fields are dynamic

I have a table with few rows and recurring header. The number of columns is not fixed and can vary. The header is a single cell spanning across the whole table. When a column is taken away from the table the header width is not recalculated and exceeds the width of the table. How can I contain the header inside the table with as little code as possible. If possible I would prefer to not use JS.
I have recreated the problem here in JSFiddle.
<table>
<colgroup>
<col style="width:10px">
<col style="width:20px">
<col style="width:30px">
</colgroup>
<tr>
<th colspan=100>
numbers
<tr>
<td>1<td>2<td class="hide">3</td>
<tr>
<td>1<td>2<td class="hide">3</td>
<tr>
<th colspan=100>
numbers
<tr>
<td>4<td>5<td class="hide">6</td>
</table>
td{
border: 1px solid grey;
}
table {
border: 1px solid black;
border-collapse:collapse;
table-layout: fixed;
}
els = document.getElementsByClassName("hide")
for(var i=0;i<els.length;i++)
els[i].style.display = "none";
Edited
I am not using JQuery(I used it for shorter example). The columns are concealed with JS(on click a column disappears). The example there is as close to my problem as it gets. The headers are repeated every ~100 rows (in fact there is <tr><th>Index:</th><th>Item:</th></tr>.
http://jsfiddle.net/arhws/6/
<table>
<caption>
Numbers
</caption>
[...]
Try resetting the colspan based on the visible cells:
$(".hide").hide();
var rowlength = $( "tr:nth-child(2) td" ).length;
var hidelength = $( "tr:nth-child(2) td.hide" ).length;
$("th").attr("colspan",rowlength-hidelength);
For anyone interested in how I did it in the end:
http://jsfiddle.net/7sXv4/14/
I have added the same class "hide" to the col so that when the column is hidden the col tag is not displayed anymore.
I made the colspan on tr the exact maximum number of columns.
I have added a width to the table of the first column (minimal width possible)
BTW I know the fiddle does not work in Chrome but for some reason in my application it works both in Chrome and FF.

How can a subtable inherit and line up with parent table's columns?

I have a table nested inside another table. The thead of the outside table has 10 columns. The first td of every tr inside the tbody is a normal cell.
The cells 2 through 10 can actually have several sub-rows that are dynamically created. I need these 9 (1 through 9) to line up with the parent table's columns 2 through 10. I'm not sure how to achieve this without changing my overall structure to be a single table with a dynamic rowspan on the first column.
This is overtly complicated to visualize, so here's a JSFiddle to help. That sub-table should span all the way to column '10' of the parent table.
http://jsfiddle.net/23p34/1/
Before I go and switch up my entire architecture so far, I wanted to at least ask if my approach could feasibly work. Perhaps overall, it'd be easier if I did just switch.
You could do something like this: http://jsfiddle.net/23p34/4/
var subTables = $("table").find("table");
var headerColumns = $("table:first").find("tr:first").find("th:not(:first)");
var widths = new Array();
for (i = 0; i < 9; i++){
widths.push($(headerColumns.get(i)).width());
}
$.each(subTables.find("tr"), function(){
var row = this;
var rowCells = $(row).find("td");
for (x = 0; x < 9; x++){
var td = rowCells.get(x);
if ($(td).width() > widths[x]){
widths[x] = $(td).width();
}
}
});
$.each(headerColumns, function(index){
$(this).width(widths[index] + "px");
});
$.each(subTables.find("tr"), function(){
var row = this;
var rowCells = $(row).find("td");
$.each(rowCells, function(index){
$(this).width(widths[index] + "px");
});
});
Make sure to add colspans to the outer table's cells.
<body>
<div>
<table>
<thead>
<tr>
<th>1</th>
<th>2</th>
<th>3</th>
<th>4</th>
<th>5</th>
<th>6</th>
<th>7</th>
<th>8</th>
<th>9</th>
<th>10</th>
</tr>
</thead>
<tbody>
<tr>
<td>test</td>
<td colspan="9">
Basically you loop through all cells and determine the largest width for that column. Then you go back and set all cells in that column to match the largest width. Its not going to be perfect, so you would need to tweak it a bit. It also isn't the prettiest option. I think you would probably be better served with moving it to one table.

HTML table like `ls`

Is it possible to create an HTML/CSS Table that is formatted like the POSIX ls? That is, entries are displayed alphabetically in columns, where the number of columns is dependent on the width of each column?
For example, see in this screenshot how the columns are only as wide as necessary. The fourth column is much wider than than the others, and the third column is narrowest of all as all its file names are short. There are four columns in this screenshot but there could be more if the terminal were wider and fewer if it were narrower.
The number of columns varies based on the width of the terminal and the exact file names in the listing. As more file names are shown, more columns are added. Once the right side of the terminal is reached, ls makes the columns taller. If there are lots of short file names there could be a lot of columns, whereas if the file names are long there would be fewer.
Well, the good-news is that browsers "sorta" support this with table elements and table-layout:auto rendering (this should be the default, and is after an appropriate CSS reset). The bad news is it's only "sorta".
For starters, you must pick the number of columns and render the HTML table such that the items are in the correct column - this includes all sorting! Then, if you don't over-constrain the width of any column in the table, make sure the table is table-layout:auto, and set the width of the table then the results should be similar to that of ls - that is, the columns will "automatically adjust width" based on the content.
To get an "identical" result to ls would require something more heavy-handed, such as using a fixed-font (like that used in a terminal) and manually calculating the column widths (like ls does), perhaps in a <pre> element. CSS/HTML has limitations that ls simply avoids by doing layout calculations itself against a fixed-width terminal.
This is a table as any other. Unless there is something else you didn't specify. You may do something like this
<table>
<colgroup style="width:22%"></colgroup>
<colgroup style="width:25%"></colgroup>
<colgroup style="width:25%"></colgroup>
<colgroup style="width:25%"></colgroup>
<colgroup style="width:3%"></colgroup>
<thead>
<tr>
<th>Closed Day</th>
<th><span>|</span>Is this a paid day?</th>
<th><span>|</span>Last updated date</th>
<th><span>|</span>Last updated by</th>
<th><span>|</span>Current?</th>
</tr>
</thead>
<tbody>
<tr>
<td>08/10/2013</td>
<td>No</td>
<td>02/12/2014</td>
<td>c-jsmith</td>
<td>Yes</td>
</tr>
<tr>
<td>09/01/2013</td>
<td>Yes</td>
<td>02/12/2014</td>
<td>c-kkearney</td>
<td>Yes</td>
</tr>
<tr>
<td>12/25/2013</td>
<td>Yes</td>
<td>01/12/2014</td>
<td>c-jjohnson</td>
<td>Yes</td>
</tr>
<tr>
<td>12/26/2013</td>
<td>Yes</td>
<td>02/01/2014</td>
<td>c-gthompson</td>
<td>Yes</td>
</tr>
</tbody>
Using a table similar to above and the script below with some modifications you should be able to limit the amount of rows and stack to the right with positioning.
<script>
function tableWrap() {
var maxRows = 10;
var table = document.getElementById('myTable');
var wrapper = table.parentNode;
var tableRows = table.rows.length;
var height = 0;
if (tableRows > maxRows) {
for (var i = 0; i < maxRows; i++) {
height += table.rows[i].Height;
}
wrapper.style.height = height + "px";
}
}
</script>
I managed to get something started with javascript:
var outer = document.getElementById("outer");
function setColumns(n) {
var style = outer.style;
style.columnCount = n;
style.MozColumnCount = n;
style.WebkitColumnCount = n;
}
var i = 1;
while (outer.scrollWidth <= outer.offsetWidth) {
setColumns(++i);
}
setColumns(i - 1);
http://jsfiddle.net/jEq4R/2/
It doesn't handle the width, yet, but it at least gives a good number of columns.
EDIT: works in firefox but not webkit
Adjust the width in this jsfiddle and see http://jsfiddle.net/sajith/DdqfA/
HTML
<div>column</div><div>column</div><div>column</div>
<div>column</div><div>column</div><div>column</div>
<div>column</div><div>column</div><div>column</div>
<div>column</div><div>column</div><div>column</div>
<div>column</div><div>column</div><div>column</div>
<div>column</div><div>column</div><div>column</div>
CSS
div {
width: 200px;
display: inline-block;
}

How do I let width of table determine width of entire page

I have an HTML page that contains a table. The table is dynamically generated from a database on the server side. I would like the width of the table to determine the width of the entire page. That is, other block elements above and below the table should take on the same width as the table.
I do not want to use fixed widths. I prefer a pure css solution but if fudging things with JavaScript is the only way, then so be it. I need fairly wide browser support.
I tried using a div with display: inline-block around the table and the other block elements. The idea was to have the div "shrink to fit" around the table and thereby set the width of the other elements. This did not work and I think it's because the div does not know which of the elements inside should be the "master", determining the width for the other elements.
Edit: Added a fiddle: http://jsfiddle.net/5Z3ru/. In this example, I would like the paragraph above the table to be the same width as the table (not the other way around). I do not want to use a fixed width for the table or paragraph.
Edit 2: Conceptually, what I am looking for can be imagined as if the table is rendered alone in a separate document. Then, the rendered table is inserted into a new document and the width of the rendered table is used for setting the width of the new document. So, nothing in the final document affected the rendering of the table, and the table width becomes the only factor in deciding the width of the final document.
Lets call the initially rendered width of the wrap as X.
wrap, when initially rendered and without any width specified, will automatically fill all available horizontal space on the screen available to it. In this case, the entire width of the document. Therefore, in this case, X = 100% of the document.
You cannot make X less than 100% without specifying a new width (aside from methods that are of no use here).
Using CSS, you can make the table the only deciding factor to the expansion of wrap, as it will naturally expand to include a table that grows beyond X.
To make the wrap shrink below X, to a dynamic value (the natural width of the table) you will have to use Javascript. This will mean that the document will load, then the table width is ascertained (var w = $( "table" ).width()), then that width is applied to wrap ($("#wrap").css("width":w)).
With a wrap div around both the table and the text, you would need to have reverse inheritance and have the wrap div inherit the width of the table. Unfortunately, though many of us want it, there is no reverse inheritance. Alternatively, you would just go straight to having the <p> element inherit the width of the table naturally, which is also impossible from what I know. The only way to inherit width is from the parent, so in this situation the parent of the <p> would have to be the table, which wouldn't work even if the table wasn't generated dynamically because putting the <p> element in table would affect its width and you'd end up telling the <p> element to inherit its own width. Reverse inheritance and a parent selector are in high demand but don't exist. I think the only way you can do this is with JavaScript.
I know of no way to do it only in HTML and CSS, so cheers to anyone who figures it out. I am intrigued by this question and I wonder if there is something I'm missing.
I believe JavaScript is the way to go.
I believe a previous answer here is correct already: treboothjd6.
Conclusion:
lt is not possible.
workarounds
Setting width
Regarding tables this is very unfortunate and in my opinion, this lack of css solution is a leading cause of css mess, because most css developers will set a width for either the entire table or its columns. This can cause inconsistencies with spacing and requires rigid strictness going forward with all further dimensions. Then use that same width for the other desired elements for better design constraints.
Getting computed table width with javascript
There is another solution which is less used, is a viable solution, but it does require javascript.
Use javascript to place a className: eg: .jsEnabled or use equivalent - modernizr.
In your css, hide the parent class, to prevent flashing, flickering, glitches of delayed browser rendering between previous width and desired width.
In Javascript detect the computed width of the table. The table visibility is hidden, not none, so the browser still can detect its taken up width. Then use that width to dynamically set the desired other elements, ie the parent.
Now use javascript to reshow the parent element.
Since most websites depend on js now anyway this solution provides the dynamic nature you are looking for with less css messiness going forward without having to adhere to a cascade of dimensions predetermined by a chosen width as in previous workaround.
Example codepen:
https://codepen.io/inspiraller/pen/bGEeNeQ?editors=1111
js
const tablewidth = (strParentSelector, strTableSelector) => {
const getWidth = $elem => {
const computed = window.getComputedStyle($elem);
return computed.getPropertyValue('width');
};
const setWidth = ($elem, width) => {
$elem.style.width = width;
};
const show = $elem => {
$elem.style.visibility = 'visible';
}
const $parent = document.querySelector(strParentSelector);
const $table = document.querySelector(strTableSelector);
const width = getWidth($table);
setWidth($parent, width);
show($parent);
};
const enableJS = () => {
document.body.classList.add("jsEnabled");
}
const docReady = fn => {
if (document.readyState === "complete" || document.readyState === "interactive") {
setTimeout(fn, 1);
} else {
document.addEventListener("DOMContentLoaded", fn);
}
}
enableJS();
docReady(() => {
tablewidth('.someParent', '.tableGeneric');
});
css
.jsEnabled .someParent {
visibility: hidden;
}
html
<section class="someParent">
<table class="tableGeneric" summary="Test Diary">
<thead>
<tr>
<th class="thtd thtd--date">
DATE
</th>
<th class="thtd thtd--time">
TIME
</th>
<th class="thtd thtd--cat_dudar_its_friend">
CAT
</th>
<th class="thtd thtd--subcat">
SUBCAT
</th>
</tr>
</thead>
<tbody>
<tr>
<td class="thtd thtd--2018 ">2018</td>
<td class="thtd thtd--0100 ">0100</td>
<td class="thtd thtd--sup ">sup</td>
<td class="thtd thtd--zinc,_mag,_niacn_200mg ">zinc, mag, niacn 200mg</td>
</tr>
<tr>
<td class="thtd thtd--2018 ">2018</td>
<td class="thtd thtd--0200 ">0200</td>
<td class="thtd thtd--feel ">feel</td>
<td class="thtd thtd--tired ">tired</td>
</tr>
<tr>
<td class="thtd thtd--2018 ">2018</td>
<td class="thtd thtd--0300 ">0300</td>
<td class="thtd thtd--sup ">sup</td>
<td class="thtd thtd--zinc,_mag,_niacn_200mg ">zinc, mag, niacn 200mg</td>
</tr>
<tr>
<td class="thtd thtd--2018 ">2018</td>
<td class="thtd thtd--0400 ">0400</td>
<td class="thtd thtd--sup ">sup</td>
<td class="thtd thtd--zinc,_mag,_niacn_200mg ">zinc, mag, niacn 200mg</td>
</tr>
<tr>
<td class="thtd thtd--2018 ">2018</td>
<td class="thtd thtd--0500 ">0500</td>
<td class="thtd thtd--feel ">feel</td>
<td class="thtd thtd--tired ">tired</td>
</tr>
<tr>
<td class="thtd thtd--2018 ">2018</td>
<td class="thtd thtd--0630 ">0630</td>
<td class="thtd thtd--sup ">sup</td>
<td class="thtd thtd--zinc,_mag,_niacn_200mg ">zinc, mag, niacn 200mg</td>
</tr>
<tr>
<td class="thtd thtd--2018 ">2018</td>
<td class="thtd thtd--0700 ">0700</td>
<td class="thtd thtd--sup ">sup</td>
<td class="thtd thtd--zinc,_mag,_niacn_200mg ">zinc, mag, niacn 200mg</td>
</tr>
<tr>
<td class="thtd thtd--2018 ">2018</td>
<td class="thtd thtd--0800 ">0800</td>
<td class="thtd thtd--feel ">feel</td>
<td class="thtd thtd--tired ">tired</td>
</tr>
</tbody>
</table>
<p>This text should nicely be the same width as the table. If it doesn't happen to be the same width as the table then this is not what I want. I reiterate, as its very important that this paragraph text does indeed wrap at the same width as the table.
</section>
React using Typescript and forwardRef example
https://codepen.io/inspiraller/pen/abdZvzM?editors=1111
What about set tablels with relative?
table{
width:100%;
}
Made a fiddle with a fixed body width and a table inside with 100% width.
I've added
table {
width:19.85em;
}
#wrap p {
width:19.85em;
}
EMs are similar to PX but they are scalable. For that reason I use them for pretty much everything. I found the width of the table in EMs (and made it that just in case) and set that as the width of the wrap. You could remove the wrap and give the <p> a class with this width if you want. And you don't really need the width of the table to be 19.85em, but it's a good reminder of what the width of the <p> or wrap should be. Anyway, in any situation like this, try using EMs instead of PX because they're scalable.

Adding last row of table rowspan attribute doesnt work

I'm using twitter bootstrap but i dont think that makes a difference to what I'm doing.
Basically I have a table. I'm testing the length of an enumerable that is filling the table and the last row i want to "pad" to the full length of the container i.e. if its less than 10 rows i want to add a row that has a rowspan that is 10 - item.count... however, its just rendering a blank row... is this intentional or am i doing something wrong? Here is a fiddle:
http://jsfiddle.net/L46FX/37/
and here is a table... any help would be appreciated...
<table class="table table-bordered">
<thead>
<tr>
<th>#</th>
<th>First Name</th>
<th>Last Name</th>
<th>Username</th>
</tr>
</thead>
<tbody>
<tr>
<td rowspan="2">1</td>
<td>Mark</td>
<td>Otto</td>
<td>#mdo</td>
</tr>
<tr>
<td>Mark</td>
<td>Otto</td>
<td>#TwBootstrap</td>
</tr>
<tr>
<td>2</td>
<td>Jacob</td>
<td>Thornton</td>
<td>#fat</td>
</tr>
<tr>
<td>3</td>
<td colspan="2">Larry the Bird</td>
<td>#twitter</td>
</tr>
<tr>
<td colspan="4" rowspan="10">
this should be a row that is 10 rows long...
</td>
</tr>
</tbody>
</table>
EDIT:
As suggested, javascript seems to be the answer... this is what I came up with, it tests the line-height due to the fact my tables are in a tab so the height attribute came back with 0 because they weren't currently in a active tab..
$('.stretch').each(function () {
var rows = $(this).rowCount();
if (rows < 10) {
var lr = $(this).children('tbody').children('tr:last');
var bg = lr.children('td').first().css('background-color');
var ht = lr.css('line-height').replace('px', '') * (10 - rows);
var row = '<td colspan="' + lr.children('td').length + '"></td>';
$(this).children('tbody').append('<tr style="height: ' + ht + 'px; background-color: ' + bg + '">' + row + '</tr>');
}
});
Also to clarify what I was doing... I really hate it when a table renders 1 row, it just looks so ugly :) I tend to put action items for the table in the footer so this attempts to fill the container with a giant row and anchors the tfoot to the bottom of the parent or very close to it....
Not sure I completely understand... but here is what I think...
rowspan is used incorrectly in your code. It will only increase the height of a tr if the column has rows beside it. See this example: http://reference.sitepoint.com/html/th/rowspan
If you want to expand the last row to 10x its size, you could use some script as follows:
var a = $( "tr" ).last().height();
$( "tr" ).last().css('height',a * 10 + 'px');
Here's the demo: http://jsfiddle.net/L46FX/38/
You mean the CELL should be 10 COLUMNS long. You are mixing up the meanings of "row" and "column" (col) and also "row" and "cell".
<tr>
<td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td><td>10</td>
</tr>
<tr>
<td colspan="10">this should be a CELL that is 10 COLUMNS long...</td>
</tr>
Of course your table first needs to have 10 columns and yours does not.
I didn't understand real problem, but it you want last table cell <td> spans 10 rows, than you used it incorrectly.
This is not a valid html. If you give rowspan into last row table-cell than, there is no space to spans table-cell.
ROWSPAN: This attribute specifies the number of rows spanned by the current cell. The default value of this attribute is one ("1"). The value zero ("0") means that the cell spans all rows from the current row to the last row of the table section (THEAD, TBODY, or TFOOT) in which the cell is defined.
Read table specification
See this