Avoid page break happening between two specific rows - html

This answer helps to avoid a page break inside a single row of a table, however I am looking for a way to prevent a page break from occurring between two different rows. Let me explain my situation (apologies for formatting):
header: | Col1 | Col2 | Col3 | Col4 |
row 1: | Val1 | Val2 | Val3 | Val4 |
row 2: | Value relating to 1,2,3,4 |
row 3: | Val5 | Val6 | Val7 | Val8 |
row 4: | Value relating to 5,6,7,8 |
I have a table in which every two rows are related to each other, and should not be shown on separate pages. The second row in each pair has a single value that should be able to span over all the columns of that row.
I have tried the following using page-break-inside: avoid:
Putting the two rows inside a <div> tag
Having Col4 span over both rows (Col4 content just moves to next page)
Putting both rows into a table (loses alignment with headings)

You should use multiple <tbody> tags instead of <div>. The property page-break-inside: avoid must be set on the <tbody>.
In a HTML table you can set only one <thead> and <tfoot>, but several <tbody>.

You could use nested tables, i.e. each of the td cells in your current rows 1 and 3 could contain a table consisting of 1 column and 2 rows with 1 cell each, with the cell in the second row containing the related value to the first row.
So your rows 1 and 2 would become one row with 4 cells, each containing a nested table consisting of 2 rows with 1 cell each. The same for your current rows 3 and 4 etc.
Then you could apply page-break-inside: avoid to these nested tables.
.maintable {
width: 100%;
border-collapse: collapse;
}
.maintable > tbody > tr > th, .maintable > tbody > tr > td {
border: 1px solid #ddd;
}
.maintable > tbody > tr > td > table {
page-break-inside: avoid;
width: 100%;
border-collapse: collapse;
}
.maintable > tbody > tr > td > table tr:first-child td {
border-bottom: 1px solid #ddd;
}
<table class="maintable">
<tr>
<th>Header 1</th>
<th>Header 2</th>
<th>Header 3</th>
<th>Header 4</th>
</tr>
<tr>
<td>
<table>
<tr>
<td>value 1</td>
</tr>
<tr>
<td>related value 1a</td>
</tr>
</table>
</td>
<td>
<table>
<tr>
<td>value 2</td>
</tr>
<tr>
<td>related value 2a</td>
</tr>
</table>
</td>
<td>
<table>
<tr>
<td>value 3</td>
</tr>
<tr>
<td>related value 3a</td>
</tr>
</table>
</td>
<td>
<table>
<tr>
<td>value 4</td>
</tr>
<tr>
<td>related value 4a</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table>
<tr>
<td>value 5</td>
</tr>
<tr>
<td>related value 5a</td>
</tr>
</table>
</td>
<td>
<table>
<tr>
<td>value 6</td>
</tr>
<tr>
<td>related value 6a</td>
</tr>
</table>
</td>
<td>
<table>
<tr>
<td>value 7</td>
</tr>
<tr>
<td>related value 7a</td>
</tr>
</table>
</td>
<td>
<table>
<tr>
<td>value 8</td>
</tr>
<tr>
<td>related value 8a</td>
</tr>
</table>
</td>
</tr>
</table>

<style type="text/css">
table{
border: 1px solid black;
border-collapse: collapse;
}
td{
border: 1px solid black;
}
</style>
<table style="border: 1px solid black">
<tr>
<td>value 1</td>
<td> value 2</td>
<td> value 3</td>
<td>value 4</td>
</tr>
<tr>
<td colspan="4"> Values ralted to 1, 2, 3, 4</td>
</tr>
</table>

Related

How to set HTML table column widths as a percentage (without table footer affecting table body)?

