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

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.

Related

Is there any way to clear/hide the first td in a two td table, without access to the first td?

Is there any way to clear or hide the contents of the first td, from the second td in a two column table, without any edit access to the actual td's?
So I'd like to hide the numbers in the table below
<table>
<tr>
<td>1.</td>
<td>Content</td>
</tr>
<tr>
<td>2.</td>
<td>More content</td>
</tr>
<tr>
<td>3.</td>
<td>Even more content</td>
</tr>
</table>
This is in a vendor-supplied application that spits out the coded page. The only access is the ability to add code in the Content section (second td in each row).
I've tried to use a div tag with some absolute positioning and just cover the first td with the second, but I could never get it to work consistently.
With CSS Selectors
If your page has only one table you could use CSS selectors. In your case you need to add a style that targets <td> tags that don't have a previous <td> sibling.
td {
/* hide the first td element */
display: none;
}
td + td {
/* display all td elements that have a previous td sibling */
display: block;
}
If you are only able to add content within the second <td> of each row then adding a whitespace stripped version of the above code within style tags to the first one will probably work, but could have messy side effects if there is more than one table on your page.
<table>
<tr>
<td>1.</td>
<td><style>td{display:none;}td+td{display:block;}</style>Content</td>
</tr>
<tr>
<td>2.</td>
<td>More content</td>
</tr>
<tr>
<td>3.</td>
<td>Even more content</td>
</tr>
</table>
With JavaScript
If you have more than one table on your page, try inserting an empty <div> with a unique ID into the first <td>'s content. Immediately after place a script that targets the closest <table> parent of that ID, from which you can extract the necessary <td>s to hide. Additionally, you need to make sure you only run the code once the page is loaded, otherwise it may not pick up any trs etc beyond where the script is implemented.
The easiest way to find the nearest parent that is <table> is by using closest but this isn't supported in Internet Explorer. This post has a good solution (parent only) that I'll use.
The complete script:
window.onload = function() {
function getClosest( el, tag ) {
tag = tag.toUpperCase();
do {
if ( el.nodeName === tag ) {
return el;
}
} while ( el = el.parentNode );
return null;
}
var table = getClosest( document.getElementById( 'unique-id' ), 'table' );
var trs = table.getElementsByTagName( 'tr' );
for ( var i = 0; i < trs.length; i++ ) {
trs[ i ].getElementsByTagName( 'td' )[ 0 ].style.display = 'none';
}
}
Including the <div> with a unique ID, stripping whitespace and adding the <script> tags, your table would look something like:
<table>
<tr>
<td>1.</td>
<td><div id="unique-id"></div><script>window.onload=function(){function getClosest(el,tag){tag=tag.toUpperCase();do{if(el.nodeName===tag){return el;}}while(el=el.parentNode);return null;}var table=getClosest(document.getElementById('unique-id'),'table'),trs = table.getElementsByTagName('tr');for(var i=0;i<trs.length;i++){trs[ i ].getElementsByTagName('td')[0].style.display='none';}}</script>Content</td>
</tr>
<tr>
<td>2.</td>
<td>More content</td>
</tr>
<tr>
<td>3.</td>
<td>Even more content</td>
</tr>
</table>

How to get line from table with Jsoup

I have table without any class or id (there are more tables on the page) with this structure:
<table cellpadding="2" cellspacing="2" width="100%">
...
<tr>
<td class="cell_c">...</td>
<td class="cell_c">...</td>
<td class="cell_c">...</td>
<td class="cell">SOME_ID</td>
<td class="cell_c">...</td>
</tr>
...
</table>
I want to get only one row, which contains <td class="cell">SOME_ID</td> and SOME_ID is an argument.
UPD.
Currently i am doing iy in this way:
doc = Jsoup.connect("http://www.bank.gov.ua/control/uk/curmetal/detail/currency?period=daily").get();
Elements rows = doc.select("table tr");
Pattern p = Pattern.compile("^.*(USD|EUR|RUB).*$");
for (Element trow : rows) {
Matcher m = p.matcher(trow.text());
if(m.find()){
System.out.println(m.group());
}
}
But why i need Jsoup if most of work is done by regexp ? To download HTML ?
If you have a generic HTML structure that always is the same, and you want a specific element which has no unique ID or identifier attribute that you can use, you can use the css selector syntax in Jsoup to specify where in the DOM-tree the element you are after is located.
Consider this HTML source:
<html>
<head></head>
<body>
<table cellpadding="2" cellspacing="2" width="100%">
<tbody>
<tr>
<td class="cell">I don't want this one...</td>
<td class="cell">Neither do I want this one...</td>
<td class="cell">Still not the right one..</td>
<td class="cell">BINGO!</td>
<td class="cell">Nothing further...</td>
</tr> ...
</tbody>
</table>
</body>
</html>
We want to select and parse the text from the fourth <td> element.
We specify that we want to select the <td> element that has the index 3 in the DOM-tree, by using td:eq(3). In the same way, we can select all <td> elements before index 3 by using td:lt(3). As you've probably figured out, this is equal and less than.
Without using first() you will get an Elements object, but we only want the first one so we specify that. We could use get(0) instead too.
So, the following code
Element e = doc.select("td:eq(3)").first();
System.out.println("Did I find it? " + e.text());
will output
Did I find it? BINGO!
Some good reading in the Jsoup cookbook!

Adding last row of table rowspan attribute doesnt work

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

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

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>

aligning columns in two separate (but related) html tables

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