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');