I want to have a fast page-load but also not have the user see a delay before content is rendered while scrolling down the page.
I have a large html page with many <dl>
elements.
To speed up page load, I have set content-visibility: auto
in css. See https://web.dev/content-visibility/
dl {
content-visibility: auto;
contain-intrinsic-size: 1000px;
}
Due to the complexity of the contents of the <dl>
s there is a noticeable delay when a user scrolls while the <dl>
s are rendered as they come into the viewport.
Thus, soon after page-load I want to render all the offscreen <dl>
straight away (before a user scrolls to them) but in such a way that it does not block the main thread and scrolling remains responsive.
So, I want to set content-visibility: visible
on the <dl>
s starting from the top one, and not blocking the main thread (for more than say 50ms). So, maybe allowing user interaction after rendering each <dl>
.
So, I need a version of the below, that doesn't block the main thread:
document.querySelectorAll('dl').forEach(function(dlElement, currentIndex, listObj) { dlElement.style['content-visibility'] = 'visible' });
My use case: My page is of math notes, which I want all on one page to reduce friction. I use katex which (for now, before we can use mathml on chrome) produces very large and complex html, which even server-side rendered still takes a lot of time for layout and rendering on the browser.
Rather than leave this unanswered, let me paste my (unperfected) code I have been testing for the last few weeks.
// --------- Shim requestIdleCallback if not supported in browser ----------------------------------
window.requestIdleCallback =
window.requestIdleCallback ||
function (cb) {
var start = Date.now();
return setTimeout(function () {
cb({
didTimeout: false,
timeRemaining: function () {
return Math.max(0, 50 - (Date.now() - start));
}
});
}, 1);
}
window.cancelIdleCallback =
window.cancelIdleCallback ||
function (id) {
clearTimeout(id);
}
// Global
let isRequestIdleCallbackScheduled = false;
let nodeToRemove = null;
let isVisualUpdateScheduled = false;
let totalDlElementsLeftToShow = 0;
function startIfNeeded() {
totalDlElementsLeftToShow = document.querySelectorAll('dl:not([style*="content-visibility: visible;"]), .ra:not([style*="content-visibility: visible;"]').length;
if (totalDlElementsLeftToShow > 0) {
console.log('Not a mobile - Let\'s make things visible when we are next idle');
scheduleVisibilityChanges();
}
else {
console.log('Apparently, all visible');
}
}
function scheduleVisibilityChanges() {
// Only schedule the rIC if one has not already been set.
if (isRequestIdleCallbackScheduled) {
//console.log('returning because idle callback scheduled');
startIfNeeded();
}
isRequestIdleCallbackScheduled = true;
//console.log('scheduling visibility changes when next idle or in 30 seconds at the latest');
requestIdleCallback(processHiddenElements, { timeout: 30000 });
}
function processHiddenElements(deadline) {
// Since our operation takes a while, we only want to go ahead if we have at least 50ms.
while (deadline.timeRemaining() > 49 && totalDlElementsLeftToShow > 0) {
// console.log('time remaining is ', deadline.timeRemaining(), '- scheduling next visual update');
// Don't set content-visibility immediately wait for the next
// requestAnimationFrame callback.
scheduleVisualUpdateIfNeeded();
}
// console.log('Deadline reached, will check again the next time the user is idle if there are more events still to send');
if (totalDlElementsLeftToShow > 0) {
requestIdleCallback(processHiddenElements, { timeout: 30000 });
}
}
function scheduleVisualUpdateIfNeeded() {
if (isVisualUpdateScheduled) {
// console.log('returning - visual update already scheduled')
return;
};
isVisualUpdateScheduled = true;
// console.log('requesting animation frame');
requestAnimationFrame(setContentToVisible);
}
function setContentToVisible() {
// console.log('changing visibility of element ');
let completeHiddenNodeList = document.querySelectorAll('dl:not([style*="content-visibility: visible;"]), .ra:not([style*="content-visibility: visible;"]');
// We chunk the layout changes
let i;
let numberToChunk = 20;
if (completeHiddenNodeList.length < 20) {
numberToChunk = completeHiddenNodeList.length
}
for (i = 0; i < numberToChunk; ++i) {
completeHiddenNodeList[i].style.contentVisibility = 'visible';
}
isVisualUpdateScheduled = false;
isRequestIdleCallbackScheduled = false;
totalDlElementsLeftToShow = totalDlElementsLeftToShow - numberToChunk;
}
if (!navigator.userAgentData.mobile) {
startIfNeeded();
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.