I am working on my own website and not good with codes yet. When I am scrolling down I want to appear another content of the navbar and when I am on the top, original navbar is appearing. I want this to be done in pure JavaScript with no libraries or framewokrs. Please see codes below and I know that codes are not organised. I will do that later on.
var nav = document.querySelector("nav");
var hide = document.querySelector(".hide");
var appear = document.querySelector(".appear")
window.onscroll = function(){
if(document.body.scrollTop > 70){
hide.style.display = "block";
appear.style.display = "none"
} else {
hide.style.display = "none";
appear.style.display = "block"
}
}
nav{
list-style-type: none;
text-align: center;
background-color: #3FA9A5;
position: sticky;
top: 0;
}
.hide{
font-size: 70px;
font-family: 'Long Cang', cursive;
display: block;
}
.appear{
height: 70px;
display: none;
}
.appear img{
width: 210px;
}
ul{
margin: 0 auto;
padding: 0;
}
body{
margin: 0;
}
.container{
max-width: 1080px;
width: 95%;
margin: 10px auto;
display: grid;
grid-template-columns: 25% 50% 25%;
}
.text{
text-align: center;
}
.profile {
border: 1px solid black;
padding: 0 10px 20px 10px;
}
#main{
width: 100%;
}
.post{
margin-left: 4.165%;
}
#image{
width: 100%;
}
#post-divide{
margin-left: 10px;
margin-right: 10px;
}
.comments{
width: 100%;
margin-top: 68.5px;
padding-bottom: 293.5px;
border: 1px solid black;
}
h2{
text-align: center;
}
.center{
grid-column: 2;
}
<link rel="stylesheet" type="text/css" href="test.css">
<link href="https://fonts.googleapis.com/css?family=Indie+Flower|Long+Cang&display=swap" rel="stylesheet">
<title>test</title>
</head>
<body>
<nav>
<ul>
<li class="hide">Unknown</li>
<li class="appear"><img src="cat.png"></li>
</ul>
</nav>
<div class="container">
<div class="col-1">
<div class="profile text">
<img id="main" src="https://data.whicdn.com/images/86629641/superthumb.jpg?t=1384568664">
<hr>
<p>12 posts</p>
<p>instagram</p>
<button>Subscribe!</button>
</div>
</div>
<div class="col-1">
<div class="post">
<h2>TITLE</h2>
<div>
<img id="image" src="https://i.pinimg.com/originals/76/d4/8c/76d48cb2928845dfcfab697ac7cbcf1c.jpg">
</div>
<hr id="post-divide">
</div>
</div>
<div class="col-1">
<div class="comments text"></div>
</div>
<div class="col-1 center">
<div class="post">
<h2>TITLE</h2>
<div>
<img id="image" src="https://i.pinimg.com/originals/76/d4/8c/76d48cb2928845dfcfab697ac7cbcf1c.jpg">
</div>
<hr id="post-divide">
</div>
</div>
<div class="col-1">
<div class="comments text"></div>
</div>
</div>
I think I should add something to the JS code but don't know why
Would be thankful if you would advise me how could I write HTML/CSS code so I do not have to create 2 navbars if it is possible
The following instruction:
document.querySelector("hide");
Will query for elements like:
<hide></hide>
Since plain selectors without prefix (div, header, span) will query for the whole element tags, not for classes or attrbitues.
Maybe you meant to query for the class, using the .:
document.querySelector(".hide");
var hide = document.querySelector(".hide");
var appear = document.querySelector(".appear")
So you should use class selector
You are using "hide" and "appear" as selectors but they do not exist in your HTML.
Use ".hide" and ".appear" in your querySelector instead.
var hide = document.querySelector(".hide");
var appear = document.querySelector(".appear");
Since both navbars have a static data, I would suggest to keep both of them and follow with answers of guys, that suggested to update querySelector param. Or you can hide/show the data inside of navbar (in your case it's only ul element) and leave the whole navbar always visible. So you can put classes appear/hide on ul element instea of navbar and then in JS get them with document.querySelector('.navbar .hide') and document.querySelector('.navbar .appear').
Using framework/library will definitely simplify it.
However, if you still want to have only one navbar in pure js/html/css (or it's data just dynamic) I would probably do like this:
HTML:
<nav class="navbar">
<ul>
<li><img src="cat.png"></li>
</ul>
</nav>
somewhere in JS:
var navbarUl = document.querySelector('.navbar ul');
window.onscroll = function() {
if (document.body.scrollTop > 70) {
navbarUl.innerHtml = '';
navbarUl.appendChild(getTopNavbarHTML);
} else {
navbarUl.innerHtml = '';
navbarUl.appendChild(getNavbarHTML);
}
}
getNavbarHTML and getTopNavbarHTML - will return documentFragment with li elements, see for details https://www.w3schools.com/jsref/met_document_createdocumentfragment.asp
But changing DOM during a scroll event can drastically decrease performance of a web app
I am trying to nest tables within a table row, while maintaining the appearance of a single table, as shown in the example below (a table with a single row with a data value and two nested tables, one 2x2 and the other 3x3) :
This is just an example; the actual table has significantly more rows and columns. I want to use tables because of the natural reflowing of column widths and row heights to fit the table data without having to worry about the container size (i.e. table width = 100%).
The problem I am having is that the tallest table sets the row height, but the other tables don't expand to fill that height, so the internal borders don't stretch from top to bottom as shown in the result of this snippet:
.display {
border-collapse: collapse;
}
.display, .display td, .display th {
border: 1px solid black;
}
.subtable {
border-collapse: collapse;
}
.subtable td {
border-top: 0;
border-bottom: 1px solid black;
border-left: 0;
border-right: 1px solid black;
}
.subtable tr td:last-of-type {
border-top: 0;
border-bottom: 1px solid black;
border-left: 0;
border-right: 0;
}
.subtable tr:last-of-type td {
border-top: 0;
border-bottom: 0;
border-left: 0;
border-right: 1px solid black;
}
.subtable tr:last-of-type td:last-of-type {
border: 0;
}
td {
padding: 5px;
}
td.d-subtable {
padding: 0;
}
<table class="display" cellpadding="0">
<tr><th>Customer</th><th>Items</th><th>Payments</th></tr>
<tr><td>Customer Name</td>
<td class="d-subtable"><table class="subtable" cellpadding="0"><tr><td>Item1</td><td>5</td><td>$400.00</td></tr><tr><td>Item2</td><td>10</td><td>$200.00</td></tr><tr><td>Item3</td><td>2</td><td>$500.00</td></tr></table></td>
<td class="d-subtable"><table class="subtable" cellpadding="0"><tr><td>12 Sep 2018</td><td>$3,000.00</td></tr><tr><td>18 Sep 2018</td><td>$2,000.00</td></tr></table></td>
</tr>
</table>
Now I know I can resolve this problem using rowspan (and that is how I am currently solving the problem) but that requires deciding in advance which rows to line up and that can lead to issues such as that generated by the below snippet, where it would clearly be better if I'd applied rowspan="2" to the first row (instead of the last row) of the table with 2 rows:
td {
border: 1px solid black;
}
table {
border-collapse: collapse;
width: 500px;
}
<table cellpadding="5">
<tr><td rowspan="3">x</td>
<td>problem when you have some really long text in the first row</td><td>p</td><td>a</td><td>b</td><td>c</td></tr><tr><td rowspan="2">z</td><td rowspan="2">q</td><td>d</td><td>e</td><td>f</td></tr><tr><td>g</td><td>some other really long text</td><td>i</td>
</tr>
</table>
I would prefer the above table to look like this:
Is there a way to achieve what I want using HTML/CSS? There are a lot of rows in the table so I'd prefer the browser sort it out before rendering. However if it's not possible I'm open to a Javascript/JQuery solution.
Update
Although I did find a workable solution at the time (see my posted answer) I have since encountered some situations where setting the widths of the columns in advance (even as percentages) was difficult owing to not being able to anticipate all the possible data to be displayed. So I'm hoping to find an answer that doesn't rely on doing that.
Since I didn't make it as clear as I should have, I have multiple rows in which I want to nest tables, keeping the heights matched as well as the column widths. For example, for two rows, I would like to be able to create a layout like this:
Where with raw table HTML the result looks like this:
.display {
border-collapse: collapse;
}
.display, .display td, .display th {
border: 1px solid black;
}
.subtable {
border-collapse: collapse;
}
.subtable td {
border-top: 0;
border-bottom: 1px solid black;
border-left: 0;
border-right: 1px solid black;
}
.subtable tr td:last-of-type {
border-top: 0;
border-bottom: 1px solid black;
border-left: 0;
border-right: 0;
}
.subtable tr:last-of-type td {
border-top: 0;
border-bottom: 0;
border-left: 0;
border-right: 1px solid black;
}
.subtable tr:last-of-type td:last-of-type {
border: 0;
}
td {
padding: 5px;
}
td.d-subtable {
padding: 0;
}
<table class="display" cellpadding="0">
<tr><th>Customer</th><th>Items</th><th>Payments</th></tr>
<tr><td>Customer 1</td>
<td class="d-subtable"><table class="subtable" cellpadding="0"><tr><td>Item1</td><td>5</td><td>$400.00</td></tr><tr><td>Item2</td><td>100</td><td>$20.00</td></tr><tr><td>Item3</td><td>2</td><td>$500.00</td></tr></table></td>
<td class="d-subtable"><table class="subtable" cellpadding="0"><tr><td>12 Sep 2018</td><td>$3,000.00</td></tr><tr><td>18 Sep 2018</td><td>$2,000.00</td></tr></table></td>
</tr>
<tr><td>Customer 304</td>
<td class="d-subtable"><table class="subtable" cellpadding="0"><tr><td>Item4</td><td>5</td><td>$6.00</td></tr></table></td>
<td class="d-subtable"><table class="subtable" cellpadding="0"><tr><td>20 Sep 2018</td><td>$4.00</td></tr><tr><td>27 Sep 2018</td><td>$26.00</td></tr></table></td>
</tr>
</table>
I would suggest the use of flex to achieve your need. Flex is very powerful for this kind of layout as we can easily let the content guide it. Please, see the attached snippet. It is purely made from HTML and CSS. No fixed sizes and no Javascript required.
(old snippet)
.outer {
display: flex;
flex-wrap: wrap;
/* For demo purposes */
max-width: 500px;
margin: 20px auto;
border-left: 1px solid black;
border-top: 1px solid black;
}
.column {
flex: 1 1 auto;
display: flex;
flex-direction: column;
flex-wrap: wrap;
}
.row {
display: flex;
flex-direction: row;
flex: 1 1 auto;
}
.inner {
flex: 1 1 auto;
display: flex;
flex-direction: column;
}
.item {
border-right: 1px solid black;
border-bottom: 1px solid black;
text-align: center;
padding: 3px;
}
.item.heading {
font-weight: bold;
}
.item:not(.heading) {
flex: 1 1 auto;
justify-content: center;
align-items: center;
display: flex;
}
.fixed .narrow {
flex-basis: 20px;
}
<div class="outer">
<div class="column">
<div class="item heading">Customer</div>
<div class="item">
<span>Customer Name</span>
</div>
</div>
<div class="column">
<div class="item heading">Items</div>
<div class="inner fixed">
<div class="row">
<div class="item">Item1</div>
<div class="item narrow">5</div>
<div class="item last">$400.00</div>
</div>
<div class="row">
<div class="item">Item2</div>
<div class="item narrow">10</div>
<div class="item last">$200.00</div>
</div>
<div class="row">
<div class="item">Item3</div>
<div class="item narrow">2</div>
<div class="item last">$500.00</div>
</div>
</div>
</div>
<div class="column">
<div class="item heading">Payments</div>
<div class="inner">
<div class="row">
<div class="item">12 sep 2018</div>
<div class="item">$3,000.00</div>
</div>
<div class="row">
<div class="item">
18 sep 2018
</div>
<div class="item">
$2,000.00
</div>
</div>
</div>
</div>
</div>
Update: Changed according to your comment/answer. It somewhat depends on your HTML structure. I had to move the headings to its own ".row.row-item" and therefor needed to set a flex-basis to align the columns. This can be extended with multiple ".row.row-item". See snippet below.
.outer {
display: flex;
flex-wrap: wrap;
/* For demo purposes */
max-width: 600px;
margin: 20px auto;
border-left: 1px solid black;
border-top: 1px solid black;
}
.column {
flex: 1 1 33.33%;
display: flex;
flex-direction: column;
flex-wrap: wrap;
}
.row {
display: flex;
flex-direction: row;
flex: 1 1 auto;
}
.row-item {
flex-basis: 100%;
}
.inner {
flex: 1 1 auto;
display: flex;
flex-direction: column;
}
.item {
border-right: 1px solid black;
border-bottom: 1px solid black;
text-align: center;
}
.item.heading {
font-weight: bold;
flex: 1 1 33.33%;
}
.item:not(.heading) {
flex: 1 1 33.33%;
justify-content: center;
align-items: center;
display: flex;
}
.fixed .narrow {
flex: 1 1 20px;
}
<div class="outer">
<div class="row row-item">
<div class="item heading">Customer</div>
<div class="item heading">Items</div>
<div class="item heading">Payments</div>
</div>
<div class="row row-item">
<div class="column">
<div class="item">
<span>Customer 1</span>
</div>
</div>
<div class="column">
<div class="inner fixed">
<div class="row">
<div class="item">Item1</div>
<div class="item narrow">5</div>
<div class="item last">$400.00</div>
</div>
<div class="row">
<div class="item">Item2</div>
<div class="item narrow">10</div>
<div class="item last">$200.00</div>
</div>
<div class="row">
<div class="item">Item3</div>
<div class="item narrow">2</div>
<div class="item last">$500.00</div>
</div>
</div>
</div>
<div class="column">
<div class="inner">
<div class="row">
<div class="item">12 sep 2018</div>
<div class="item">$3,000.00</div>
</div>
<div class="row">
<div class="item">
18 sep 2018
</div>
<div class="item">
$2,000.00
</div>
</div>
</div>
</div>
</div>
<div class="row row-item">
<div class="column">
<div class="item">
<span>Customer 304</span>
</div>
</div>
<div class="column">
<div class="inner fixed">
<div class="row">
<div class="item">Item4</div>
<div class="item narrow">5</div>
<div class="item last">$6.00</div>
</div>
</div>
</div>
<div class="column">
<div class="inner">
<div class="row">
<div class="item">20 sep 2018</div>
<div class="item">$4.00</div>
</div>
<div class="row">
<div class="item">
27 sep 2018
</div>
<div class="item">
$26.00
</div>
</div>
</div>
</div>
</div>
<div class="row row-item">
<div class="column">
<div class="item">
<span>Customer 605</span>
</div>
</div>
<div class="column">
<div class="inner fixed">
<div class="row">
<div class="item">Item5</div>
<div class="item narrow">50</div>
<div class="item last">$60.00</div>
</div>
<div class="row">
<div class="item">Item6</div>
<div class="item narrow">3</div>
<div class="item last">$260.00</div>
</div>
</div>
</div>
<div class="column">
<div class="inner">
<div class="row">
<div class="item">29 sep 2018</div>
<div class="item">$40.00</div>
</div>
<div class="row">
<div class="item">
30 sep 2018
</div>
<div class="item">
$206.00
</div>
</div>
</div>
</div>
</div>
</div>
I was eventually able to solve this by writing an onload function to find the maximum height of all the nested tables in a given row and then set the height of every nested table in that row to the same value.
window.onload=function () {
let rows = document.querySelectorAll('tr');
for (let r = 0; r < rows.length; r++) {
let subtables = rows[r].querySelectorAll('.subtable');
let maxHeight = 0;
for (let i = 0; i < subtables.length; i++) {
maxHeight = Math.max(maxHeight, subtables[i].clientHeight);
}
for (let i = 0; i < subtables.length; i++) subtables[i].style.height='' + maxHeight + 'px';
}
};
The only downside of this solution was that it meant I had to assign widths to the <td>s in the nested tables. However since I could use percentage widths this wasn't too big an issue for me:
<table class="display" cellpadding="0">
<tr><th>Customer</th><th>Items</th><th>Payments</th></tr>
<tr><td>Customer 1</td>
<td class="d-subtable"><table class="subtable" cellpadding="0"><tr><td width="35%">Item1</td><td width="20%">5</td><td width="45%">$400.00</td></tr><tr><td>Item2</td><td>10</td><td>$200.00</td></tr><tr><td>Item3</td><td>2</td><td>$500.00</td></tr></table></td>
<td class="d-subtable"><table class="subtable" cellpadding="0"><tr><td width="60%">12 Sep 2018</td><td width="40%">$3,000.00</td></tr><tr><td>18 Sep 2018</td><td>$2,000.00</td></tr></table></td>
</tr>
<tr><td>Customer 2</td>
<td class="d-subtable"><table class="subtable" cellpadding="0"><tr><td width="35%">Item4</td><td width="20%">5</td><td width="45%">$600.00</td></tr></table></td>
<td class="d-subtable"><table class="subtable" cellpadding="0"><tr><td width="60%">20 Sep 2018</td><td width="40%">$4,000.00</td></tr><tr><td>27 Sep 2018</td><td>$2,000.00</td></tr></table></td>
</tr>
</table>
Final output:
This example is a responsive design which utilizes only HTML and nested CSS Grids inside of a Flexbox.
I took the liberty of adding headers and a pagination placeholder to your scenario. These may be removed without affecting the rest of the layout.
I have created a GitHub repo nested-CSS-Grid-and-Flexbox-Playground which contains an Angular application utilizing this layout with dynamic data as well as references I accumulated while researching this project.
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<div class="container">
<div class="header">
<h1>Customers List</h1>
</div>
<div class="list">
<div class="customer-column-header">Customers</div>
<div class="invoice-column-header">Invoices</div>
<div class="payments-column-header">Payments</div>
<div class="customer-row">
<div class="customer-column">
<div>Acme Widget Manufacturing, Inc.</div>
</div>
<ul class="invoice-column">
<li class="invoice-row-header">
<div>Description</div>
<div>Quantity</div>
<div>Price</div>
</li>
<li class="invoice-row">
<div>Item 1</div>
<div>5</div>
<div>$400.00</div>
</li>
<li class="invoice-row">
<div>Item 2</div>
<div>10</div>
<div>$200.00</div>
</li>
<li class="invoice-row">
<div>Item 3</div>
<div>2</div>
<div>$500.00</div>
</li>
</ul>
<ul class="payment-column">
<li class="payment-row-header">
<div>Date</div>
<div>Amount</div>
</li>
<li class="payment-row">
<div>12 Sep 2018</div>
<div>$3,000.00</div>
</li>
<li class="payment-row">
<div>18 Sep 2018</div>
<div>$2,000.00</div>
</li>
<li class="payment-row">
<div>12 Sep 2018</div>
<div>$3,000.00</div>
</li>
<li class="payment-row">
<div>18 Sep 2018</div>
<div>$2,000.00</div>
</li>
</ul>
</div>
<div class="customer-row">
<div class="customer-column">
<div>Beta Company</div>
</div>
<ul class="invoice-column">
<li class="invoice-row-header">
<div>Description</div>
<div>Quantity</div>
<div>Price</div>
</li>
<li class="invoice-row">
<div>Item 1</div>
<div>5</div>
<div>$400.00</div>
</li>
<li class="invoice-row">
<div>Item 2</div>
<div>10</div>
<div>$200.00</div>
</li>
<li class="invoice-row">
<div>Item 3</div>
<div>2</div>
<div>$500.00</div>
</li>
</ul>
<ul class="payment-column">
<li class="payment-row-header">
<div>Date</div>
<div>Amount</div>
</li>
<li class="payment-row">
<div>12 Sep 2018</div>
<div>$3,000.00</div>
</li>
<li class="payment-row">
<div>18 Sep 2018</div>
<div>$2,000.00</div>
</li>
</ul>
</div>
</div>
<div class="pagination">
<p>Pagination Placeholder</p>
</div>
</div>
</body>
</html>
CSS
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: inherit;
}
ul {
list-style-type: none;
}
.container {
width: 62.5rem;
max-width: 80rem;
margin: 0 auto;
background-color: lightgray;
display: flex;
flex-direction: column;
justify-content: center;
}
.header {
padding: .5rem;
background-color: darkgrey;
align-self: center;
}
.list {
background-color: darkcyan;
display: grid;
grid-template-columns: 1fr repeat(2, minmax(min-content, 1fr));
}
.customer-column-header {
grid-column: 1 / 2;
}
.invoice-column-header {
grid-column: 2 / 3;
}
.payments-column-header {
grid-column: 3 / 4;
}
.customer-column-header,
.invoice-column-header,
.payments-column-header {
padding: .5rem;
text-align: center;
}
.customer-row {
border-left: 1px solid;
border-top: 1px solid;
background-color: orangered;
grid-column: 1 / -1;
display: grid;
grid-template-columns: 1fr repeat(2, minmax(min-content, 1fr));
}
.customer-column {
grid-column: 1 / 2;
}
.invoice-column {
grid-column: 2 / 3;
}
.payment-column {
grid-column: 3 / 4;
}
.customer-column {
align-self: center;
justify-self: right;
}
.customer-column > div {
padding: 1rem;
}
.invoice-column {
border-left: 1px solid;
}
.invoice-row-header {
background-color: darkcyan;
border-bottom: 1px solid;
display: grid;
grid-template-columns: repeat(3, minmax(6rem, 1fr));
justify-self: stretch;
}
.invoice-row-header > div {
text-align: right;
padding: .5rem;
justify-self: stretch;
align-self: stretch;
}
.invoice-row-header > div:nth-child(2) {
border-left: 1px solid;
border-right: 1px solid;
}
.invoice-row {
border-bottom: 1px solid;
display: grid;
grid-template-columns: repeat(3, minmax(6rem, 1fr));
justify-items: stretch;
align-items: stretch;
}
.invoice-row > div {
text-align: right;
padding: .5rem;
justify-self: stretch;
align-self: stretch;
}
.invoice-row div:nth-child(2) {
border-left: 1px solid;
border-right: 1px solid;
}
.payment-column {
border-left: 1px solid;
}
.payment-row-header {
background-color: darkcyan;
border-bottom: 1px solid;
display: grid;
grid-template-columns: repeat(2, minmax(6rem, 1fr));
justify-self: stretch;
}
.payment-row-header > div {
text-align: right;
padding: .5rem;
justify-self: stretch;
align-self: stretch;
}
.payment-row-header > div:nth-child(1) {
border-right: 1px solid;
}
.payment-row {
border-bottom: 1px solid;
display: grid;
grid-template-columns: repeat(2, minmax(6rem, 1fr));
justify-items: stretch;
align-items: stretch;
}
.payment-row > div {
text-align: right;
padding: .5rem;
justify-self: stretch;
align-self: stretch;
}
.payment-row > div:nth-child(1) {
border-right: 1px solid;
}
.pagination {
padding: .5rem;
background-color: darkgrey;
align-self: center;
}
#media only screen and (min-width: 120rem) {
.container {
max-width: 80rem;
margin: 0;
}
}
#media only screen and (max-width: 80rem) {
.container {
max-width: 62.5rem;
margin: 0 auto;
}
}
#media only screen and (max-width: 62.5rem) {
.container {
max-width: 45rem;
margin: 0 auto;
}
.list {
grid-template-columns: repeat(autofit, 100%);
}
.customer-column-header,
.invoice-column-header,
.payments-column-header {
grid-column: 1 / -1;
}
.customer-row {
grid-template-columns: repeat(autofit, 100%);
justify-content: center;
}
.customer-row .customer-column,
.customer-row .invoice-column,
.customer-row .payments-column {
grid-column: 1 / -1;
}
.customer-column {
justify-self: center;
}
}
#media only screen and (max-width: 45rem) {
.container {
width: 100%;
margin: 0 auto;
}
}
cref:https://codepen.io/randydaddis/pen/LqEjEg
No rowspans or colspans Were Harmed Making This Table
The following is a diagram of the table sans thead:
The term "column" is termed loosely. For example: column td.items refers to all
td.items as a group.
There is the main table...
...and then a tbody for each customer row. Having multiple tbodies is valid.
Next is a tr and then...
...a td. This td is the columns: .customer, .items, and .payments.
Within each td is a sub-table and sub-tbody.
The first column td.customer is limited to one sub-row since the content for each
tbody.row is just a
customer's name. The cells for this column have the properties
that control tbody.row height
(see comments in demo).
The second column td.items can have multiple sub-rows, the demo features from 1 to 3
sub-rows.
The last column td.payments can have multiple sub-rows as well, the demo features
2 sub-rows each.
Demo
Details are commented in demo
The demo is responsive (might need MQ for edge cases and mobile devices).
Valid HTML/CSS and semantically sound.
No JavaScript/jQuery.
Built purely with <table>, <thead>, <tbody>, <tr>, <th>, and <td> tags (not even a div or span).
* { border: 0px none transparent; padding: 0px; margin: 0px; }
/*
|- table-layout: fixed;
|| Gives you more control over table behavior such as setting column widths and
|| table adhering to them.
===
|- height: 100%; width: 100%;
|| Applied to table.main as well as the nested tables. It facilitates all of
|| the nested tables to stretch evenly within tbody.row.
*/
table { border-collapse: collapse; border: 2px solid #000;
table-layout: fixed; height: 100%; width: 100%; }
table table { border: 1px solid #000; }
.main { min-height: 40vh; }
th { border-bottom: 2px solid #000; outline: 1px solid #000; }
/*
|| This rule set determines content wrapping behavior within each cell.
*/
td td { border: 1px solid #000; padding: 0px 5px; word-wrap: break-word;
word-break:break-word; overflow: hidden}
.items td:first-of-type { width: 30%; }
.items td:nth-of-type(2) { width: 25%; text-align: right; }
.items td:last-of-type { width: 45%; text-align: right; }
.payments td:last-of-type { text-align: right; }
.customer,
.items,
.payments { border: 0px none transparent; padding: 0px; }
th:first-of-type { border-left: 3px solid #000; width: 20%; }
th:nth-of-type(2) { width: 40%; }
th:last-of-type { border-right: 3px solid #000; width: 40%; }
/*
|| This allows the tr.row to always be equal in height as well as being
|| responsive. This column was the best choice as the one to stabilize height
|| since the content probably changes the least and it has the most space to use
|| hidden spacers (see next comment).
*/
.customer table { min-height: 20vh; }
/*
|| This sets a within the cells in the first column. Although vh units
|| are very responsive, they will start collapsing if the viewport height is
|| reduced disproportionately vs. viewport width. Thus, this pseudo-element
|| ensures a minimum height of 60px for both tr.row.
*/
.customer td::after { content: '\a0'; display: inline-block; width:0.5px;
min-height: 60px; line-height: 60px; vertical-align: middle; }
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
</head>
<body>
<table class='main'>
<thead>
<tr>
<th>Customer</th><th>Items</th><th>Payments</th>
</tr>
</thead>
<tbody class='row'>
<tr>
<td class='customer'>
<table><tr><td>
Customer 1
</td></tr></table>
</td>
<td class='items'>
<table>
<tr><td>Item1</td><td>5</td><td>$400.00</td></tr>
<tr><td>Item2</td><td>100</td><td>$20.00</td></tr>
<tr><td>Item3</td><td>2</td><td>$500.00</td></tr>
</table>
</td>
<td class='payments'>
<table>
<tr><td>12 Sep 2018</td><td>$3,000.00</td></tr>
<tr><td>18 Sep 2018</td><td>$2,000.00</td></tr>
</table>
</td>
</tr>
</tbody>
<tbody class='row'>
<tr>
<td class='customer'>
<table><tr><td>
Customer 304
</td></tr></table>
</td>
<td class='items'>
<table>
<tr><td>Item4</td><td>5</td><td>$6.00</td></tr>
</table>
</td>
<td class='payments'>
<table>
<tr><td>20 Sep 2018</td><td>$4.00</td></tr>
<tr><td>27 Sep 2018</td><td>$26.00</td></tr>
</table>
</td>
</tr>
</tbody>
<tbody class='row'>
<tr>
<td class='customer'>
<table><tr><td>
Customer 888
</td></tr></table>
</td>
<td class='items'>
<table>
<tr><td>Item5</td><td>50</td><td>$100.00</td></tr>
<tr><td>Item6</td><td>10</td><td>$500.00</td></tr>
</table>
</td>
<td class='payments'>
<table>
<tr><td>10 Nov 2018</td><td>$3,000.00</td></tr>
<tr><td>17 Nov 2018</td><td>$7,000.00</td></tr>
</table>
</td>
</tr>
</tbody>
</table>
</body>
</html>
References
table-layout
vh and vw
word-wrap: break-word; word-break:break-word;
:first-/:nth-/:last-of-type
::before/after
Here's a JavaScript solution that sets both the row heights and column widths automatically (does not require specifying column widths), and supports resizing.
The complete solution/demo is here: http://jsfiddle.net/ez0jqc1L/
The one caveat is this requires that you wrap the content of all <td> cells with <div class="content"></div> (see the jsfiddle for an example).
First, we fix the subtable heights:
let tbody = /* the tbody of the <table> containing subtables we are fixing */;
for(let r = 0; r < tbody.children.length; r++) {
let row = tbody.children[r];
let subtables = row.querySelectorAll('.subtable');
let maxHeight = 0;
for(let i = 0; i < subtables.length; i++) {
maxHeight = Math.max(maxHeight, subtables[i].clientHeight);
}
for(let i = 0; i < subtables.length; i++) {
subtables[i].style.height = maxHeight + 'px';
}
}
Then, we iterate over all subtable columns to compute the max width for each set of vertically adjacent cells (we store this into the maxColWidths array, each index of the array corresponds to the set of vertically adjacent cells):
let forEachSubtableColumn = function(f) {
for(let r = 0; r < tbody.children.length; r++) {
let row = tbody.children[r];
let subtables = row.querySelectorAll('.subtable');
let c = 0;
for(let i = 0; i < subtables.length; i++) {
let subtable = subtables[i];
if(subtable.children.length === 0 || subtable.children[0].children.length === 0) {
continue;
}
let stbody = subtable.children[0];
for(let j = 0; j < stbody.children.length; j++) {
let srow = stbody.children[j];
for(let k = 0; k < srow.children.length; k++) {
let td = srow.children[k];
f(c + k, td);
}
}
c += stbody.children[0].children.length;
}
}
};
let maxColWidths = [];
forEachSubtableColumn(function(c, td) {
if(c >= maxColWidths.length) {
maxColWidths.push(td.children[0].clientWidth);
} else {
maxColWidths[c] = Math.max(td.children[0].clientWidth, maxColWidths[c]);
}
});
Finally, we set the column widths. This is where the <div class="content"> wrapping is required, because setting the width of a <td> does not guarantee the browser will make it that exact width, but I can have this guarantee with an element having display: inline-block.
forEachSubtableColumn(function(c, td) {
td.children[0].style.width = maxColWidths[c] + 'px';
});
For resizing support we clear all the forced widths and heights so we can recompute them afterwards:
onresize = function() {
let tables = document.querySelectorAll('.subtable');
for(let i = 0; i < tables.length; i++) {
let table = tables[i];
table.style.removeProperty('height');
}
let tds = document.querySelectorAll('.subtable td');
for(let i = 0; i < tds.length; i++) {
let td = tds[i];
td.children[0].style.removeProperty('width');
}
updateTables();
};
EDIT: Corrected the onresize code.
The problem as given can actually be solved rather straightforward with nesting CSS grid layouts.
(If there there was colspan or rowspan that would require using their counterparts grid-column and grid-row.)
I simplified the HTML so the solution can be understood more clearly - though that loses the semantics of the table.
If it's desired to maintain the table markup then the intervening tags (e.g. the <tr>) need to be styled as display:contents to ensure they don't break up the layout (like here).
/* defining the grid */
.grid{display:grid;grid-gap:0 0;}
.grid-2col{grid-template-columns:auto auto;}
.grid-3col{grid-template-columns:auto auto auto;}
/* making it look like a table. */
.th{font-weight:bold;}
.grid>*{
border:1px solid black;
padding:5px;}
/* avoiding double borders. */
/* no double top border - first row can be recognized by class .th */
.grid>*{border-top:none;}
.th{border-top:1px solid black;}
/* no double side border - first column can be recognized modulo number of columns of grid. */
.grid>*{border-left:none;}
.grid-2col>*:nth-child(2n+1){border-left:1px solid black;}
.grid-3col>*:nth-child(3n+1){border-left:1px solid black;}
/* no padding in nested tables. */
.grid>.grid{border:none;padding:0px;}
.grid>.grid>*{border-left:none;border-top:none;}
<div class="grid grid-3col">
<span class="th">Customer</span>
<span class="th">Items</span>
<span class="th">Payments</span>
<span>Customer Name</span>
<div class="grid grid-3col">
<span>Item1</span>
<span>5</span>
<span>$400.00</span>
<span>Item2</span>
<span>10</span>
<span>$200.00</span>
<span>Item3</span>
<span>2</span>
<span>$500.00</span>
</div>
<div class="grid grid-2col">
<span>12 Sep 2018</span>
<span>$3,000.00</span>
<span>18 Sep 2018</span>
<span>$2,000.00</span>
</div>
</div>
The meaning of the <table> tag has changed between current HTML and older HTML. While <table> used to server more of a formatting function, in HTML5 it should only be used for a literal table. As others have mentioned, your setup doesn't really look like a table in the literal sense. So while using a bunch of nested <table> elements could accomplish what you want, it's probably not the most effective way.
You could accomplish this by just nesting a bunch of <div> elements along with some basic CSS. Here's an example:
<div style="width: 1000px; height: 600px; border: 1px solid #000;">
<div style="width: 100px; height: 600px; display: inline-block; border: 1px solid #000; margin: 0; padding: 0;">X</div>
<div style="width: 100px; height: 300px; display: inline-block; border: 1px solid #000; margin: 0; padding: 0;">Y</div>
<div style="width: 100px; height: 300px; display: inline-block; border: 1px solid #000; position: relative; top: 300px; margin: 0; padding: 0; left: -105px;">Z</div>
</div>
This will produce the X, Y, and Z parts of the display you describe above. The same technique can be expanded to build the rest of your display.
A few things to note:
This example uses PXs to determine width, which is really bad practice form a CSS perspective. It would be too big on mobile and too small on a large desktop. You could, however, adapt this technique to use a more adaptive format. This will add complexity to the solution though, hence why I chose to use PXs for the example.
This example uses inline CSS since it's the easiest way to show the solution. However, this is really bad practice, DON'T ACTUALLY DO THIS!
Hope this helps.
Online spreadsheet programs like Google Sheets make it look so easy, but when I first dove in, it was much more complicated. I gave each row a special attribute like row="r_1" and each subrow specific attributes like row="r_1" subrow="sr_1_a". onkeyup events or an onload triggered math to find all parent rows using querySelectorAll, then made sure their height was equal to all the subrow heights added up.
In my opinion I assume that it'd be hard to achieve what you want.
Reasons: td are nested in tr, so any change in height will affect height of of the associated row.
Suggestion: you can have five separate tabs or divs and have them displayed inline-block, then put your data in them.
If you use this suggestion, please first set a div that wraps the 5 columns and give it a font-size of 0px, then remember to change the font-size to something useful for the children.
I am wanting to display a div .before() another if it does not contain a specific class within it. Though it seems simple enough, somehow I am not able to get it working...
Here's a snippet of the progress I've made so far:
$('.container > #content').not('.entry', function() {
$(this).before('<div class="noentry">No entries to display.</div>');
});
body {
font-size: 16px;
margin: 0;
padding: 0;
border: 0;
}
h1 {
font-size: 22px;
margin-top: 0;
}
.container {
margin: 0 auto;
max-width: 300px;
border: 1px solid lightgrey;
padding: 10px;
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<h1>Section With an Entry:</h1>
<div id="content">
<div class="entry">This is an entry.</div>
</div>
</div>
<div class="container">
<h1>Section Without an Entry:</h1>
<div id="content"></div>
</div>
The .not() method does not work as you are expecting. It only checks the immediate object for the .entry class. You need to search descendants. See the updated example below, you can use a .find().
Also, as noted in the comments above, you shouldn't duplicate ids, so I changed your content to a class.
$(function() {
$('.container > .content').each(function() {
if (!$(this).find(".entry").length) {
$(this).before('<div class="noentry">No entries to display.</div>');
}
});
});
body {
font-size: 16px;
margin: 0;
padding: 0;
border: 0;
}
h1 {
font-size: 22px;
margin-top: 0;
}
.container {
margin: 0 auto;
max-width: 300px;
border: 1px solid lightgrey;
padding: 10px;
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<h1>Section With an Entry:</h1>
<div class="content">
<div class="entry">This is an entry.</div>
</div>
</div>
<div class="container">
<h1>Section Without an Entry:</h1>
<div class="content"></div>
</div>
So let's say I have something like this:
body {
background: #ffffff;
}
.table {
display: table;
margin: 0px auto;
max-width: 400px
}
.row {
display: table-row;
width: 100%
}
.td1,
.td2,
.td3 {
display: table-cell;
border: 2px #aaaaaa solid;
padding: 15px;
background: #eeeeee;
font-size: 18px;
color: #000000;
width: 100%;
}
.td2,
.td3 {
border-top: none;
color: red;
}
<body>
<div class="table">
<div class="row">
<div class="td1">Here is some random text</div>
</div>
<div class="row">
<div class="td2">This is the text you see at first</div>
</div>
<div class="row">
<div class="td3">This is the text below the other div</div>
</div>
</div>
Now, what I would like to do is have the td2 text to show when you first see the page, but not the td3. Then when clicking the td2 div it makes a fadeout or slides upwards, and then reveal the td3 div and that text. In this particular case the div doesn't have to come back when re-clicking. It's just like a "one way ticket". Click, and it's gone forever.
What might be the easiest way to do this ?
You could use JQuery UI to get the fade effect, and register to click event on .td2 in order to update the DOM as per your requirement. Here's one way of doing it:
$(".td2").on("click", function(){
$(".td2").fadeOut();
$(".td3").fadeIn();
});
body {
background: #ffffff;
}
.table {
display: table;
margin: 0px auto;
max-width: 400px
}
.row {
display: table-row;
width:100%
}
.td1, .td2, .td3 {
display: table-cell;
border: 2px #aaaaaa solid;
padding: 15px;
background: #eeeeee;
font-size: 18px;
color: #000000;
width:100%;
}
.td2, .td3 {
border-top: none;
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery-ui.min.js"></script>
<div class="table">
<div class="row">
<div class="td1">Here is some random text</div>
</div>
<div class="row">
<div class="td2">This is the text you see at first</div>
</div>
<div class="row">
<div class="td3" style="display:none">This is the text below the other div</div>
</div>
</div>
$('.td2').on('click', function() {
$(this).fadeOut(200).promise()
.done(function() {
$('.td3').fadeIn(200);
});
});
.table {
display: table;
margin: 0px auto;
max-width: 400px
}
.row {
display: table-row;
width: 100%
}
.hide {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="table">
<div class="row">
<div class="td1">
Here is some random text
</div>
</div>
<div class="row">
<div class="td2">
This is the text you see at first
</div>
</div>
<div class="row">
<div class="td3 hide">
This is the text below the other div
</div>
</div>
</div>
You will need to learn some javascript and some jQuery for this ;)
Add this to your css:
.td3{
display: none;
}
And write this javascript:
$('.td2').on( "click", function(){
$('.td2').fadeOut();
$('.td3').fadeIn();
});
I'm needing to create CSS classes that can display content similar to this design image here: design concept
Obviously, the code statements themselves don't matter. But how can I create CSS that could wrap the containing content as seen in the image and have that work to n nested containers? I've been playing around with div tags and display: inline-block styling but nothing is working out.
Here is what I currently have, using flex-box. This is almost what I need except that the "rows" aren't setting their width to fit the text content as it just sets the width of everything to the largest width child... seems that this approach might not be possible.
.container {
display: inline-flex;
flex-direction: column;
padding-left: 15px;
}
.containerRow {
display: flex;
flex-direction: column;
justify-content: center;
height: 35px;
margin: 5px;
}
.dropContainer {
height: 70px;
border: 1px solid #ccc!important;
background-color: white;
color: black;
}
.purple {
background-color: #872A61;
color: white;
}
.green {
background-color: #478B26;
color: white;
}
<div class="container purple">
<div class="containerRow">
if (something == true) then
</div>
<div class="container green">
<div class="containerRow">
<div><b>where</b> something(x: Number, y:Number) <b>is</b></div>
</div>
<div class="dropContainer">
Some more stuff again
</div>
<div class="dropContainer">
Some more stuff again
</div>
<div class="containerRow">
<b>end</b>
</div>
</div>
<div class="containerRow">
<b>end</b>
</div>
</div>
Use margins or padding styles with percentages to achieve the nth term.