I'm really having a hard time understanding how to style column widths in a HTML table. I can't get my head around why percentage widths aren't applying and why columns inside tfoot affect column widths in tbody.
Can anyone shed some light on this and perhaps explain how I can make the columns within the tbody be set to one-third (33.333%) and columns in the tfoot be set to one-half (50%) and actually span the full width of the table (right now they only span across 2 columns above, rather than 3 columns)?
Any help/guidance would be most appreciated.
tbody,
tfoot {
width: 100%;
}
tbody tr td {
width: 33.333%;
}
tfoot tr th,
tfoot tr td {
width: 50%;
}
<table border="1">
<tbody>
<tr>
<td>Body Row 1 Column 1</td>
<td>Body Row 1 Column 2</td>
<td>Body Row 1 Column 3</td>
</tr>
</tbody>
<tfoot>
<tr>
<th>Footer Row 1 Column 1</th>
<td>Footer Row 1 Column 2</td>
</tr>
<tr>
<th>Footer Row 2 Column 1</th>
<td>Footer Row 2 Column 2</td>
</tr>
<tr>
<th>Footer Row 3 Column 1</th>
<td>Footer Row 3 Column 2</td>
</tr>
</tfoot>
</table>
If you are not restricted so that you have to use one table, why not just a table inside a table?
<tfoot>
<tr>
<td colspan="3">
<table>
<tbody>
<tr>
<td>First half</td>
<td>Second half</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tfoot>
Just make sure the styling applies just as well and give your table table { width: 100%; }, no border, margin, padding, etc..
I find the best solutions are those where you ignore the problem.

Make 1 table look like 2 on top of each other

I want to make 1 table to look like 2 tables where they are on top of each other with a little space between them. Each table has the same number of columns, but the text they contain can differ. And each table can contain many rows. I need this because i need columns of both tables always to be the same width. How do i achieve this? I need that Empty row's side borders to hide
<table>
<tr> <!-- First table rows --> </tr>
<td>text</td>
<td>text</td>
<tr> <!-- Empty space between tables --> </tr>
<tr> <!-- Second table rows --> </tr>
<td>text</td>
<td>text</td>
Just use a single <td> element with a specific height as a separator, and use border-collapse to mimic what you're looking for:
table {
border-collapse: collapse;
}
table td {
border: 1px solid #000;
}
table td.separator {
border: none;
height: 40px;
}
<table>
<tr>
<td>text</td>
<td>text</td>
</tr>
<tr>
<td>text</td>
<td>text</td>
</tr>
<tr>
<td colspan="2" class="separator"></td>
</tr>
<tr>
<td>text</td>
<td>text</td>
</tr>
<tr>
<td>text</td>
<td>text</td>
</tr>
</table>
You can use css for this. border-spacing
Change 45px for sizing
table {
border-collapse: collapse;
}
th {
background-color: red;
Color:white;
}
th, td {
width:150px;
text-align:center;
border:1px solid black;
padding:5px
}
.geeks {
border-right:hidden;
}
.gfg {
border-collapse:separate;
border-spacing:0 45px;
}
h1 {
color:green;
}
<!DOCTYPE html>
<html>
<head>
<style>
</style>
</head>
<body>
<center>
<h2>Row spacing in a table</h2>
<table>
<tr>
<th>Employee ID</th>
<th>Name</th>
<th>Gender</th>
<th>Age</th>
</tr>
</table>
<table class = "gfg">
<tr>
<td class = "geeks">10001</td>
<td>Thomas</td>
<td>M</td>
<td>32</td>
</tr>
<tr>
<td class = "geeks">10002</td>
<td>Sally</td>
<td>F</td>
<td>28</td>
</tr>
<tr>
<td class = "geeks">10003</td>
<td>Anthony</td>
<td>M</td>
<td>24</td>
</tr>
</table>
</center>
</body>
</html>
You could use something like shown below. The colspan="4" on table-spacing td specifies how many columns the cell should span.
Advice
However if the data is really different from each other I would recommend actually using two different tables instead of two . It make it easier for screen readers to distinct the data from each other. To improve this further you can use table headers to improve your accessibility even more.
Source: https://www.w3schools.com/tags/tag_thead.asp
.table {
border-collapse: collapse;
}
.table-spacing td {
border: none;
height: 15px; /* Increase/descrease for white-space between 'tables' */
}
td {
padding: 6px;
border: 1px solid black;
}
<table class="table">
<tr>
<td> Cel 1</td>
<td> Cel 2</td>
<td> Cel 3</td>
<td> Cel 4</td>
<tr>
<tr>
<td> Cel 5</td>
<td> Cel 6</td>
<td> Cel 7</td>
<td> Cel 8</td>
<tr>
<tr class="table-spacing"><td colspan="4"></td></tr>
<tr>
<td> Cel 1</td>
<td> Cel 2</td>
<td> Cel 3</td>
<td> Cel 4</td>
<tr>
<tr>
<td> Cel 5</td>
<td> Cel 6</td>
<td> Cel 7</td>
<td> Cel 8</td>
<tr>
</table>

