'How to keep user's scrolling place when resizing div

I wanted to do a cool menu effect for a website I'm working on. I'm having a div act as the the section for the main content. When the user opens the menu, the main content div will resize and move out of the way, revealing the menu. However, when I do this with the code I have written, it always loses my scrolling place on the page. Is there any way to keep my place on the page when it shrinks and also when it expands back again? Below is what I have. Thank you in advance!

function shrinkPage() {
   
   var element = document.getElementById("mock-body");
   element.classList.toggle("mock-body-on-burger");
   
   var z = document.getElementById("mock-body-container");
   z.classList.toggle("mock-body-container-on-burger");
   
   var x = document.getElementById("body");
   x.classList.toggle("body-on-burger");
};
body {
	margin: 0;
	background:#000;
}

.body-on-burger {
	max-width: 100%;
	overflow-x:hidden;
}

.mock-body-container{
	height:100vh;
}

.mock-body-container-on-burger {
	height:100vh;
	transform: scale(0.4) translate(130%);
	overflow: hidden;
}

.mock-body-size-change{
	overflow: scroll;
}

.mock-body {
	position:relative;
	background: #fff;
	margin-left: 50px;
}
  
.container {
	position: fixed;
	height:50px;
	width:50px;
	cursor: pointer;
}

.container #icon {
	width: 16px;
	height: 8px;
	position: relative;
	margin: 0px auto 0;
	top: 40%;
}

.container #icon .bars {
	height: 1px;
	background: #fff;
}

.myDiv {
	height:500px;
}

.one {
	background:red;
}

.two {
	background:green;
}

.three {
	background:blue;
}
<body id="body">



	<div class="menu-activator" onclick="shrinkPage()">
		<div class="container usd">
			<div id="icon">
				<div class="bars first"></div>
			</div>
		</div>
	</div>
	
	
	<div id="mock-body-container" class="mock-body-container">
		<div id="mock-body" class="mock-body">
			<div class="myDiv one"></div>
			<div class="myDiv two"></div>
			<div class="myDiv three"></div>
		</div>
 	</div>
   </body>


Solution 1:[1]

Please take a look at the snippet below. Notice how the overflow property is used.

You have to scroll mock-body-container to keep its scrolling position. You're scrolling body instead, so when you scale mock-body-container there is nothing to scroll in body and you loose the scrolling position.

function shrinkPage() {
   
   var element = document.getElementById("mock-body");
   element.classList.toggle("mock-body-on-burger");
   
   var z = document.getElementById("mock-body-container");
   z.classList.toggle("mock-body-container-on-burger");
   
   var x = document.getElementById("body");
   x.classList.toggle("body-on-burger");
};
body {
	margin: 0;
	background:#000;
}

.body-on-burger {
	max-width: 100%;
	overflow-x:hidden;
}

.mock-body-container{
	height:100vh;
  overflow:auto;
}

.mock-body-container-on-burger {
	height:100vh;
	transform: scale(0.4) translate(130%);
}

.mock-body-size-change{
	overflow: scroll;
}

.mock-body {
	position:relative;
	background: #fff;
	margin-left: 50px;
}
  
.container {
	position: fixed;
	height:50px;
	width:50px;
	cursor: pointer;
}

.container #icon {
	width: 16px;
	height: 8px;
	position: relative;
	margin: 0px auto 0;
	top: 40%;
}

.container #icon .bars {
	height: 1px;
	background: #fff;
}

.myDiv {
	height:500px;
}

.one {
	background:red;
}

.two {
	background:green;
}

.three {
	background:blue;
}
<body id="body">



	<div class="menu-activator" onclick="shrinkPage()">
		<div class="container usd">
			<div id="icon">
				<div class="bars first"></div>
			</div>
		</div>
	</div>
	
	
	<div id="mock-body-container" class="mock-body-container">
		<div id="mock-body" class="mock-body">
			<div class="myDiv one"></div>
			<div class="myDiv two"></div>
			<div class="myDiv three"></div>
		</div>
 	</div>
   </body>

