Skip to content

Commit

Permalink
use getClientRects to replace clientWidth/Height calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
jonirrings committed May 11, 2022
1 parent 4a14845 commit eae6f74
Showing 1 changed file with 7 additions and 70 deletions.
77 changes: 7 additions & 70 deletions src/utils/geometry.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,79 +69,16 @@ function getSVGContentRect(target) {
* @returns {DOMRectInit}
*/
function getHTMLElementContentRect(target) {
// Client width & height properties can't be
// used exclusively as they provide rounded values.
const {clientWidth, clientHeight} = target;

// By this condition we can catch all non-replaced inline, hidden and
// detached elements. Though elements with width & height properties less
// than 0.5 will be discarded as well.
//
// Without it we would need to implement separate methods for each of
// those cases and it's not possible to perform a precise and performance
// effective test for hidden elements. E.g. even jQuery's ':visible' filter
// gives wrong results for elements with width & height less than 0.5.
if (!clientWidth && !clientHeight) {
return emptyRect;
}
const rects = target.getClientRects();

const styles = getWindowOf(target).getComputedStyle(target);
const paddings = getPaddings(styles);
const horizPad = paddings.left + paddings.right;
const vertPad = paddings.top + paddings.bottom;

// Computed styles of width & height are being used because they are the
// only dimensions available to JS that contain non-rounded values. It could
// be possible to utilize the getBoundingClientRect if only it's data wasn't
// affected by CSS transformations let alone paddings, borders and scroll bars.
let width = toFloat(styles.width),
height = toFloat(styles.height);

// Width & height include paddings and borders when the 'border-box' box
// model is applied (except for IE).
if (styles.boxSizing === 'border-box') {
// Following conditions are required to handle Internet Explorer which
// doesn't include paddings and borders to computed CSS dimensions.
//
// We can say that if CSS dimensions + paddings are equal to the "client"
// properties then it's either IE, and thus we don't need to subtract
// anything, or an element merely doesn't have paddings/borders styles.
if (Math.round(width + horizPad) !== clientWidth) {
width -= getBordersSize(styles, 'left', 'right') + horizPad;
}

if (Math.round(height + vertPad) !== clientHeight) {
height -= getBordersSize(styles, 'top', 'bottom') + vertPad;
}
}

// Following steps can't be applied to the document's root element as its
// client[Width/Height] properties represent viewport area of the window.
// Besides, it's as well not necessary as the <html> itself neither has
// rendered scroll bars nor it can be clipped.
if (!isDocumentElement(target)) {
// In some browsers (only in Firefox, actually) CSS width & height
// include scroll bars size which can be removed at this step as scroll
// bars are the only difference between rounded dimensions + paddings
// and "client" properties, though that is not always true in Chrome.
const vertScrollbar = Math.round(width + horizPad) - clientWidth;
const horizScrollbar = Math.round(height + vertPad) - clientHeight;

// Chrome has a rather weird rounding of "client" properties.
// E.g. for an element with content width of 314.2px it sometimes gives
// the client width of 315px and for the width of 314.7px it may give
// 314px. And it doesn't happen all the time. So just ignore this delta
// as a non-relevant.
if (Math.abs(vertScrollbar) !== 1) {
width -= vertScrollbar;
}

if (Math.abs(horizScrollbar) !== 1) {
height -= horizScrollbar;
}
if (rects.length === 0) {
// Any elements that are not directly rendered, an empty list is returned.
return emptyRect;
}
const [rect] = rects;
const {left, top, width, height} = rect;

return createRectInit(paddings.left, paddings.top, width, height);
return createRectInit(left, top, width, height);
}

/**
Expand Down

0 comments on commit eae6f74

Please sign in to comment.