align table header in one table to body in another table

I have two html tables. The first table is for the header and the second table is for the body. The reason for having two separate table is to be able to have a fixed header and a scrollable body.
How will I make the table header aligned with the table body?
Below is my code. current output
HTML
.scroll {
height: 100px;
overflow: auto;
}
#containerdiv {
width: 80%;
border: 2px solid brown;
}
<div id="containerdiv">
<div class="header">
<table>
<thead>
<!-- column names are going to be generated automatially with angular -->
<tr>
<th style="border: red solid 2px">Id</th>
<th style="border: red solid 2px">Customer Name</th>
<th style="border: red solid 2px">Address</th>
<th style="border: red solid 2px">Phone</th>
</tr>
</thead>
<!-- this is to set size for the column headers-->
<tbody>
<tr>
<td style="width:2%;"></td>
<td style="width:5%;"></td>
<td style="width:6%;"></td>
<td style="width:4%;"></td>
</tr>
</tbody>
</table>
</div>
<div class="scroll">
<table id="tablebody">
<tr>
<td style="width:4%;border: red solid 2px;">1</td>
<td style="width:5%;border: red solid 2px;">Customer 1</td>
<td style="width:6%;border: red solid 2px;">Address 1</td>
<td style="width:4%;border: red solid 2px;">phone number 1</td>
</tr>
<tr>
<td style="width:4%;border: red solid 2px;">2</td>
<td style="width:5%;border: red solid 2px;">Customer 2</td>
<td style="width:6%;border: red solid 2px;">Address 2</td>
<td style="width:4%;border: red solid 2px;">phone number 2</td>
</tr>
<tr>
<td style="width:4%;border: red solid 2px;">3</td>
<td style="width:5%;border: red solid 2px;">Customer 3</td>
<td style="width:6%;border: red solid 2px;">Address 3</td>
<td style="width:4%;border: red solid 2px;">phone number 3</td>
</tr>
<tr>
<td style="width:4%;border: red solid 2px;">4</td>
<td style="width:5%;border: red solid 2px;">Customer 4</td>
<td style="width:6%;border: red solid 2px;">Address 4</td>
<td style="width:4%;border: red solid 2px;">phone number 4</td>
</tr>
<tr>
<td style="width:4%;border: red solid 2px;">5</td>
<td style="width:5%;border: red solid 2px;">Customer 5</td>
<td style="width:6%;border: red solid 2px;">Address 5</td>
<td style="width:4%;border: red solid 2px;">phone number 5</td>
</tr>
</table>
</div>
</div>
Your main problem is that your widths 1. don't match, and more importantly 2. don't make sense.
Note that in your header, the first column inside the tbody is set at width: 2%, but the equivalent column in the next table is at width: 4%. Those values are gonna have to match, or things won't line up.
But more importantly, assuming we change that 2% to 4%, your columns only add up to 19% wide.
Percentage widths are based on their parents, not on the overall page width. So since you have set #containerdiv to 80% wide, by setting a column to 4% wide, you're making that column 4% of 80% of the page width = 0.32% of the page width.
What you really want to do is think of the table as 100% wide, and divide your columns up so their widths add up to 100%.
#containerdiv {
width: 80%;
}
#containerdiv table {
width: 100%;
}
#containerdiv table td:nth-child(1) { /* first column */
width: 15%;
}
/* and so on for other columns */
The other thing you can do to make this easier is to use box-sizing to include borders in the widths of your columns, so if you want a column to be, say, 25% wide with a 4 pixel border, you don't have to worry about setting a width like calc(25% - 4px). That is, if you want to continue with non-collapsed borders and spacing between table cells.
Lastly, note that your border shorthand property was out of order. It should be border-width, border-style, then border-color.
In this example, I took all your inline styles out and moved them into the stylesheet to make things easier to visualize, but if you're going to end up with inline styles in your app, that's fine. Follow the principles here, and it'll work:
.scroll {
height: 100px;
overflow: auto;
}
#containerdiv {
width: 80%;
border: 2px solid brown;
}
#containerdiv table {
width: 100%;
}
.header table {
padding-right: 17px;
}
#containerdiv table * {
box-sizing: border-box;
}
#containerdiv th,
#containerdiv td {
border: 2px solid red;
}
#containerdiv .header tbody td {
border: none;
}
#containerdiv th:nth-child(1),
#containerdiv td:nth-child(1) {
width: 15%;
}
#containerdiv th:nth-child(2),
#containerdiv td:nth-child(2) {
width: 30%;
}
#containerdiv th:nth-child(3),
#containerdiv td:nth-child(3) {
width: 30%;
}
#containerdiv th:nth-child(4),
#containerdiv td:nth-child(4) {
width: 25%;
}
<div id="containerdiv">
<div class="header">
<table>
<thead>
<!-- column names are going to be generated automatially with angular -->
<tr>
<th>Id</th>
<th>Customer Name</th>
<th>Address</th>
<th>Phone</th>
</tr>
</thead>
<!-- this is to set size for the column headers-->
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
<div class="scroll">
<table id="tablebody">
<tr>
<td>1</td>
<td>Customer 1</td>
<td>Address 1</td>
<td>phone number 1</td>
</tr>
<tr>
<td>2</td>
<td>Customer 2</td>
<td>Address 2</td>
<td>phone number 2</td>
</tr>
<tr>
<td>3</td>
<td>Customer 3</td>
<td>Address 3</td>
<td>phone number 3</td>
</tr>
<tr>
<td>4</td>
<td>Customer 4</td>
<td>Address 4</td>
<td>phone number 4</td>
</tr>
<tr>
<td>5</td>
<td>Customer 5</td>
<td>Address 5</td>
<td>phone number 5</td>
</tr>
</table>
</div>
</div>
Edit regarding scrollbar: I have fixed the scrollbar issue on PC by adding padding-right to the only first table, so that there is a gap to the right of it where the scrollbar appears next to the second table. I chose 17px as the value because that's the scrollbar width for the most common browsers on Windows. But note that this isn't a perfect solution because not all browsers' scrollbars are exactly the same width.
A real-life perfect execution of that approach would use JavaScript to detect the scrollbar width and then set the padding-right accordingly.
However, an alternate approach that doesn't require any JavaScript is to set the table widths in viewport units, for example, to 75vw.
That's because 100vw is equivalent to the entire width of the window, including the scrollbar, whereas 100% (on body) is equivalent to the window width to the left of the scrollbar. So basically using vw units would let you ignore the scrollbar so that both tables come out the same width. Just choose a value that's small enough to leave space for the scrollbar on the bottom table, and the top table will match, even though it doesn't have a scrollbar.
Finally, note that all of this is really just to get around problems you're causing for yourself by the overall approach you're using here of using two separate tables to achieve the fixed header. Really, in my opinion, you should only have one table and just freeze the thead in place and be done with it. Then you wouldn't even have the scrollbar issue. Revising the whole thing to work that way is beyond the scope of this question, but it's something for you to consider.
I would use one table and fix the header like below.
Note: in <th> tags, the text has to be placed twice: once in a <div> (this will be the fixed one) and once normally (this will stay inside the table structure and ensure column width). Latter one can be hidden with some additional styling.
thead th div {
position: fixed;
}
<table>
<thead>
<tr>
<th>
<div>header 1 which is longer</div>
header 1 which is longer
<!-- yes, it's needed! -->
</th>
<th>
<div>header 2</div>
header 2
<!-- yes, it's needed! -->
</th>
</tr>
</thead>
<tbody>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
<tr>
<td>content 1</td>
<td>content 2</td>
</tr>
</tbody>
</table>

