Set min-width in HTML table's <td> - html

My table has several columns.
Each column should have dynamic width that depends on the browser window size. On the other hand, each column must not be too tiny. So I tried to set min-width for those columns but it's not a valid property. Tried min-width for <td> as well but that too is an invalid property.
Is there any way to set min-width for col/td in HTML table?

try this one:
<table style="border:1px solid">
<tr>
<td style="min-width:50px;border:1px solid red">one</td>
<td style="min-width:100px;border:1px solid red">two</td>
</tr>
</table>

min-width and max-width properties do not work the way you expect for table cells. From spec:
In CSS 2.1, the effect of 'min-width' and 'max-width' on tables, inline tables, table cells, table columns, and column groups is undefined.
This hasn't changed in CSS3.

Try using an invisible element (or psuedoelement) to force the table-cell to expand.
td:before {
content: '';
display: block;
width: 5em;
}
JSFiddle: https://jsfiddle.net/cibulka/gf45uxr6/1/

If you need your cells to be large enough to fit the largest word in that column, you can try surrounding that or those specific words with <span style="white-space: nowrap">; that will cause that specific word to not wrap, forcing the column-width to be a minimum of that dynamic width.
Idea from #Jon.

<table style="min-width:50px; max-width:150px;">
<tr>
<td style="min-width:50px">one</td>
<td style="min-width:100px">two</td>
</tr>
</table>
This works for me using an email script.

None of these solutions worked for me. The only workaround I could find was, adding all the min-width sizes together and applying that to the entire table. This obviously only works if you know all the column sizes in advanced, which I do. My tables look something like this:
var columns = [
{label: 'Column 1', width: 80 /* plus other column config */},
{label: 'Column 2', minWidth: 110 /* plus other column config */},
{label: 'Column 3' /* plus other column config */},
];
const minimumTableWidth = columns.reduce((sum, column) => {
return sum + (column.width || column.minWidth || 0);
}, 0);
tableElement.style.minWidth = minimumTableWidth + 'px';
This is an example and not recommended code. Fit the idea to your requirements. For example, the above is javascript and won't work if the user has JS disabled, etc.

One way should be to add a <div style="min-width:XXXpx"> within the td, and let the <td style="width:100%">

If you have set the percentages width of your columns and for you could be enough to FIX the entire table width or set a minimum width, this is valid
<table style="min-width:1000px;">
or
<table style="width:1000px;">
please note that this is said to work ONLY as inline style
I had this need with a bootstrap 5 table and my code ended to be
<table style="min-width:1000px;" class="table table-striped
table-hover table-bordered text-center table-responsive" id="tabella">
you better appreciate this when in mobile with small or empty TDs content

<table style="border:2px solid #ddedde">
<tr>
<td style="border:2px solid #ddedde;width:50%">a</td>
<td style="border:2px solid #ddedde;width:20%">b</td>
<td style="border:2px solid #ddedde;width:30%">c</td>
</tr>
<tr>
<td style="border:2px solid #ddedde;width:50%">a</td>
<td style="border:2px solid #ddedde;width:20%">b</td>
<td style="border:2px solid #ddedde;width:30%">c</td>
</tr>
</table>

Related

How to change the class of a <td> sub element depending on the value of another <td> in the same <tr>

I have a multi column table where one td contains the order status and another td contains a button tag. What I want to achieve is to hide the button tag if the order status is set to 'Part complete' and show the button if the status is set to 'Not complete'. Below is html of one of the tr's in the table -
<tr class="order-row ui-sortable-handle" data-index="46929" data-position="4">
<td style="text-align:center">4</td>
<td style="text-align:center">46929</td>
<td style="text-align:center">13/12/2021</td>
<td style="text-align:center">PS Machine shop (X)</td>
<td style="text-align:center">PSMAC</td>
<td style="text-align:center">Part complete</td>
<td style="text-align:center">1</td>
<td style="text-align:center"><button class="hide-unassign unassign-button" type="button"><i class="icon_fa fas fa-trash"></i></button></td>
</tr>
I am using jQuery to .addClass hide-unassign to the button tag, css below -
.hide-unassign {
display: none;
}
This works fine in hiding the button tag, but I am having no luck in only applying it if the value in the status td contains the text 'Part complete'.
Here is the jQuery I am running -
$("#Orders-Allocated").each(function(){
$('.button').has('.td:contains("Part complete")').addClass(' hide-unassign');
});
and this adds the hide-unassign class to all button elements on all rows. Not what I want to achieve.
Any advice would be greatly appreciated.
You selected the button but you should select the table row. Also you added dots to 'button' and 'td'. Dots mean that they are classes. Elements don't have a prefix with dots
So here is an example that could work
$('tr')
.has('td:contains("Part complete")')
.find('button')
.addClass('hide-unassign');
Instead of tr you could also use .order-row. Or if the #Orders-Allocated is the table row context/Id you can use this

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 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.

Table is getting too big

<table border="1" style="width:200px;">
<tr>
<td style="width:50px;overflow:hidden;">Who</td>
<td style="width:50px;overflow:hidden;">Time</td>
<td style="width:100px;overflow:hidden;">What</td>
</tr>
<?php
while($wr = mysqli_fetch_array($read)) {
echo' <tr>
<td>'.$wr['Who'].'</td>
<td>'.$wr['Time'].'</td>
<td>'.$wr['What'].'</td></tr>';
}
?>
$wr['What'] is pulling big data from database and my table is going over 200px. How can I fix it ?
You can use table-layout:fixed and it should force it...
style="width:200px;table-layout:fixed"
Here's a fiddle with appropriate css.
Use the max-width property in CSS on your td to set the maximum width of whatever you want
style='max-width:100px'

Any way to synchronize table column widths with HTML + CSS?

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