HTML colspan 0 alternative - html

I have a HTML table, and i would like to give the last row (in <tfoot> tag) only one cell expanding to all the table.
I was using colspan="0", then i saw that it only worked in Firefox.
I then tried colspan="100%".
It works fine, but not pass the w3c validator (Very important in my project).
Is there a working alternative ?
I saw people who use colspan="1000", not a bad idea but are there some performance problems with this ?
Thanks for advice.

My first answer is: refactor your code. If you need the total number of columns to build the table footer then the function you use to build the table body should return that number (and not only the HTML).
That said and only in case it's too complicated (or you don't have control about that code) you may simply count them by yourself, I would avoid any trick about colspan because it's behavior isn't homogeneous (and it's not validated too).
You can easy count the number of cells using the first row (if the table is well formed all the rows have the same number of columns).
The first naive solution would be to split() HTML tbody then to substr_count() the <td/> of the first row. Unfortunately this may work only in a very controlled situation (tables must be well formed, table may contain or not tbody and it doesn't manage colspan of that cells).
Better solution involves a small HTML parser (see this great post here on SO for a good and detailed list), when you have DOM then you can easily count TDs and check for their attributes (I say this in advance: no, you can't use regex to parse HTML).
To be honest I think refactoring is much more suitable...

Might be the following code I use could be useful too:
var len = document.getElementById("myTable").rows[0].cells.length;
document.getElementById("myTablelastrowfirstcell").colSpan = len;
the first line gets into the variable len the number of cells (td or th elements, doesn't matter, if all the table has the same number of column) contained into the first row of mytable;
The second row modifies the colspan property/attribute of the targeted cell positioned into the last row and sets it to the value previously got.
The following has the same code, shortened:
document.getElementById("myTablelastrowfirstcell").colSpan = document.getElementById("myTable").rows[0].cells.length;
Notes:
Sometimes the table contains a thead, a tbody and a tfoot. In such
case it is needed to modify the code using the id of one of them
that has the correct number of columns to return.
The given examples, in some situations, might work only when rendered by the browser, if rendered for printing they might won't work anymore and table layout might be different.
Working example (click on run code example at the end of the code to run it and see how it operates):
function spanLastRowCols() {
var len = document.getElementById("myTable").rows[0].cells.length;
var len = document.getElementById("ext").colSpan = len;
info.innerText = len;
}
table, td {
border: 1px solid black;
}
<p>Click the button to change the content of the first table cell.</p>
<p>Then copy and paste some td cells for each rows forthe first and the second tr. Than run the snippet again and click the button to change the content of the first table cell to compare differences.</p>
<table id="myTable">
<tr>
<td>Row1 cell1</td>
<td>Row1 cell2</td>
<td>Row1 cell3</td>
<td>Row1 cell4</td>
<td>Row1 cell5</td>
</tr>
<tr>
<td>Row2 cell1</td>
<td>Row2 cell2</td>
<td>Row2 cell3</td>
<td>Row2 cell4</td>
<td>Row2 cell5</td>
</tr>
<tr>
<td id= "ext">Row3 cell1</td>
</tr>
</table>
<br>
<button onclick="spanLastRowCols()">Try it</button>
Last row colSpan attribute value: <span id="info"></span>

The <caption> tag is well supported and will give you a result similar to <tfoot colspan="1000">:
table {
background: #eee;
}
table caption {
background: #e0e0e0;
}
td,
th {
margin: 5px;
padding: 5px;
}
<table>
<thead>
<th>Quote</th>
<th>Author</th>
<th>More</th>
<tbody>
<tr>
<td>One cow at a time, set free the entire herd</td>
<td colspan="2">Prosper Stupefy</td>
</tr>
</tbody>
<caption style="caption-side:bottom">This will always span to the full width of the table</caption>
<caption style="caption-side:top">A list of made-up quotes</caption>
</table>
Note that you will need to css style it.
Documentation: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/caption

Related

Markdown table rowspan without loss of formatting

As described in this and this answers, we can use HTML tags in Markdown to create tables with cells spanning multiple rows or columns. Suppose I want to make the following table (rendered by Visual Studio Code with extension "Markdown All in One"):
Desired Effect
But the problem for the second answer is that the rowspan/colspan of the first column/row will be rendered with a additional column/row in the front, as in the following example (does not work on StackOverflow, but works in VSCode; a work-around is to add an empty column/row, as suggested by the first comment in that answer, but this is still not perfect):
||Letter|Typesetting|Result|
|-|-|-|-|
|<td rowspan=4>a |Normal|a
||Italic|*a*|
||Bold|**a**|
||Math|$a$
Result:
Table constructed using method in Answer 2
Then we can use the HTML tags, as described by the first answer:
<table>
<thead>
<tr> <th>Letter <th>Typesetting <th>Result
</thead>
<tbody>
<tr> <td rowspan=4>a <td>Normal <td>a
<tr> <td>Italic <td>*a*
<tr> <td>Bold <td>**a**
<tr> <td>Math <td>$a$
</tbody>
</table>
But then Markdown formatting will be lost:
Table constructed using method in Answer 1
Is there any way to overcome this problem, i.e. using HTML tags to achieve rowspan/colspan without loss of Markdown text formatting?

Dynamic height for table cell in horizontal table

I used this answer to create a horizontal table as i have a fixed amount of horizontal rows but N number of vertical columns. This works really well but because the HTML rows are actually columns, the height between cells does not stay consistent in the displayed rows.
By adding the following to the answer provided, I'm able to ensure each column fits on the page, causing text wrap to occur, but then the rows height don't necessarily match.
td {
max-width: 200px;
}
JSFiddle example.
In the fiddle example above, how do I make the cell with "Title" and the cell with "Braveheart" match the height of the third cell in that row?
Hint: the correct answer is not to hard code the height of the first two cells, since I have no idea how long another cell may be when it is added later.
EDIT
I can't use JavaScript as the html never hits anything client side. It's rendered and then passed into a PDF creation utility.
This may not be the best performing answer, or even the most concise, but it could start you in the right path (fiddle):
<div>
<table>
<tbody>
<tr>
<th class="title">Title</th>
<th class="year">Release Year</th>
<th class="director">Director</th>
</tr>
<tr>
<td class="title">Braveheart</br>part 2</td>
<td class="year">1992?</td>
<td class="director">Mel Gibson?</td>
<tr>
<td class="title">Some movie with a ridiculously long title. I mean, like two paragraphs for a title, which is ridiculous of course but it proves my point.</td>
<td class="year">2015</td>
<td class="director">The Great Anton - Director of the year 2012</td>
</tr>
</tbody>
</table>
</div>
$(document).ready(function(){
function getMaxHeight(e){
var maxHeight = Math.max.apply(null, $(e).map(function ()
{
return $(this).height();
}).get());
return maxHeight;
}
$('tr').each(function(){
$(this).find('.title').css("height", getMaxHeight('.title'));
$(this).find('.year').css("height", getMaxHeight('.year'));
$(this).find('.director').css("height", getMaxHeight('.director'));
});
});
The max height function came from this SO answer.

Alternate table row color using CSS, individual cells get colored not the even rows

Somehow I can't figure out the following: Alternate table row color using CSS?
If I use the code suggested in the aforementioned topic the even cells get colored (the first, third and fifth. There is a total of 5 cells in a row). It doesn't matter if I use 'even' or 'odd'.
td:nth-child(odd)
{
background: #f5f6fa;
}
If use the following code, all the rows get colored.:
tr:nth-child(odd)
{
background: #f5f6fa;
}
#svdh You've got tags outside of your body and html tags also which in a normal web page wouldn't be rendered. The problem with your HTML is you're setting up loads of tables instead of one with multiple rows. It should be like this.
<table>
<tr>
<td>One</td>
<td>One.</td>
</tr>
<tr>
<td>Two</td>
<td>Two.</td>
</tr>
<tr>
<td>Three</td>
<td>Three.</td>
</tr>
</table>
Fiddle here..
https://jsfiddle.net/fo7Ldfqs/
UPDATED:
If you've got multiple tables and you're trying to color every other one then just use:
table:nth-child(odd){background:#ff0000;}
Fiddle here.. https://jsfiddle.net/4641ph6u/

Only parsing outer element

I am writing a scraper with Nokogiri, and I want to scrape a large HTML file.
Currently, I am scraping a large table; here is a small fragment:
<table id="rptBidTypes__ctl0_dgResults">
<tr>
<td align="left">S24327</td>
<td>
Airfield Lighting
<div>
<div>
<table cellpadding="5px" border="2" cellspacing="1px" width="100%" bgcolor=
"black">
<tr>
<td bgcolor="white">Abstract:<br />
This project is for the purchase and delivery, of various airfield
lighting, for a period of 36 months, with two optional 1 year renewals,
in accordance with the specifications, terms and conditions specified in
the solicitation.</td>
</tr>
</table>
</div>
</div>
</td>
</tr>
</table>
And here is the Ruby code I am using to scrape:
document = doc.search("table#rptBidTypes__ctl0_dgResults tr")
document[1..-1].each do |v|
cells = v.search 'td'
if cells.inner_html.length > 0
data = {
number: cells[0].text,
}
end
ScraperWiki::save_sqlite(['number'], data)
end
Unfortunately this isn't working for me. I only want to extract S24327, but I am getting the content of every table cell. How do I only extract the content of the first td?
Keep in mind that under this table, there are many table rows following the same format.
In CSS, table tr means tr anywhere underneath the table, including nested tables. But table > tr means the tr must be a direct child of the table.
Also, it appears you only want the cell values, so you don't need to iterate. This will give you all such cells (the first in each row):
doc.search("table#rptBidTypes__ctl0_dgResults > tr > td[1]").map(&:text)
The content of the first td would be:
doc.at("table#rptBidTypes__ctl0_dgResults td").text
The problem is that your search is matching two different things: the <tr> tag nested directly within the table with id rptBidTypes__ctl0_dgResults, and the <tr> tag within the table nested inside that parent table. When you loop through document[1..-1] you're actually selecting the second <tr> tag rather than the first one.
To select just the direct child <tr> tag, use:
document = doc.search("table#rptBidTypes__ctl0_dgResults > tr")
Then you can get the text for the <td> tag with:
document.css('td')[0].text #=> "S24327"

Colspan all columns

How can I specify a td tag should span all columns (when the exact amount of columns in the table will be variable/difficult to determine when the HTML is being rendered)? w3schools mentions you can use colspan="0", but it doesn't say exactly what browsers support that value (IE 6 is in our list to support).
It appears that setting colspan to a value greater than the theoretical amount of columns you may have will work, but it will not work if you have table-layout set to fixed. Are there any disadvantages to using an automatic layout with a large number for colspan? Is there a more correct way of doing this?
Just use this:
colspan="100%"
It works on Firefox 3.6, IE 7 and Opera 11! (and I guess on others, I couldn't try)
Warning: as mentioned in the comments below this is actually the same as colspan="100". Hence, this solution will break for tables with css table-layout: fixed, or more than 100 columns.
I have IE 7.0, Firefox 3.0 and Chrome 1.0
The colspan="0" attribute in a TD is NOT spanning across all TDs in any of the above browsers.
Maybe not recommended as proper markup practice, but if you give a higher colspan value than the total possible no. of columns in other rows, then the TD would span all the columns.
This does NOT work when the table-layout CSS property is set to fixed.
Once again, this is not the perfect solution but seems to work in the above mentioned 3 browser versions when the table-layout CSS property is automatic.
If you want to make a 'title' cell that spans all columns, as header for your table, you may want to use the caption tag (http://www.w3schools.com/tags/tag_caption.asp / https://developer.mozilla.org/en-US/docs/Web/HTML/Element/caption) This element is meant for this purpose. It behaves like a div, but doesn't span the entire width of the parent of the table (like a div would do in the same position (don't try this at home!)), instead, it spans the width of the table. There are some cross-browser issues with borders and such (was acceptable for me). Anyways, you can make it look as a cell that spans all columns. Within, you can make rows by adding div-elements. I'm not sure if you can insert it in between tr-elements, but that would be a hack I guess (so not recommended). Another option would be messing around with floating divs, but that is yuck!
Do
<table>
<caption style="gimme some style!"><!-- Title of table --></caption>
<thead><!-- ... --></thead>
<tbody><!-- ... --></tbody>
</table>
Don't
<div>
<div style="float: left;/* extra styling /*"><!-- Title of table --></div>
<table>
<thead><!-- ... --></thead>
<tbody><!-- ... --></tbody>
</table>
<div style="clear: both"></div>
</div>
As a partial answer, here's a few points about colspan="0", which was mentioned in the question.
tl;dr version:
colspan="0" doesn't work in any browser whatsoever. W3Schools is wrong (as usual). HTML 4 said that colspan="0" should cause a column to span the whole table, but nobody implemented this and it was removed from the spec after HTML 4.
Some more detail and evidence:
All major browsers treat it as equivalent to colspan="1".
Here's a demo showing this; try it on any browser you like.
td {
border: 1px solid black;
}
<table>
<tr>
<td>ay</td>
<td>bee</td>
<td>see</td>
</tr>
<tr>
<td colspan="0">colspan="0"</td>
</tr>
<tr>
<td colspan="1">colspan="1"</td>
</tr>
<tr>
<td colspan="3">colspan="3"</td>
</tr>
<tr>
<td colspan="1000">colspan="1000"</td>
</tr>
</table>
The HTML 4 spec (now old and outdated, but current back when this question was asked) did indeed say that colspan="0" should be treated as spanning all columns:
The value zero ("0") means that the cell spans all columns from the current column to the last column of the column group (COLGROUP) in which the cell is defined.
However, most browsers never implemented this.
HTML 5.0 (made a candidate recommendation back in 2012), the WhatWG HTML living standard (the dominant standard today), and the latest W3 HTML 5 spec all do not contain the wording quoted from HTML 4 above, and unanimously agree that a colspan of 0 is not allowed, with this wording which appears in all three specs:
The td and th elements may have a colspan content attribute specified, whose value must be a valid non-negative integer greater than zero ...
Sources:
https://www.w3.org/TR/html50/tabular-data.html#attributes-common-to-td-and-th-elements
https://html.spec.whatwg.org/multipage/tables.html#attributes-common-to-td-and-th-elements
https://www.w3.org/TR/html53/tabular-data.html#attributes-common-to-td-and-th-elements
The following claims from the W3Schools page linked to in the question are - at least nowadays - completely false:
Only Firefox supports colspan="0", which has a special meaning ... [It] tells the browser to span the cell to the last column of the column group (colgroup)
and
Differences Between HTML 4.01 and HTML5
NONE.
If you're not already aware that W3Schools is generally held in contempt by web developers for its frequent inaccuracies, consider this a lesson in why.
For IE 6, you'll want to equal colspan to the number of columns in your table. If you have 5 columns, then you'll want: colspan="5".
The reason is that IE handles colspans differently, it uses the HTML 3.2 specification:
IE implements the HTML 3.2 definition, it sets colspan=0 as colspan=1.
The bug is well documented.
If you're using jQuery (or don't mind adding it), this will get the job done better than any of these hacks.
function getMaxColCount($table) {
var maxCol = 0;
$table.find('tr').each(function(i,o) {
var colCount = 0;
$(o).find('td:not(.maxcols),th:not(.maxcols)').each(function(i,oo) {
var cc = Number($(oo).attr('colspan'));
if (cc) {
colCount += cc;
} else {
colCount += 1;
}
});
if(colCount > maxCol) {
maxCol = colCount;
}
});
return maxCol;
}
To ease the implementation, I decorate any td/th I need adjusted with a class such as "maxCol" then I can do the following:
$('td.maxcols, th.maxcols').each(function(i,o) {
$t = $($(o).parents('table')[0]); $(o).attr('colspan', getMaxColCount($t));
});
If you find an implementation this won't work for, don't slam the answer, explain in comments and I'll update if it can be covered.
Another working but ugly solution : colspan="100", where 100 is a value larger than total columns you need to colspan.
According to the W3C, the colspan="0" option is valid only with COLGROUP tag.
Below is a concise es6 solution (similar to Rainbabba's answer but without the jQuery).
Array.from(document.querySelectorAll('[data-colspan-max]')).forEach(td => {
let table = td;
while (table && table.nodeName !== 'TABLE') table = table.parentNode;
td.colSpan = Array.from(table.querySelector('tr').children).reduce((acc, child) => acc + child.colSpan, 0);
});
html {
font-family: Verdana;
}
tr > * {
padding: 1rem;
box-shadow: 0 0 8px gray inset;
}
<table>
<thead>
<tr>
<th>Header 1</th>
<th>Header 2</th>
<th>Header 3</th>
<th>Header 4</th>
<th>Header 5</th>
<th>Header 6</th>
</tr>
</thead>
<tbod><tr>
<td data-colspan-max>td will be set to full width</td>
</tr></tbod>
</table>
Simply set colspan to the number of columns in the table.
All other "shortcuts" have pitfalls.
The best thing to do is set the colspan to the correct number to begin with. If your table has 5 columns, set it to colspan="5" That is the only way that will work in all scenarios. No, it's not an outdated solution or only recommended for IE6 or anything -- that's literally the best way to handle this.
I wouldn't recommend using Javascript to solve this unless the number of columns changes during runtime.
If the number of columns is variable, then you'll need to calculate the number of columns so that you can populate the colspan. If you have a variable number of columns, whatever is generating the table should be able to be adapted to also calculate the number of columns the table has.
As other answers have mentioned, if your table is not set to table-layout: fixed, you can also just set colspan to a really large number. But I find this solution messy, and it can be a headache if you come back later and decide it should be a fixed table layout. Better just to do it correctly the first time.
A CSS solution would be ideal, but I was unable to find one, so here is a JavaScript solution: for a tr element with a given class, maximize it by selecting a full row, counting its td elements and their colSpan attributes, and just setting the widened row with el.colSpan = newcolspan;. Like so...
var headertablerows = document.getElementsByClassName('max-col-span');
[].forEach.call(headertablerows, function (headertablerow) {
var colspan = 0;
[].forEach.call(headertablerow.nextElementSibling.children, function (child) {
colspan += child.colSpan ? parseInt(child.colSpan, 10) : 1;
});
headertablerow.children[0].colSpan = colspan;
});
html {
font-family: Verdana;
}
tr > * {
padding: 1rem;
box-shadow: 0 0 8px gray inset;
}
<table>
<tr class="max-col-span">
<td>1 - max width
</td>
</tr>
<tr>
<td>2 - no colspan
</td>
<td colspan="2">3 - colspan is 2
</td>
</tr>
</table>
You may need to adjust this if you're using table headers, but this should give a proof-of-concept approach that uses 100% pure JavaScript.
Anyone else here feel that diving into JS for this seemingly minor issue seems a bit much?
PURE CSS
Boom! I have a pure CSS solution to offer you! Example is below, you just have to add a class to the row that you want to span all columns. Then the CSS will make the first <td> element span the full width and hide the remaining <td> elements. (You must use visibility:hidden; and NOT display:none; for this.)
Note: You will need at least two cells for this method to render nicely, and CSS will render best if you keep the correct quantity of <td> elements - don't remove any to make room for span element. This will help ensure the cells / rows still flow normally.
EXAMPLE
/* standard styling css */
table {
border-collapse: collapse;
}
table, tr, td {
border: 1px solid black;
}
td {
padding: 3px;
}
/* make full width class span the whole table */
.full-span {
position:relative;
}
.full-span > * {
visibility: hidden;
border:0;
}
.full-span > *:nth-child(1) {
display: block;
visibility: unset;
position:absolute;
}
<table>
<tbody>
<tr>
<td>A1</td>
<td>A2</td>
<td>A3</td>
<td>A4</td>
</tr>
<tr class="full-span">
<td>B1 long text</td>
<td>B2</td>
<td>B3</td>
<td>B4</td>
</tr>
<tr>
<td>C1</td>
<td>C2</td>
<td>C3</td>
<td>C4</td>
</tr>
<tr>
<td>D1</td>
<td>D2</td>
<td>D3</td>
<td>D4</td>
</tr>
</tbody>
</table>
Bonus tip!
if you are dynamically producing your table in PHP/JS, this may clean up some of your code. Say you are looping through a 2D array to create a table: for each row that needs to span all columns you'll need to add some logic to calculate the amount of columns, add the colspan attribute, add any remaining <td> elements required to make up the full width of the table and so on.
Using my method, you can loop through all the columns and output them all, and simply include the class in the parent row.
Just want to add my experience and answer to this.
Note: It only works when you have a pre-defined table and a tr with ths, but are loading in your rows (for example via AJAX) dynamically.
In this case you can count the number of th's there are in your first header row, and use that to span the whole column.
This can be needed when you want to relay a message when no results have been found.
Something like this in jQuery, where table is your input table:
var trs = $(table).find("tr");
var numberColumns = 999;
if (trs.length === 1) {
//Assume having one row means that there is a header
var headerColumns = $(trs).find("th").length;
if (headerColumns > 0) {
numberColumns = headerColumns;
}
}
colspan="100%"
it's work also in email outlook , gmail....