JSFiddle - React, Tailwind, and code Playground
HTML
<div id="save">
<button id="saveButton">Save position</button>
<span id="saved">Saved!</span>
</div>
<div id="box"></div>
<div id="content">
TOP<br><br>jklf; dsjak; lfdjsakeruwiq ptewquiporewquipofdsuaipv dsnmvczxnm.,vcxznm.,
fdsn.,mfdsanm,dsnm.,vcxzjfap urioepw uipofd sjakl; fjkdsl; afjkdl; sajfkdls;
av znx,.mcvnm,cv.znx ureopwuqiporewup kfldsja fas
jklf; dsjak; lfdjsakeruwiq ptewquiporewquipofdsuaipv dsnmvczxnm.,vcxznm.,
fdsn.,mfdsanm,dsnm.,vcxzjfap urioepw uipofd sjakl; fjkdsl; afjkdl; sajfkdls;
av znx,.mcvnm,cv.znx ureopwuqiporewup kfldsja fas
jklf; dsjak; lfdjsakeruwiq ptewquiporewquipofdsuaipv dsnmvczxnm.,vcxznm.,
fdsn.,mfdsanm,dsnm.,vcxzjfap urioepw uipofd sjakl; fjkdsl; afjkdl; sajfkdls;
av znx,.mcvnm,cv.znx ureopwuqiporewup kfldsja fas
jklf; dsjak; lfdjsakeruwiq ptewquiporewquipofdsuaipv dsnmvczxnm.,vcxznm.,
fdsn.,mfdsanm,dsnm.,vcxzjfap urioepw uipofd sjakl; fjkdsl; afjkdl; sajfkdls;
av znx,.mcvnm,cv.znx ureopwuqiporewup kfldsja fas
jklf; dsjak; lfdjsakeruwiq ptewquiporewquipofdsuaipv dsnmvczxnm.,vcxznm.,
fdsn.,mfdsanm,dsnm.,vcxzjfap urioepw uipofd sjakl; fjkdsl; afjkdl; sajfkdls;
av znx,.mcvnm,cv.znx ureopwuqiporewup kfldsja fas
jklf; dsjak; lfdjsakeruwiq ptewquiporewquipofdsuaipv dsnmvczxnm.,vcxznm.,
fdsn.,mfdsanm,dsnm.,vcxzjfap urioepw uipofd sjakl; fjkdsl; afjkdl; sajfkdls;
av znx,.mcvnm,cv.znx ureopwuqiporewup kfldsja fas
jklf; dsjak; lfdjsakeruwiq ptewquiporewquipofdsuaipv dsnmvczxnm.,vcxznm.,
fdsn.,mfdsanm,dsnm.,vcxzjfap urioepw uipofd sjakl; fjkdsl; afjkdl; sajfkdls;
av znx,.mcvnm,cv.znx ureopwuqiporewup kfldsja fas
jklf; dsjak; lfdjsakeruwiq ptewquiporewquipofdsuaipv dsnmvczxnm.,vcxznm.,
fdsn.,mfdsanm,dsnm.,vcxzjfap urioepw uipofd sjakl; fjkdsl; afjkdl; sajfkdls;
av znx,.mcvnm,cv.znx ureopwuqiporewup kfldsja fas
jklf; dsjak; lfdjsakeruwiq ptewquiporewquipofdsuaipv dsnmvczxnm.,vcxznm.,
...
CSS
#save {
position:fixed;
top:30px;
left:10px;
width:20%;
}
#saved {
visibility:hidden;
color:green;
}
#content {
width:60%;
margin:auto;
}
#box {
position: absolute;
background-color: black;
opacity: 0.5;
height: 2.5em;
left: 0%;
right:0%;
}
JavaScript
function checkStorageSupport() {
var test = "test";
try {
localStorage.setItem(test, test);
localStorage.removeItem(test);
return true;
} catch(e) {
return false;
}
}
function getTotalHeight() {
return document.body.clientHeight;
}
function getSavedPercent() {
var percent = storageSupported ? loadFromStorage() : loadFromCookie();
return (percent == null || percent == "") ? 0 : percent;
}
/******* Save *******/
function saveInStorage() {
localStorage.setItem("scrollPercent", (document.documentElement.scrollTop / getTotalHeight()));
}
function saveCookie() {
var expDate = new Date();
expDate.setDate(expDate.getDate() + 7); // start over if it's been more than ___ days
document.cookie = "scrollPercent=" + (document.documentElement.scrollTop / getTotalHeight())
+ "; " + expDate;
}
/******* Load *******/
function loadFromStorage() {
return localStorage.getItem("scrollPercent");
}
function loadFromCookie() {
return document.cookie.replace(/(?:(?:^|.*;\s*)scrollPercent\s*\=\s*([^;]*).*$)|^.*$/, "$1");
}
/******* Remove *******/
function removeFromStorage() {
localStorage.removeItem("scrollPercent");
}
function removeCookie() {
document.cookie = "scrollPercent=''";
}
/******* Handler *******/
var saveButton = document.getElementById("saveButton"),
saved = document.getElementById("saved");
saveButton.onclick = function() {
storageSupported ? saveInStorage() : saveCookie();
saved.style.visibility = "visible";
setTimeout(function() {
saved.style.visibility = "hidden";
}, 1500);
};
/******* Logic *******/
var storageSupported = checkStorageSupport(),
percent = getSavedPercent();
if (percent > 0) {
if (confirm("Would you like to continue reading where you left off?")) {
document.documentElement.scrollTop = percent * getTotalHeight(); // with jQuery, $("html, body").animate({...