This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
HTML table with fixed headers?
I've tried several methods to get a scroll bar from an HTML table with a fixed header but had no luck. I think I need a solution where the header is somehow "attached" to the table body (rather than the typical nested table solution). Every solution I tried messes up the width of the header columns and the body columns. In other words they get out of synch and the columns of the header don't line up properly with those of the scrolling table. The widths of the headers and the columns vary from column to column.
Is there any way for me to achieve this? I'd rather not use JavaScript. Oh and I need this to work in Internet Explorer as well.
Update: It is pretty important for me to get this functionality. I need the fixed header for both column and row headers. So far no solution has worked properly. I considered making the headers separate tables, but this wouldn't work when scrolling since the headers would stay fixed.
It seems like there would be many use cases for fixed HTML headers so it is surprising to me that there is no adequate solution.
(Oh, and I tried the option suggested by opatut in the link, but it doesn't work in all browsers and I need this work in Internet Explorer, Firefox and Chrome. If it doesn't work in Internet Explorer 6 that's OK).
Oh, and if I must fix the column widths or row heights, that's OK too, I would just be glad to have a working fixed header HTML table (cross-browser).
I have a solution which is a pure CSS solution and allows the table to be normal and variable width. This is a new solution and has some issues depending on the design of your headers. The good news is that if your headers are left-aligned, or your columns are fixed width, it should be fine. There are some visual bugs in IE6, and I've found that some cells need a min-width to keep the headers showing if the content in the column is less wide then the header. All the issues are visual, so if it looks good you're done. The table body is totally normal, and since there's no JavaScript you don't have to do anything if the user re-sizes the page.
Check out my solution and leave me a comment
http://salzerdesign.com/blog/?p=191
I know you're trying to avoid Javascript, but I was in exactly the same boat as you (struggling with what to do for days on the exact challenge for a new application) and solved the problem in about 10 minutes once I found Datatables:
Working example of a solution: http://www.datatables.net/examples/basic_init/scroll_y.html
It EXACTLY matches header and body columns width-wise every time. Widths can be specified, but it's also intelligent enough to auto size. Column highlighting and sorting is supported by default using the provided sample CSS. Switching to a paginated model (what I ended up using) is a single line of code. And....the best part--if you're concerned that your user might not have Javascript turned on, it degrades perfectly back to standards-compliant HTML tables. IMHO, it's the least painful, most feature rich solution out there that fully supports IE.
If it makes you feel any better, I've used this solution on both a government (military) site and an international bank's websites....both the most demanding and strictest customers I've ever come across...and both were extremely happy with the results.
My first answer didn't attempt to fix both headers and columns. Here's an example that should work in all typical browsers (but it may need some tweaking).
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<style>
th { text-align: center; border: 1px solid black; padding:3px; }
td { text-align: center; border: 1px solid black; padding:3px; }
th.c1, td.c1 { width: 100px; }
th.c2, td.c2 { width: 150px; }
th.c3, td.c3 { width: 60px; }
th.c4, td.c4 { width: 100px; }
th.c5, td.c5 { width: 150px; }
th.c6, td.c6 { width: 60px; }
#rowScroll { height: 100px; } /* Subtract the scrollbar height */
#contentScroll { height: 100px; width: 300px; }
#colScroll { width: 272px; } /* Subtract the scrollbar width */
</style>
<table cellspacing="0" cellpadding="0" style="float: left;" style="width:300px; height:100px;" >
<tr>
<td id="void" style="border: 0;">
</td>
<td id="rowHeaders" style="border: 0;">
<div id="colScroll" style="overflow-x:hidden;">
<table cellspacing="0" cellpadding="0" style="width: 600px;">
<tr>
<th class="c1">A</th>
<th class="c2">B</th>
<th class="c3">C</th>
<th class="c4">D</th>
<th class="c5">E</th>
<th class="c6">F</th>
</tr>
</table>
</div>
</td>
</tr>
<tr>
<td id="colHeaders" style="border: 0;">
<div id="rowScroll" style="overflow-y:hidden">
<table cellspacing="0" cellpadding="0">
<tr><td>R1</td></tr>
<tr><td>R2</td></tr>
<tr><td>R3</td></tr>
<tr><td>R4</td></tr>
<tr><td>R5</td></tr>
<tr><td>R6</td></tr>
<tr><td>R7</td></tr>
<tr><td>R8</td></tr>
<tr><td>R9</td></tr>
</table>
</div>
</td>
<td id="content" style="border: 0;">
<div id="contentScroll" style="overflow:auto">
<table cellspacing="0" cellpadding="0" style="width: 600px;">
<tr><td class="c1">A1</td><td class="c2">B1</td><td class="c3">C1</td><td class="c4">D1</td><td class="c5">E1</td><td class="c6">F1</td></tr>
<tr><td class="c1">A2</td><td class="c2">B2</td><td class="c3">C2</td><td class="c4">D2</td><td class="c5">E2</td><td class="c6">F2</td></tr>
<tr><td class="c1">A3</td><td class="c2">B3</td><td class="c3">C3</td><td class="c4">D3</td><td class="c5">E3</td><td class="c6">F3</td></tr>
<tr><td class="c1">A4</td><td class="c2">B4</td><td class="c3">C4</td><td class="c4">D4</td><td class="c5">E4</td><td class="c6">F4</td></tr>
<tr><td class="c1">A5</td><td class="c2">B5</td><td class="c3">C5</td><td class="c4">D5</td><td class="c5">E5</td><td class="c6">F5</td></tr>
<tr><td class="c1">A6</td><td class="c2">B6</td><td class="c3">C6</td><td class="c4">D6</td><td class="c5">E6</td><td class="c6">F6</td></tr>
<tr><td class="c1">A7</td><td class="c2">B7</td><td class="c3">C7</td><td class="c4">D7</td><td class="c5">E7</td><td class="c6">F7</td></tr>
<tr><td class="c1">A8</td><td class="c2">B8</td><td class="c3">C8</td><td class="c4">D8</td><td class="c5">E8</td><td class="c6">F8</td></tr>
<tr><td class="c1">A9</td><td class="c2">B9</td><td class="c3">C9</td><td class="c4">D9</td><td class="c5">E9</td><td class="c6">F9</td></tr>
</table>
</div>
</td>
</tr>
</table>
<script src="../js/jquery-1.4.2.min.js" type="text/javascript"></script>
<script type="text/javascript">
var content = $("#contentScroll");
var headers = $("#colScroll");
var rows = $("#rowScroll");
content.scroll(function () {
headers.scrollLeft(content.scrollLeft());
rows.scrollTop(content.scrollTop());
});
</script>
</body>
</html>
Try my solution, it's bug free and optimized for performance (not sacrificing functionality):
http://code.google.com/p/js-scroll-table-header/
If you try it and need any help, just ask, I'm the author.
It's a bit too much code to put in here directly, but what it comes down to is, at minimum, you'll need some hefty CSS for this. Using javascript and jQuery can lighten that, so I'll include links to both methods.
HTML + CSS Only
You can use the source on this page to copy an example of how you can do exactly what you're asking via CSS and HTML. This is reported as working in pretty much all current browsers (Opera 7.x + (All Platforms), Mozilla 1.x + (All Platforms), IE 6.x + (Windows), Safari 1.x + (MacOS), Konqueror 3.x + (Linux / BSD)), but if you have to go back to IE 5.x, it starts to fail.
Javascript/jQuery
If you decide that you're open to including Javascript and jQuery, there's a second option that looks a bit simpler to implement: this blog article shows how.
All I've found need fixed values for cell width and height, so if you want to keep it dynamic you're stuck with JavaScript.
One solution I like is this one, but you need to define a width for each colum. » Fixed headers in large HTML tables at The Code Project.
If you don't want to use JavaScript, maybe you can set the fixed column widths with PHP. I would determine the average string length of the cells to get the column width:
column_width = column_average / (all_cells_average * column_count) * table_width
You can use DataTables without JavaScript. It won't have sorting but the table, headers and divs that are hosting them will work. Just look at the page source - it has 3 divs each with a table with identical widths in thead. Top and bottom just provide header and footer and the one in the middle provides data. It's actually pretty close to your original idea that you need to heep these parts separated.
Related
This is a theme, HTML or css issue. So please don't leave this when I mention "tiki". I believe it can be solved with a supposedly simple css script.
In our university page, I use the Tiki-wiki platform. Please take a look at the people page. This page consists of multiple tables, in each, there's a group of people listed.
The problem: In the previous version of Tiki, all names in the whole page were aligned without my intervention. Now in the new version of Tiki, you see that all names are not aligned. Every table has its own positioning of the names. This is the case although all tables have exactly the same html tagging and css styling and exactly same image sizes.
The fact that this worked in the previous version of tiki, made me believe that this is nothing but a styling issue, since themes also were updated.
Could you please tell me what I have to do to fix this and make all names aligned? For each table I created my own div with class name "peopletablediv".
If you require any additional information, please ask.
PS: Recreating the whole page isn't a preferred solution.
Just add
.peopletablediv .wikitable {
table-layout: fixed;
}
to your site's CSS and you're done.
In the CSS, you can specify a fixed size for the td conaining pictures :
.wikicell
{
width: 408px; /* or any convenient value here */
}
I'd try to add this to your CSS
.wikitable > tr > .wikicell:first-child{
width: 350px;
}
For an HTML solution, you could add a <colgroup> to each of the tables, just below the <table> tag:
<colgroup>
<col style="width: 380px;" />
<col colspan="2" />
</colgroup>
So the table code might look like this:
<table class="wikitable table table-striped table-hover">
<colgroup>
<col style="width: 380px;">
<col colspan="2" style="background-color:yellow">
</colgroup>
<tbody>
<tr>
<td class="wikicell"><a><img width="120" ...></a>
</td>
<td colspan="2" class="wikicell">Prof. Dmitry Budker <br><a ...>Send e-mail</a>
</td>
</tr>
</tbody>
</table>
Sorry i can't add a comment, not enough "points" still apparently, so this is more of a question than an answer...
Which version of Tiki did you upgrade to and from? (we released 4 new versions the other day) And where is "the people page", sorry, i don't see a link.
If you upgraded from Tiki 12 (say) to 13 or 14 then the whole framework has changed to Bootstrap so some extra custom CSS may well be needed to recreate previous appearances (as you suspected). Can't really tell exactly what without an example.
Hope i can improve my "answer" when i have a little more info, thanks :)
I'm working with a content management system that doesn't allow me to alter the head of the pages I'm working with. The page I'm creating will be edited by others using a WYSIWYG editor and will include a table where users can upload new documents. I want to style this with CSS so that I can give one command to put a line between each row (and this won't need to be done every time by each user - since they likely won't know how), but every time I do this it doesn't show anything. My code attempt is below, is this possible?
<table width=600px cellSpacing=2 cellPadding=2 style="td {border-bottom: solid 1px black;" }">
Not that I'm aware of. But you can do this
<style type="text/css">
.specialtable td {
border-bottom: 1px solid black;
}
</style>
<table width=600px cellSpacing=2 cellPadding=2 class="specialtable">
...
</table>
This will ensure that only this specific table's <td/> elements will be styled according to your needs. Note: according to the w3c specs, <style/> is only allowed within the <head/> element of your document. But in many browsers, it still works if you put it anywhere in the <body/>. Since you're looking for a kind of hack, this may be a viable solution for you
You can use frame and rules, two lesser-known attributes of the table element.
<table cellpadding="3" cellspacing="0" frame="below" rules="rows">
<tr><td>one</td><td>two</td></tr>
<tr><td>three</td><td>four</td></tr>
<tr><td>five</td><td>six</td></tr>
</table>
See jsFiddle.
Or if you only want lines in between the rows and not below the bottom one, leave out frame="below".
This won't work in all browsers though.
I have a table as follow:
<table>
<tr>
<td>
*PROBLEMATIC CELL*
</td>
<td rowspan="2">
</td>
<td rowspan="3">
</td>
</tr>
<tr>
<td>
</td>
</tr>
<tr>
<td colspan="2">
</td>
</tr>
</table>
The first cell of the first row, has a padding at the bottom. Well it's not really padding but it looks like padding and using firebug I can not find what the space there actually is.
I think what is happening is that, firefox automatically adjusts the bottom padding of the first td in the first tr with the padding top of the first and only td of the second tr.
p.s. works perfectly fine in Chrome.
Basically what I am trying to achieve is for the height of the first td in the first tr, to be only as tall as required but not taller so that the content of that cell ends on the same place as where the td ends without any space between them.
The website URL is: http://mmamail.com/
It seems to have something to do with the padding-top placed on the first TD of the SECOND TR. The weird thing is that it works nicely on chrome.
You've presented the browser with an incomplete layout problem. You have a three-by-three grid, none of whose columns or rows have fixed sizes. So the issue is you end up with a taller first row than you intended, as the browser tries to allocate ‘spare’ height caused by the rowspan in the second column amongst the cells in the first column.
There isn't a standardised algorithm for this; browsers do different things, often including unpleasant things like looking at the raw number of bytes of markup in each cell. You don't want to rely on this behaviour. It also slows page rendering down and can give really weird, page-distorting effects when there's a very small or large amount of content. If you need to use tables for layout, make sure to use table-layout: fixed with explicit widths for the fixed-size columns, and set explicit heights for cells when there are rowspans, to avoid ambiguity.
But a proliferation of rowspan/colspan is often a hint you should be looking at a different form of layout. This example is very much easier to acheive using CSS instead. eg.:
<div id="ads">
<script type="text/javascript">//...google stuff...</script>
...
</div>
<div id="content">
<div id="video"><fieldset>
<legend>...</legend>
<object ...>
</fieldset></div>
<form id="poll" method="post" action="..."><fieldset>
<legend>...</legend>
...options...
</fieldset></form>
<form id="subscribe" method="post" action="..."><fieldset>
<legend>...</legend>
...fields...
</fieldset></form>
<div id="about">
...
</div>
</div>
with styles something like:
#ads { position: absolute; right: 0; width: 160px; }
#content { margin-right: 160px; }
#video { float: right; width: 440px; }
#poll, #subscribe { margin: 0 440px 0 0; }
#about { clear: right; }
I'd also advise you to move the JavaScript logic out from the inline event handler attributes you currently have to separate JavaScript blocks (either embedded <script> blocks or linked external scripts). Especially for the multi-line event handlers: quite apart from the horrible maintainability of mixing scripts into markup, in HTML/XML newlines in attributes are not preserved. That means your newlines in JS code are converted into spaces, so if you miss a single semicolon your script will break or behave oddly (where usually in a script block or external script, the auto-newline-semicolon-fallback would save you).
ie.
onsubmit="
var inputs = this.getElementsByTagName('input');
var checkedValue;
for(var i = 0; i < inputs.length; i++)
{
if(inputs[i].getAttribute('type') == 'radio' && inputs[i].checked)
{
checkedValue = inputs[i].value;
}
}
/*makeAjaxPostRequest('/poll/ajax-vote.php', 'vote='+checkedValue, processAjaxResponse);*/
makeAjaxGetRequest('/poll/ajax-vote.php?vote='+checkedValue, processAjaxResponse);
return false;"
instead:
<form id="pollForm" method="post" action="/poll/form-vote.php>
...
</form>
<script type="text/javascript">
document.getElementById('pollForm').onsubmit= function() {
var checkedValue= getRadioValue(this.elements.vote);
makeAjaxPostRequest('/poll/ajax-vote.php', 'vote='+encodeURIComponent(checkedValue), processAjaxResponse);
return false;
};
function getRadioValue(fields) {
for (var i= fields.length; i-->0;)
if (fields[i].checked)
return fields.value;
return '';
};
</script>
Always allow only POST requests for active forms that do something positive. Always use encodeURIComponent when creating query strings. Don't use getAttribute as it doesn't work right in IE; use direct DOM Level 1 HTML properties instead, eg. input.type.
if you are referring to the space in between the "Monthly poll" and "Monthly Magazine" boxes, it is not caused by padding...
What's happening is the td containing the flash video is too tall, and because it has a rowspan of 2, the two tds on the left are being adjusted to the height of the tallest td (aka the video box)
One solution is to add another tr below the first 2 rows,
let it have an empty td,
change the rowspan of the video box to 3
And then the redundant space you see in between the first 2 boxes will be transfered to the empty td you have just created.
OR
I would suggest you bite the bullet and start using CSS rather than tables for layout, purely because:
We are in the second decade of the 21st century
It is much more flexible to use CSS
It will be much easier for you change the look of the site in th future, without touching the markup.
It will be much better for search engines to index your site content
Assistive software such as screen readers can see your content in the order they are supposed to be seen
You will be one happy developer in the end
Controlling table cell padding with css can be tricky. Try adding these two css rules:
table { border-spacing: 0; }
table td { padding: 0; }
Unfortunately, the border-spacing rule isn't supported by all browser, so you may have to add cellpadding="0" and cellspacing="0" as an attribute to the table.
I've tried with the follow HTML code which is merely a more complete version of your code fragment. However, I'm seeing no padding as you have described. So my best guess is that it's caused by some other CSS rules you defined elsewhere.
<!doctype html>
<html>
<head>
</head>
<body>
<table>
<tr>
<td>
*PROBLEMATIC CELL*
</td>
<td rowspan="2">
</td>
<td rowspan="3">
</td>
</tr>
<tr>
<td>
</td>
</tr>
<tr>
<td colspan="2">
</td>
</tr>
</table>
</body>
</html>
I am working with a simple table-based layout that uses iFrames as depicted in the example below. This code is rendering well in all modern browsers. The iFrames are usually filled with long tables of data, but there is no odd behavior or clipping.
My concern is that it LOOKS like a really bad hack to me. Table-based layout evils aside, should I be worried about deprecation of all the width="100%" height="100%" attributes to HTML and iFrame tags?
I know that CSS can do most, if not all of this, but I don't want to use float hacks and I haven't been able to nail anything down that works in all modern browsers.
To be clear, I am looking for opinions and suggestions as to whether this solution is adequate for the next few years, or whether I should go ahead and delve into CSS hacks.
Thank you for any feedback.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Untitled</title>
<style type="text/css">
<!--
html, body
{
height: 100%;
margin: 0px;
}
-->
</style>
</head>
<body>
<table border="0" cellpadding="0" cellspacing="0" width="100%" height="100%">
<tr>
<td colspan="2"><div align="center">This is the header.</div></td>
</tr>
<tr>
<td height="100%">
<iFrame src="pane1.php" width="100%" height="100%" frameborder="0"></iframe>
</td>
<td height="100%">
<iFrame src="pane2.php" width="100%" height="100%" frameborder="0"></iframe>
</td>
</tr>
<tr>
<td colspan="2">This is the footer.</td>
</tr>
</table>
</body>
</html>
I don't see anything that's going to be removed from any browser in the next few (or several) years.
The table tag is a valid and needed set of tags. Without it, there's no way to display tabular data.
What happened was people started exploiting it to display very intricate layouts which ended up being impossible to maintain.
No one's going to shoot you for using tables in the fashion you're using. It's super simple, and does the job whily you're developing, so consider it simply an iteration. Iterative development is good. Once you figure out a CSS-based layout, the code here is simple enough to replace.
It would probably be best to move to css styles if you are concerned about deprecation. You can still use the table layout if you are more comfortable though I prefer floating divs.
To my knowledge, there is no danger of the tag becoming deprecated.
And I have it from a very good source!
see Are IFrames (HTML) obsolete?
Deprecation means that the features will not be present in future version of (X)HTML. So far all the browsers are supporting old versions of HTML, but I wouldn't rely on that myself.
All of what you're doing and much more can be done with CSS, without using hacks. Going through the exercise will help you maintain relevant skills. The page you have right now takes two extra HTTP requests to display; whether this is a concern depends how many people are requesting the page.
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....