I came across performance issues with measuring height/width of a non-tempty unstyled element. Reading following properties seems to be very slow:
.offsetHeight
.clientHeight
.scrollHeight
I've read elsewhere that it is slow because somehow reading them causes reflow. At least, that's what I've found about offsetHeight
, but the other two perform the same. There is some kind of quantum magic here, because logically reading a property should not cause page reflows. Anyway, is there a faster way to find width/height of an element in the easiest possible conditions, where the element doesn't have any style like margin, padding, border
applied to it, or no other styles whatsoever?
.style.height
just returns empty string because it only reads the values from style=""
attribute, which is empty until explicitly defined.
Update: window.getComputedStyle(el).height
performs just as slow.
I came across performance issues with measuring height/width of a non-tempty unstyled element. Reading following properties seems to be very slow:
.offsetHeight
.clientHeight
.scrollHeight
I've read elsewhere that it is slow because somehow reading them causes reflow. At least, that's what I've found about offsetHeight
, but the other two perform the same. There is some kind of quantum magic here, because logically reading a property should not cause page reflows. Anyway, is there a faster way to find width/height of an element in the easiest possible conditions, where the element doesn't have any style like margin, padding, border
applied to it, or no other styles whatsoever?
.style.height
just returns empty string because it only reads the values from style=""
attribute, which is empty until explicitly defined.
Update: window.getComputedStyle(el).height
performs just as slow.
- 9 Simply reading does not cause reflow. However, if you have changed ANYTHING in ANY OTHER ELEMENT there is potential that offsetHeight may have changed. Therefore reading after changing will cause the browser to recalculate the geometry of everything. What is slow is change, read, change, read, change, read. What is fast is change, change, change, read, read, read. This is the reason why React.js and Angular can outperform naive DOM manipulation. – slebetman Commented Aug 30, 2017 at 12:24
- 4 Relevant answer (if not actually duplicate): stackoverflow./questions/19815810/… – slebetman Commented Aug 30, 2017 at 12:26
- 3 Here's a gist of things that cause reflow: gist.github./paulirish/5d52fb081b3570c81e3a – rassar Commented Aug 30, 2017 at 12:26
- @slebetman Are you saying that there is absolutely no way to find out the element's height without causing reflow when dom changes are pending? – Slava Commented Aug 30, 2017 at 12:53
- 1 @Alph.Dev: Think about it. The browser developers have two choices here: either give potentially wrong width and height or recalculate geometry (reflow) and then return the guaranteed correct width and height. Since HTML is specified the way it is - where changes in child elements can force parents to change size and changes in parents can also force children to change size - it is not possible to figure out if sizes have changed or not without actually calculating everyting. Guess which choice browser devs decided to implement? (I'm not sure they have a choice depending on how DOM specs) – slebetman Commented Sep 1, 2017 at 9:11
3 Answers
Reset to default 0There is no fastest way, all of them will have the penalty of at least calling the function and recalculating layout if DOM has changed. Browser optimizations vary, some vendors batch things etc. What you can do is to:
- Batch all DOM changes you want to do, do them in one go, by using
document.createDocumentFragment
etc., and then call the method of your choice - Throttle the call using
requestAnimationFrame
, nextTick usingMessageChannel
trick orasync
functions for next microtask, like here or:
const query = ((cache) => {
const _ = void(0),
raf = window.requestAnimationFrame; //switch it to something else like `next.tick()` or `setTimeout` etc.
return (el) => {
if (cache.value !== _){
return cache.value;
}
raf(()=> cache.value = _);
return cache.value = el.offsetHeight; //change this to whatever method
}
})({value: void(0)});
query(someEl);//2000 etc.
- Like @Kaiido suggested, you can use ResizeObserver, although remember that older browser won't support the API (you will need to use
onScroll
trick on hidden elements to simulate same behavior) and both API and polyfill has the drawback of events not firing onCSS Transforms
.
At the end of the day, there will be situations where you will have to trigger layout change/reflow whatever you use. So >%50 of what you can do boils down to limiting how much you can call your query
function.
(no framework can cheat here, and NO, they do not give you an advantage if you know what you are doing).
What if you use the getBoundingClientRect()
method: This method returns the size of an element and its position relative to the viewport. It does not trigger a reflow, so it can be faster, but it all depends on the plexity of the page and the number of elements on the page.
Window.getComputedStyle()
The Window.getComputedStyle() method returns an object containing the values of all CSS properties of an element, after applying active stylesheets and resolving any basic putation those values may contain.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745616321a4636257.html
评论列表(0条)