Solution 2:[2]

Once you know the element that was in focus it should be relatively easy. If you need to find which element was last in focus, you can do that with a scroll function. If you need this as well let me know and I will update my answer.

If you know that #mock-body is the last element in focus, just scroll back to it after the resize.

In this example I've used jQuery as it makes this interaction easier, but this can be done (albeit more verbosely) with vanilla JS as well.

$('html, body').animate({
  scrollTop: $('#mock-body').offset().top
}, 0); // If you want the animation to be smoother you can increase 0 to a higher number

Solution 3:[3]

A simple way to do it is to remember the position of the document scroll and reapply it when you getting back to "normal" view:

let savedScroll; 

function shrinkPage() {
  let _s = (el) => document.querySelector(el),
      s_ = (d) => !d.classList.contains('body-on-burger'),
    x = _s('#body'),
    element = _s('#mock-body'),
    z = _s('#mock-body-container');

  if (s_(x)) {
    savedScroll = document.documentElement.scrollTop;
  }

  element.classList.toggle("mock-body-on-burger");
  z.classList.toggle("mock-body-container-on-burger");
  x.classList.toggle("body-on-burger");

  if (s_(x)) {
    document.documentElement.scrollTop = savedScroll;
  }
};

Check it out:

let savedScroll; 

function shrinkPage() {
  let _s = (el) => document.querySelector(el),
      s_ = (d) => !d.classList.contains('body-on-burger'),
    x = _s('#body'),
    element = _s('#mock-body'),
    z = _s('#mock-body-container');

  if (s_(x)) {
    savedScroll = document.documentElement.scrollTop;
  }

  element.classList.toggle("mock-body-on-burger");
  z.classList.toggle("mock-body-container-on-burger");
  x.classList.toggle("body-on-burger");

  if (s_(x)) {
    document.documentElement.scrollTop = savedScroll;
  }
};
body {
  margin: 0;
  background: #000;
}

.body-on-burger {
  max-width: 100%;
  overflow-x: hidden;
}

.mock-body-container {
  height: 100vh;
}

.mock-body-container-on-burger {
  height: 100vh;
  transform: scale(0.4) translate(130%);
  overflow: hidden;
}

.mock-body-size-change {
  overflow: scroll;
}

.mock-body {
  position: relative;
  background: #fff;
  margin-left: 50px;
}

.container {
  position: fixed;
  height: 50px;
  width: 50px;
  cursor: pointer;
}

.container #icon {
  width: 16px;
  height: 8px;
  position: relative;
  margin: 0px auto 0;
  top: 40%;
}

.container #icon .bars {
  height: 1px;
  background: #fff;
}

.myDiv {
  height: 500px;
}

.one {
  background: red;
}

.two {
  background: green;
}

.three {
  background: blue;
}
<body id="body">
  <div class="menu-activator" onclick="shrinkPage()">
    <div class="container usd">
      <div id="icon">
        <div class="bars first"></div>
      </div>
    </div>
  </div>


  <div id="mock-body-container" class="mock-body-container">
    <div id="mock-body" class="mock-body">
      <div class="myDiv one"></div>
      <div class="myDiv two"></div>
      <div class="myDiv three"></div>
    </div>
  </div>
</body>

Legend: _s(el) returns first match of el and s_(d) checks if d has class body-on-burger.

Solution 4:[4]

The simple way to do this is to determine the change in height during the resize, and scroll that much.

const heightChange = newHeight - initialHeight;
scrollableDiv.scrollTop = scrollableDiv.scrollTop - heightChange;

In my case I am using a resize method I wrote, so I do this work inside of a window.addEventListener("mousemove", handleResize); when I know the div in actively being resized by the user.

This will still work fine with native html resizable elements, you just need to figure out how/when to listen for resize/drag events accordingly.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Kosh
Solution 2 SISYN
Solution 3
Solution 4 augustmuir