I'm trying to construct a table dynamically, with a size determined by the current width of the browser window.
Since the table cells' sizes and their containing div's size are both being set relative to the window's width, the cells should fit exactly within the div. This is working perfectly for the width, but not for the height. The last row of cells appears to overhang the bottom of the div by a fractional amount.
Logging the sizes of the div and one of the table cells shows that they ought to align correctly, as the cell's height is exactly 1/10 of the div's height, and there are 10 rows of cells. However, the visual doesn't match, even though the math works out as expected.
What is causing the discrepancy between the calculated and displayed heights?
const pageWidth = document.documentElement.scrollWidth;
const nRows = 10; const nColumns = 10;
const tableDiv = document.getElementById("tableDiv");
tableDiv.style.width = 0.7*pageWidth + "px";
tableDiv.style.height = 0.7*pageWidth + "px";
tableDiv.style.backgroundColor = "yellow";
// Dynamically generate a table of the specified dimensions
function constructTable(nR, nC) {
const tbl = document.createElement("table"); tbl.id = "test table";
var tRow; var tCell;
for (let r = 0; r < nR; r++) { // Use 'let,' not 'var,' or else all row/column numbers will be set to the final (maximum) values of r and c
tRow = document.createElement("tr");
tbl.appendChild(tRow);
for (let c = 0; c < nC; c++) {
tCell = document.createElement("td"); tCell.className = "testing"; tRow.appendChild(tCell);
}
}
return tbl;
}
function showTable(t) {
tableDiv.innerHTML = "";
tableDiv.appendChild(t);
const dynamicSizeCells = document.getElementsByClassName("testing");
for (var i = 0; i < dynamicSizeCells.length; i++) {
dynamicSizeCells[i].style.width = 0.7*pageWidth/nColumns + "px";
dynamicSizeCells[i].style.height = 0.7*pageWidth/nRows + "px";
dynamicSizeCells[i].style.backgroundColor = "green";
}
console.warn("Div width is " + tableDiv.style.width + ", div height is " + tableDiv.style.height + "; cell width is " + dynamicSizeCells[0].style.width + ", cell height is " + dynamicSizeCells[0].style.height);
}
const theTable = constructTable(nRows, nColumns);
showTable(theTable);
body {
background-color: darkblue;
}
#tableDiv {
margin-left: 15%;
margin-top: 5%;
}
.testing {
background-color: "green";
}
<div id="tableDiv"></div>
I'm trying to construct a table dynamically, with a size determined by the current width of the browser window.
Since the table cells' sizes and their containing div's size are both being set relative to the window's width, the cells should fit exactly within the div. This is working perfectly for the width, but not for the height. The last row of cells appears to overhang the bottom of the div by a fractional amount.
Logging the sizes of the div and one of the table cells shows that they ought to align correctly, as the cell's height is exactly 1/10 of the div's height, and there are 10 rows of cells. However, the visual doesn't match, even though the math works out as expected.
What is causing the discrepancy between the calculated and displayed heights?
const pageWidth = document.documentElement.scrollWidth;
const nRows = 10; const nColumns = 10;
const tableDiv = document.getElementById("tableDiv");
tableDiv.style.width = 0.7*pageWidth + "px";
tableDiv.style.height = 0.7*pageWidth + "px";
tableDiv.style.backgroundColor = "yellow";
// Dynamically generate a table of the specified dimensions
function constructTable(nR, nC) {
const tbl = document.createElement("table"); tbl.id = "test table";
var tRow; var tCell;
for (let r = 0; r < nR; r++) { // Use 'let,' not 'var,' or else all row/column numbers will be set to the final (maximum) values of r and c
tRow = document.createElement("tr");
tbl.appendChild(tRow);
for (let c = 0; c < nC; c++) {
tCell = document.createElement("td"); tCell.className = "testing"; tRow.appendChild(tCell);
}
}
return tbl;
}
function showTable(t) {
tableDiv.innerHTML = "";
tableDiv.appendChild(t);
const dynamicSizeCells = document.getElementsByClassName("testing");
for (var i = 0; i < dynamicSizeCells.length; i++) {
dynamicSizeCells[i].style.width = 0.7*pageWidth/nColumns + "px";
dynamicSizeCells[i].style.height = 0.7*pageWidth/nRows + "px";
dynamicSizeCells[i].style.backgroundColor = "green";
}
console.warn("Div width is " + tableDiv.style.width + ", div height is " + tableDiv.style.height + "; cell width is " + dynamicSizeCells[0].style.width + ", cell height is " + dynamicSizeCells[0].style.height);
}
const theTable = constructTable(nRows, nColumns);
showTable(theTable);
body {
background-color: darkblue;
}
#tableDiv {
margin-left: 15%;
margin-top: 5%;
}
.testing {
background-color: "green";
}
<div id="tableDiv"></div>
Share
Improve this question
edited Mar 17 at 3:05
Spectric
32.4k6 gold badges29 silver badges54 bronze badges
asked Mar 17 at 1:58
Quack E. DuckQuack E. Duck
7183 gold badges8 silver badges25 bronze badges
3
- 2 Recommend you edit the title of this post. The problem is completely unrelated to the fact that you’ve used Javascript to generate the table. – Brett Donald Commented Mar 17 at 3:43
- @BrettDonald The original title was different but cumbersome. Do you have any suggestions? :) – Quack E. Duck Commented Mar 17 at 3:46
- 1 “Responsive table with square cells” – Brett Donald Commented Mar 17 at 4:10
3 Answers
Reset to default 1The issue lies within the border-spacing
. By default, a 2px
border spacing exists between adjacent cells. You have to factor this into your calculation by subtracting two from the final height (starting from the second row).
Result:
const pageWidth = document.documentElement.scrollWidth;
const nRows = 10; const nColumns = 10;
const tableDiv = document.getElementById("tableDiv");
tableDiv.style.width = 0.7*pageWidth + "px";
tableDiv.style.height = 0.7*pageWidth + "px";
tableDiv.style.backgroundColor = "yellow";
// Dynamically generate a table of the specified dimensions
function constructTable(nR, nC) {
const tbl = document.createElement("table"); tbl.id = "test table";
var tRow; var tCell;
for (let r = 0; r < nR; r++) { // Use 'let,' not 'var,' or else all row/column numbers will be set to the final (maximum) values of r and c
tRow = document.createElement("tr");
tbl.appendChild(tRow);
for (let c = 0; c < nC; c++) {
tCell = document.createElement("td"); tCell.className = "testing"; tRow.appendChild(tCell);
}
}
return tbl;
}
function showTable(t) {
tableDiv.innerHTML = "";
tableDiv.appendChild(t);
const dynamicSizeCells = document.getElementsByClassName("testing");
for (var i = 0; i < dynamicSizeCells.length; i++) {
dynamicSizeCells[i].style.width = 0.7*pageWidth/nColumns + "px";
// only subtract 2 starting from the second row!
dynamicSizeCells[i].style.height = 0.7*pageWidth/nRows + (i > nRows * (nColumns - 1) ? 0 : -2) + "px";
dynamicSizeCells[i].style.backgroundColor = "green";
}
//console.warn("Div width is " + tableDiv.style.width + ", div height is " + tableDiv.style.height + "; cell width is " + dynamicSizeCells[0].style.width + ", cell height is " + dynamicSizeCells[0].style.height);
}
const theTable = constructTable(nRows, nColumns);
showTable(theTable);
body {
background-color: darkblue;
}
#tableDiv {
margin-left: 15%;
margin-top: 5%;
}
.testing {
background-color: "green";
box-sizing: border-box;
}
<div id="tableDiv"></div>
So why doesn't this affect the table horizontally?
It does. However, since the table-layout
is set to auto
, the cell widths are automatically shrunk to fit the width of the table.
If we set the table-layout
to fixed
, you will see the effect happen on both axes.
I've minified the code so it won't take up half the screen; it's just a demonstration anyways.
const pageWidth=document.documentElement.scrollWidth,nRows=10,nColumns=10,tableDiv=document.getElementById("tableDiv");function constructTable(t,l){var n,a,o=document.createElement("table");o.id="test table",o.style.width=.7*pageWidth+"px";for(let e=0;e<t;e++){n=document.createElement("tr"),o.appendChild(n);for(let e=0;e<l;e++)(a=document.createElement("td")).className="testing",n.appendChild(a)}return o}function showTable(e){tableDiv.innerHTML="",tableDiv.appendChild(e);for(var t=document.getElementsByClassName("testing"),l=0;l<t.length;l++)t[l].style.width=.7*pageWidth/nColumns+"px",t[l].style.height=.7*pageWidth/nRows+"px",t[l].style.backgroundColor="green"}tableDiv.style.width=.7*pageWidth+"px",tableDiv.style.height=.7*pageWidth+"px",tableDiv.style.backgroundColor="yellow";const theTable=constructTable(nRows,nColumns);showTable(theTable);
table{table-layout:fixed}body{background-color:#00008b}#tableDiv{margin-left:15%;margin-top:5%}.testing{background-color:"green"}
<div id="tableDiv"></div>
I’m trying to construct a table dynamically, with a size determined by the current width of the browser window.
This is actually very easy to do. Just use vw
units to size your table (or your wrapper element). 70% of the window width is 70vw
:
table {
width: 70vw;
height: 70vw;
}
Even better, use aspect-ratio
to set the height equal to the width:
table {
width: 70vw;
aspect-ratio: 1;
}
You do not need to specify sizes for the cells, they take care of themselves.
const makeTableMarkup = (rows, cols) => {
const a = ['<table>']
for (let r = 0; r < rows; r++) {
a.push('<tr>')
for (let c = 0; c < cols; c++) {
a.push('<td></td>')
}
a.push('</tr>')
}
a.push('</table>')
return a.join('')
}
document.querySelectorAll('.d').forEach(d => {
d.innerHTML = makeTableMarkup(d.dataset.rows, d.dataset.cols)
})
body {
background-color: darkblue;
margin: 1em;
display: flex;
justify-content: center;
gap: 1em;
}
.d {
width: 25vw;
aspect-ratio: 1; /* makes height equal to width */
background-color: yellow;
table {
width: 100%; /* stretch to fill the wrapper div */
height: 100%; /* stretch to fill the wrapper div */
}
td {
background-color: green;
}
}
<div class="d" data-rows="10" data-cols="10"></div>
<div class="d" data-rows="5" data-cols="10"></div>
<div class="d" data-rows="10" data-cols="5"></div>
After running this snippet, use the full page link to test the responsive behaviour.
Your issue is "not consider row-space of tr elements". And, px value should be integer value. So, I'd modified some to calc correct height of div and row height.
const pageWidth = document.documentElement.scrollWidth;
const nRows = 10; const nColumns = 10;
const tableDiv = document.getElementById("tableDiv");
const rowHeight = Math.round(0.7*pageWidth/nRows);
tableDiv.style.width = 0.7*pageWidth + "px";
//tableDiv.style.height = 0.7*pageWidth + "px";
tableDiv.style.height = (rowHeight * nRows + 8 * (nRows-1)) + "px";
tableDiv.style.backgroundColor = "yellow";
// Dynamically generate a table of the specified dimensions
function constructTable(nR, nC) {
const tbl = document.createElement("table"); tbl.id = "test table";
var tRow; var tCell;
for (let r = 0; r < nR; r++) { // Use 'let,' not 'var,' or else all row/column numbers will be set to the final (maximum) values of r and c
tRow = document.createElement("tr");
tbl.appendChild(tRow);
for (let c = 0; c < nC; c++) {
tCell = document.createElement("td");
tCell.className = "testing";
tCell.innerHtml = c + 1;
tRow.appendChild(tCell);
}
}
return tbl;
}
function showTable(t) {
tableDiv.innerHTML = "";
tableDiv.appendChild(t);
const dynamicSizeCells = document.getElementsByClassName("testing");
for (var i = 0; i < dynamicSizeCells.length; i++) {
dynamicSizeCells[i].style.width = 0.7*pageWidth/nColumns + "px";
dynamicSizeCells[i].style.height = rowHeight + "px";
dynamicSizeCells[i].style.backgroundColor = "green";
}
console.warn("Div width is " + tableDiv.style.width + ", div height is " + tableDiv.style.height + "; cell width is " + dynamicSizeCells[0].style.width + ", cell height is " + dynamicSizeCells[0].style.height);
}
const theTable = constructTable(nRows, nColumns);
showTable(theTable);
body {
background-color: darkblue;
overflow-x: hidden;
}
#tableDiv {
margin-left: 15%;
margin-top: 5%;
}
.testing {
background-color: "green";
}
<div id="tableDiv"></div>