Some context
Given a 2×5 css grid
covering whole viewport defined as :
#grid-wrapper {
display: grid;
grid-template-columns: 50% 50%;
grid-template-rows: 50px 50px 50px calc(100vh - 200px) 50px;
grid-template-areas:
"header header"
"common-toolbar common-toolbar"
"left-toolbar right-toolbar"
"left-panel right-panel"
"footer footer";
width: 100vw;
height: 100vh;
}
left-panel
and right-panel
grid cells are both overflow-y: scroll;
scrollable div
s.
The question
I would like common-toolbar
and (left/right)-toolbar
s row height not to be defined as fixed (50px
) height but to size automatically to their content height (the toolbars height, which is not static) while (left/right)-panel
still taking the rest of available viewport height.
Something like :
grid-template-rows: 50px auto auto calc(100vh - sum_of_height_of_other_rows) 50px;
Is that achievable in a grid
?
edit : snippet
const squares = [
['■', 'Black square'],
['□', 'White square'],
['▢', 'White square with rounded corners'],
['▣', 'White square containing small black square'],
['▤', 'Square with horizontal fill'],
['▥', 'Square with vertical fill'],
['▦', 'Square with orthogonal crosshatch fill'],
['▧', 'Square with upper left to lower right fill'],
['▨', 'Square with upper right to lower left fill'],
['▩', 'Square with diagonal crosshatch fill '],
]
const fruits = [
['☕', 'hot beverage'],
['⛾', 'restaurant'],
['🍅', 'tomato'],
['🍊', 'tangerine'],
['🍏', 'green apple'],
['🥑', 'avocado'],
['🍔', 'hamburger'],
['🍕', 'slice of pizza'],
['🍙', 'rice ball'],
['🍞', 'bread'],
['🍣', 'sushi'],
['🍨', 'ice cream'],
['🍭', 'lollipop'],
['🍲', 'pot of food'],
['🍷', 'wine glass'],
['🍼', 'baby bottle'],
['🍓', 'strawberry'],
]
const chess = [
['♔', 'white chess king'],
['♕', 'white chess queen'],
['♖', 'white chess rook'],
['♗', 'white chess bishop'],
['♘', 'white chess knight'],
['♙', 'white chess pawn'],
['♚', 'black chess king'],
['♛', 'black chess queen'],
['♜', 'black chess rook'],
['♝', 'black chess bishop'],
['♞', 'black chess knight'],
['♟', 'black chess pawn']
]
const fillToolbar = (toolbar, fillWith) => {
fillWith.forEach(([symbol, name]) => {
const $button = document.createElement('button')
$button.setAttribute("title", name)
$button.textContent = symbol;
toolbar.append($button)
})
}
fillToolbar(document.getElementById("common-toolbar"), squares)
fillToolbar(document.getElementById("left-toolbar"), fruits)
fillToolbar(document.getElementById("right-toolbar"), chess)
const fillText = (panel, count) => {
panel.innerHTML = '';
if (count > 0) {
panel.innerHTML =
"<p>start.<p> "
+ "<p>THE TEXT IS HERE LONG.<p> ".repeat(count)
+ "<p>end.<p> "
}
}
const count = 1000;
fillText(document.getElementById("left-panel"), count)
fillText(document.getElementById("right-panel-content"), count)
body {
margin: 0;
}
#grid-wrapper {
display: grid;
grid-template-columns: calc(50%-5px) 50%;
grid-template-rows: 50px 50px 50px calc(100vh - 200px) 50px;
grid-template-areas:
"header header"
"common-toolbar common-toolbar"
"left-toolbar right-toolbar"
"left-panel right-panel"
"footer footer";
width: 100vw;
height: 100vh;
column-gap: 10px;
}
#header {
background-color: aqua;
grid-column: span 2;
grid-area: header;
}
#common-toolbar {
background-color: blue;
grid-column: span 2;
grid-area: common-toolbar;
}
#left-toolbar {
background-color: blueviolet;
grid-area: left-toolbar;
}
#left-panel {
background-color: brown;
grid-area: left-panel;
overflow-y: scroll;
}
#right-toolbar {
background-color: chartreuse;
grid-area: right-toolbar;
}
#right-panel {
background-color: chocolate;
grid-area: right-panel;
}
#right-panel-content {
overflow-y: scroll;
height: 100%;
}
#footer {
background-color: crimson;
grid-column: span 2;
grid-area: footer;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Test box</title>
</head>
<body>
<div id="grid-wrapper">
<div id="header">The head</div>
<div id="common-toolbar">Common Toolbar 1 2 3</div>
<div id="left-toolbar"></div>
<div id="left-panel"><div id="left-panel-content"></div></div>
<div id="right-toolbar">Right Toolbar l1 l2 l3</div>
<div id="right-panel"><div id="right-panel-content"></div></div>
<div id="footer">This is the footer</div>
</div>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
3
Answers
One approach is as below, there are many possible variations on this theme (and, course, many others); explanatory comments are in the code:
JS Fiddle demo.
If, however, you would prefer – or are required – to keep the
.left-toolbar
and.right-toolbar
elements outside of the.panel
elements, then the following also works:JS Fiddle demo.
References:
align-self
.backdrop-filter
.background-color
.block-size
.box-sizing
.display
.flex-grow
.font-family
.font-size
.font-weight
.gap
.grid-column
.grid-template-columns
.grid-template-rows
.inline-size
.justify-content
.left
.margin
.margin-block
.margin-inline
.overflow-y
.padding
.padding-block
.padding-inline
.position
.top
.Array.prototype.forEach()
.Array.prototype.from()
.Array.prototype.join()
.Array.prototype.map()
.document.createDocumentFragment()
.document.createElement()
.document.querySelector()
.document.querySelectorAll()
.Element.append()
.Object.assign()
.String.prototype.replace()
.String.prototype.split()
.I think you’re looking for something like this:
Let grid’s auto-placement figure out the hard stuff for you. No need for calculating remaining height…that’s what
1fr
orone fractional unit
will do for you.Hope this helps.
Set
#grid-wrapper { grid-auto-rows: minmax(50px, auto) minmax(50px, auto) minmax(50px, auto) minmax(50px, 1fr) minmax(50px, auto); }
.Also, if you specify
grid-area
, you can omitgrid-column
…