aeppic - site layout overflow
by mgoetzke
HTML
<div class="main" title="main">
<div class="navbar" title="navbar">
nav
</div>
<div class="center">
<div class="toolbar">
TOOLBAR
</div>
<div class="page">
<div class="ae-form">
<div class="form-main-layout" title="form-main-layout">
<div class="sidebar">
FORM SIDEBAR
</div>
<div class="form-layout" title="form-root-section">
<div class="form-section-root-layout" style="">
<div class="top-of-tab-content">
A high container. maybe fields on top of root section tabs.
<div class="form-section-tabs">
<ul style="width:2000px">
<li>way too wide for overflow</li>
</ul>
</div>
</div>
<div class="form-tab-content">
<div>A LOT OF FORM CONTENT TO SCROLL</div>
<div class="spacer"></div>
<div class="header">Header 1</div>
<div class="spacer"></div>
<div class="header">Header 2</div>
<div class="spacer"></div>
<div class="header">Header 3</div>
<div class="spacer"></div>
<div class="footer">END</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
CSS
html,
body {
margin: 0;
padding: 0;
}
div {
box-sizing: border-box;
}
:root {
--top-toolbar-height: 48px;
--vertical-border-heights: 8px;
}
.main {
padding: 4px;
background: green;
display: flex;
height: 100vh;
}
.navbar {
width: 50px;
background: linear-gradient(white 0, white 50%, blue);
border: 2px solid blue;
}
.center {
flex: 1;
}
.toolbar {
height: var(--top-toolbar-height);
}
.form-main-layout {
display: grid;
grid-template-columns: minmax(50px, max-content) 1fr;
grid-gap: 10px;
background: yellow;
position: relative;
height: 100%;
}
.sidebar {
width: 100px;
height: 50px;
background: blue;
}
.form-layout {
background: white;
border: 2px solid red;
overflow: auto;
height: calc(100vh - var(--top-toolbar-height) - var(--vertical-border-heights));
display: grid;
grid-auto-rows: minmax(1px, 1fr);
}
.form-section-root-layout {
background: rgba(0, 1.0, 0, 0.8);
margin: 5px;
border: 5px orange solid;
xheight: 1000px;
display: flex;
flex-direction: column;
}
.form-section-root-layout>* {
min-height: 0px;
}
.top-of-tab-content {
display: grid;
grid-auto-rows: min-content;
x-flex-direction: column;
background: white;
}
.form-section-tabs {
background: yellow;
overflow-x: auto;
}
.form-section-tabs>* {
min-width: 0;
min-height: 0px;
}
.form-tab-content {
flex: 1;
position: relative;
overflow-y: scroll;
background: green;
xheight: 200px;
/* <-- THE LAST CRUX. WANT TO AUTOCALC THIS via remaining space*/
}
.form-tab-content>.header {
position: sticky;
top: 0px;
background: orange;
}
.form-tab-content>.header.stuck {
xbackground: yellow;
box-shadow: -1px 10px 23px 0px rgba(0, 0, 0, 0.5);
}
.form-tab-content>.spacer {
height: 200px;
}
.form-tab-content>.footer {}
JavaScript
function observeStickiness(containerSelector, targetClass) {
// Get the container element
var container = document.querySelector(containerSelector);
// Get all target elements within the container
var targets = Array.from(container.getElementsByClassName(targetClass));
console.log('observing', container, targets)
// Variable to store the ID of the requestAnimationFrame
var requestId = null;
var pending = false;
// Scroll event listener
function scrollListener() {
if (requestId === null) {
pending = false
requestId = requestAnimationFrame(checkStickiness);
} else {
pending = true;
}
}
// Function to check if each target is sticky
function checkStickiness() {
var containerRect = container.getBoundingClientRect();
targets.forEach(function(target) {
var targetRect = target.getBoundingClientRect();
var offsetTop = targetRect.top - containerRect.top;
if (offsetTop <= 0) {
// The target is sticky, add the 'stuck' class
target.classList.add('stuck');
} else {
// The target is not sticky, remove the 'stuck' class
target.classList.remove('stuck');
}
});
// Reset the requestId so the scroll listener can request another animation frame
requestId = null;
if (pending) {
scrollListener()
}
}
// Add the scroll listener to the container
container.addEventListener('scroll', scrollListener);
}
observeStickiness('.form-tab-content', 'header');