Is there a way to make one <td> display on its own row?

I need to make one row contain 4 cells as follows: the first three cells on one line and the last cell takes its own line under the first three spanning across all of them. Like so:
---------------------------------- <---Start Row
| | | |
| Cell 1 | Cell 2 | Cell 3 |
| | | |
----------------------------------
| |
| Cell 4 |
| |
---------------------------------- <---End Row
Is there a way in HTML to do this?
You're looking for the colspan attribute...
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
</tr>
<tr>
<td colspan="3">Cell 4</td>
</tr>
The colspan will allow you to "span" a single cell over multiple columns. The vertical partner to this attribute is rowspan which will allow you to span a single cell over multiple rows
However, in direct answer to your question, I do not believe it is possible have the 4th cell within a row appear on the next row.
My understanding is that you will have to create 2 separate rows to achieve what you're after. (I will be happy to remove my answer should somebody prove me wrong)
Based on the above, if a jQuery answer is acceptable, you could do the following...
$(function() {
// Get the last child, detach from the row and add colspan
$lastTd = $("table tr td:last-child").detach().attr("colspan", "3");
// Create a new row, add the detached cell, and add to the table
$("table").append($("<tr></tr>").append($lastTd));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table border="1">
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
<td>Cell 4</td>
</tr>
</table>
Not sure how clean this might be But My solution is with single tr and 4 td's
td {
border: 1px solid black;
}
tr{
width:120px;
height:50px;
display: table-caption;
}
tr >td{
width:40px;
}
tr > td:nth-child(4)
{
width:120px;
position:absolute;
display:block;
}
<table>
<tbody>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>full width td</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>full width td</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>full width td</td>
</tr>
</tbody>
</table>

align scrollable table columns with header in css

JsFiddle URL : http://jsfiddle.net/gfy4pwrr/1
<table cellspacing="0" cellpadding="0" border="0" width="325" >
<tr>
<td>
<table cellspacing="0" cellpadding="1" border="1" width="300" >
<tr>
<th>Full Name</th>
<th>Status</th>
<th>Last reported</th>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<div class ='cont' style="width:325px; height:48px; overflow:auto;">
<table class='data' cellspacing="0" cellpadding="1" border="1" width="300" >
<tr>
<td>col 1 data 1</td>
<td>col 2 data 1</td>
<td>col 3 data 1</td>
</tr>
<tr>
<td>col 1 data 2</td>
<td>col 2 data 2</td>
<td>col 3 data 2</td>
</tr>
<tr>
<td>col 1 data 3</td>
<td>col 2 data 3</td>
<td>col 3 data 3</td>
</tr>
</table>
</div>
</td>
</tr>
</table>
The columns are not aligned with the headers.
I want the table used for data to be aligned with the headers.
td width=100px for second table is not working.
I would get rid of the nested tables and use the semantics of the table element according to the w3c specs. The trick is to use the right elements but manipulate the way the browser displays them. <table>, <thead> and <tbody> can be displayed as block elements while every row can be a table (leaving <td> and <th> displayed as table-cell by default).
I've demonstrated it in a JSFiddle. But it basically comes down to a simple table structure:
<table>
<thead>
<tr>
<th>Full Name</th>
<th>Status</th>
<th>Last reported</th>
</tr>
</thead>
<tbody>
<tr>
<td>col 1 data 1</td>
<td>col 2 data 1</td>
<td>col 3 data 1</td>
</tr>
</tbody>
</table>
And setting the display properties in css with an overflow on <tbody>:
table, tbody, thead {
display: block;
}
tbody, thead {
overflow-y: scroll;
}
tbody {
height: 100px;
}
tr {
display: table;
...
}
To come back to the problem with the column width's. There is no other way solving that than setting the same width on each cell in each table (<tr>). In the fiddle I set it to 33.33%:
td , th {
width: 33.33%;
...
}
For Windows it is necessary to show the scrollbar in <thead> otherwise it doesn't size the same as <tbody>. To hide it there is a small trick:
thead {
margin-right: -300px;
padding-right: 300px;
}
It's not that the "columns are not aligned with the headers", the problem is that your second table does NOT have any header. You just have nested tables. One with headers th and second with no header, just td.
Basically your thare not in the same column as your td
So both tables, even if the width is the same, will adjust the width of the cells depending on the content inside. It's just happen all your tdhave same content (in number of charachters) so the effect was that they are slightly missaligned.
However if you set a fixed width to both thand tdand display them as ìnline-block`elements they will align: FIDDLE
However I don't recomend to change the display of the cells on a pure html table. You may have headaches incoming. (and also I don't recomend tthe use of nested tables... I had so many headaches back then when layouts were made that way... ty explorer)
Collapse the borders: border-collapse: collapse; and set box-sizing: border-box;
http://jsfiddle.net/gfy4pwrr/6/
* {
box-sizing: border-box;
}
table {
border-collapse: collapse;
}
td, th {
/* if it is 100px the overflow content in the first column "push" the border ?? */
width: 99px;
max-width: 99px;
overflow: hidden;
}
<table cellspacing="0" cellpadding="0" border="0" width="325">
<tr>
<td>
<table cellspacing="0" cellpadding="1" border="1" width="300">
<tr>
<th>Full Name</th>
<th>Status</th>
<th>Last reported</th>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<div class='cont' style="width:325px; height:48px; overflow:auto;">
<table class='data' cellspacing="0" cellpadding="1" border="1" width="300">
<tr>
<td>VeryOverflowContent long long long content</td>
<td>OverflowContent</td>
<td>col 3 data 1</td>
</tr>
<tr>
<td>col 1 data 2</td>
<td>col 2 data 2</td>
<td>col 3 data 2</td>
</tr>
<tr>
<td>col 1 data 3</td>
<td>col 2 data 3</td>
<td>col 3 data 3</td>
</tr>
</table>
</div>
</td>
</tr>
</table>
I guest you want a fixed header table.I recommend you change your html to easy build a fixed header table.
Here's my suggestion:
<div class="table-header">
<table>
<thead>
<tr>
<th>Full Name</th>
<th>Status</th>
<th>Last reported</th>
</tr>
</thead>
</table>
</div>
<div class="table-content">
<table>
<thead>
<tr>
<th>Full Name</th>
<th>Status</th>
<th>Last reported</th>
</tr>
</thead>
<tbody>
<tr>
<td>col 1 data 1</td>
<td>col 2 data 1</td>
<td>col 3 data 1</td>
</tr>
<tr>
<td>col 1 data 2</td>
<td>col 2 data 2</td>
<td>col 3 data 2</td>
</tr>
<tr>
<td>col 1 data 3</td>
<td>col 2 data 3</td>
<td>col 3 data 3</td>
</tr>
</tbody>
</table>
</div>
and css:
.table-header
{ padding-right:13.5px;
}
.table-header table
{
height:20px;
}
.table-header thead tr
{
background:#fff;
z-index:10000;
}
.table-content
{
max-height:250px;
overflow-y:auto;
overflow-x:hidden;
margin-top:-20px;
}
.table-content thead
{
visibility:collapse;
}
table
{
border-collapse: collapse;
}
table th, td
{
border: 1px solid black;
width:200px;
text-align:center;
padding:0;
}
look at:http://jsfiddle.net/chuongxl/gfy4pwrr/51/
or you can use this plugin http://www.fixedheadertable.com/