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;
}
Related
I am creating an dynamic HTML table as shown in the attached screen-shot.
User can select multiple versions ( v1, v2 etc) and I need to show the comparison between V0 and the selected versions ( currently in image, we are showing V0 vs v1). Now the problem is: there is too much space between the column if we select just one version to compare with.
Can we have a way to increase font-size and reduce column spacing if we just have 2 version to compare and adjust it as the no. of versions, to be compared with, increases?
As far as I know, media queries can be applied based on the screen sizes but it does not apply in my case.
You can change the font size based on the number of column using JavaScript.
I have created sample Snippet below, have a look.
var fontSize = 36;
var fontSizePerColumn = 12; // default 3 columns;
if($("table tr").children("td").length<=3){
fontSize = 36;
}else{
fontSize -= (($("table tr").children("td").length-3)*fontSizePerColumn);
}
if(fontSize <=12)
fontSize = 12;
$("table tr").children("td").css("font-size", fontSize+'px');
table tr td{
font-family:calibri;
font-size:36px;
border:1px solid black;
border-collapse:collapse;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="table1">
<tr>
<td width="50%">Column 1</td>
<td width="25%">Column 2</td>
<td width="25%">Column 3</td>
<td width="25%">Column 3</td>
</tr>
</table>
You can check jsfiddle here.
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.
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
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.)
I have a number of tables with the same columns and it would look a lot nicer if they shared the same column widths. Is such a thing possible? Putting them in the same table with some rows with no borders between them isn't an option.
Edit: Yeah I'm aware I can fix the widths myself but I was hoping for something that would tie in to the browser's column width algorithm but simply tied two or more tables together for the purpose of doing that layout.
I didn't think such a thing was possible but I thought I'd check just in case.
If you're not too picky about which column widths the browser comes up with, as long as they're the same across different tables, you can use the CSS table-layout property (supported by all major browsers) in combination with a table width:
table {
table-layout: fixed;
width: 100%;
}
This causes all columns (without a specified width) to have the same width, regardless of the table content.
It's only possible if you can fix-width the columns. If you can set a fixed width then some css like this should work:
td {
width: 25%;
}
You can customize each columns width like this:
<table>
<tr>
<td class="col1">...</td>
<td class="col2">...</td>
</tr>
</table>
...
<table>
<tr>
<td class="col1">...</td>
<td class="col2">...</td>
</tr>
</table>
and then specify the widths like this:
.col1 {
width: 25%;
}
.col2 {
width: 75%;
}
Here's a small JavaScript I made to resize cells to make them equal width in all tables on a page.
function resizeTables()
{
var tableArr = document.getElementsByTagName('table');
var cellWidths = new Array();
// get widest
for(i = 0; i < tableArr.length; i++)
{
for(j = 0; j < tableArr[i].rows[0].cells.length; j++)
{
var cell = tableArr[i].rows[0].cells[j];
if(!cellWidths[j] || cellWidths[j] < cell.clientWidth)
cellWidths[j] = cell.clientWidth;
}
}
// set all columns to the widest width found
for(i = 0; i < tableArr.length; i++)
{
for(j = 0; j < tableArr[i].rows[0].cells.length; j++)
{
tableArr[i].rows[0].cells[j].style.width = cellWidths[j]+'px';
}
}
}
window.onload = resizeTables;
To expand on Ken's answer, you can also specify the exact widths in pixels:
td { width: 250px }
or ems (width of the letter m):
td { width: 32em }
or ex or pt or whatever (well...actually %, pt, px, em, ex might be it). If you need your columns to be different widths, then the easy way is to give the table cells classes:
<table><tr>
<td class="col1">...</td><td class="col2">...</td>...
</tr></table>
and assign column widths to the classes:
td.col1 { width: 48em }
td.col2 { width: 200px }
...
It should be sufficient to assign column widths to the first row in each table. [edit: looks like I've been scooped on that while I was writing]
You could probably also go crazy with the CSS 2 sibling selector, and write something like
tr > td:first-child { width:48em } /* first column */
tr > td:first-child + td { width: 200px } /* second column */
tr > td:first-child + td + td { width: 5% } /* third column */
...
but if you have more than a few columns, that could get ugly. And if you're using some sort of template system or script to generate these tables, I'm sure it'll be easier/clearer to just put the class="col#" attribute on each cell in your template once.
I'm almost shocked that no one has suggested column groups! With it you can give a column a specific class, width, and other helpful properties. And since it's HTML 4.01 it's supported by all browsers that support the doctype.
Luis Siquot answer is the one I used. However instead of using clientWidth, you should use jquery width() function to normalize widths between browsers, and to not calculate padding. Using clientWidth would result in the table cells expanding on ajaxpostbacks because of the padding (if padding used in the TD's).
So, correct code using Luis Siquot's answer would be to replace
var cell = $(this)[0].rows[0].cells[j];
if(!cellWidths[j] || cellWidths[j] < cell.clientWidth) cellWidths[j] = cell.clientWidth;
with
var cell = $($(this)[0].rows[0].cells[j]);
if (!cellWidths[j] || cellWidths[j] < cell.width()) cellWidths[j] = cell.width();
The easiest way is kind of a 'dirty' way, but it works the best.
It does exactly what's required:
Just merge your two tables into one table.
In my case the only thing between the two tables was an h3
So my table
<table>
<tr></tr>
<table>
<h3>Title<h3>
<table>
<tr></tr>
<table>
became this:
<table>
<tr></tr>
<tr><td colspan="6">
<h3>Title<h3>
</td></tr>
<tr></tr>
<table>
this way your table will 'sync' it's size up.
of course this only works when there isn't too much complex stuff in between the two tables, but I'm guessing in most cases it isn't. if it was, the sync wouldn't be needed in the first place.
each pair of tables resize its columns to the same width
similar to Ole J. Helgesen but with jquery and a parameter in order to select which tables equalize.
(I cant vote but it's essentially your solution)
<table data-ss="1" border="1">
<tr><td>asdf<td>129292<td>text
</table>
<table data-ss="1" border=1>
<tr><td>a<td>1<td>each column here has the same size than the table above
</table>
<table data-ss="2" border=1>
<tr><td>asdf<td>129292<td>text
</table>
<table data-ss="2" border=1>
<tr><td>each column here has the same size than the table above<td>a<td>1
</table>
and use this sctipt
$(function(){
resizeTables('1');
resizeTables('2');
});
//please set table html attribute `data-ss="something"` to properly call this js
// ss is short for SharedSize
function resizeTables(sharedSize){
var tableArr = $('table[data-ss='+sharedSize+']');
var cellWidths = new Array();
$(tableArr).each(function() {
for(j = 0; j < $(this)[0].rows[0].cells.length; j++){
var cell = $(this)[0].rows[0].cells[j];
if(!cellWidths[j] || cellWidths[j] < cell.clientWidth) cellWidths[j] = cell.clientWidth;
}
});
$(tableArr).each(function() {
for(j = 0; j < $(this)[0].rows[0].cells.length; j++){
$(this)[0].rows[0].cells[j].style.width = cellWidths[j]+'px';
}
});
}
You can sync the column widths by combining the tables (as suggested by #Stefanvds), but using a tbody + th for each:
table {
border-collapse: collapse;
}
table thead,
table tbody {
border-bottom: solid;
}
table tbody th {
text-align: left;
}
<table>
<thead>
<tr> <th> ID <th> Measurement <th> Average <th> Maximum
<tbody>
<tr> <td> <th scope=rowgroup> Cats <td> <td>
<tr> <td> 93 <th scope=row> Legs <td> 3.5 <td> 4
<tr> <td> 10 <th scope=row> Tails <td> 1 <td> 1
<tbody>
<tr> <td> <th scope=rowgroup> English speakers <td> <td>
<tr> <td> 32 <th scope=row> Legs <td> 2.67 <td> 4
<tr> <td> 35 <th scope=row> Tails <td> 0.33 <td> 1
</table>
Source: Example in the HTML spec itself