To add to the already posted answers.
The key takeaways from my testing:
- setting an element to
display: none;
decreases ram usage
- elements that are not displayed are not affected by layout shifts and therefore have no (or very little) performance cost in this regard
- Firefox is way better at handling lots of elements (~x50)
Also try to minimize layout changes.
Here is my test setup:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body {
margin: 0;
}
.testEl {
width: 100%;
height: 10px;
}
</style>
</head>
<body>
<main id="main"></main>
</body>
<script>
// firefox Max
// const elementCount = 12200000;
// chrome Max
const elementCount = 231000;
const main = document.getElementById("main");
const onlyShowFirst1000 = true;
let _content = ""
for (let i = 0; i < elementCount; i++) {
_content += `<div class="testEl" style="background-color: hsl(${(Math.random() * 360)|0}, 100%, 50%); display: ${!onlyShowFirst1000 || i < 1000 ? "block" : "none"}"></div>`;
}
main.innerHTML = _content;
const addOneEnd = () => {
const newEl = document.createElement("div");
newEl.classList.add("testEl");
newEl.style.backgroundColor = `hsl(${(Math.random() * 360)|0}, 100%, 50%)`
requestAnimationFrame(() => {
main.appendChild(newEl);
})
};
const addOneBeginning = () => {
const newEl = document.createElement("div");
newEl.classList.add("testEl");
newEl.style.backgroundColor = `hsl(${(Math.random() * 360)|0}, 100%, 50%)`
requestAnimationFrame(() => {
main.insertBefore(newEl, main.firstChild);
})
};
const loop = (front = true) => {
front ? addOneBeginning() : addOneEnd();
setTimeout(() => loop(front), 100);
};
</script>
</html>
I create a lot of elements and have the option to only display the first 1000 of them using the onlyShowFirst1000
flag. when displaying all elements, firefox allowed up to ~12200000 elements (using 10gb of my RAM) and chrome up to ~231000.
Memory usage (at 231000 elements):
+----------+----------+-------------+
| false | true | reduction % |
+---------+----------+----------+-------------+
| Chrome | 415,764k | 243,096k | 42% |
+---------+----------+----------+-------------+
| Firefox | 169.9MB | 105.7MB | 38% |
+---------+----------+----------+-------------+
Changing the display property of an element to or from none causes the area to be repainted, but the area of your element will usually be relatively small, therefore the performance cost will also be small.
But depending on your layout, the display change might also cause a layout shift which could be quite costly since it would cause a big part of your page to repaint.
In the future (e.g. chrome 85) you will also be able to use the content-visibility
property to tell the browser which elements dont have to be rendered.
Also, you set the browser to show repaints using the dev tools, for chrome open the rendering tab and check "Paint flashing".