@@ -206,7 +206,7 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
206
206
// We use the viewport rect to determine whether a position would go off-screen.
207
207
this . _viewportRect = this . _getNarrowedViewportRect ( ) ;
208
208
this . _originRect = this . _getOriginRect ( ) ;
209
- this . _overlayRect = this . _pane . getBoundingClientRect ( ) ;
209
+ this . _overlayRect = getRoundedBoundingClientRect ( this . _pane ) ;
210
210
211
211
const originRect = this . _originRect ;
212
212
const overlayRect = this . _overlayRect ;
@@ -345,7 +345,7 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
345
345
reapplyLastPosition ( ) : void {
346
346
if ( ! this . _isDisposed && ( ! this . _platform || this . _platform . isBrowser ) ) {
347
347
this . _originRect = this . _getOriginRect ( ) ;
348
- this . _overlayRect = this . _pane . getBoundingClientRect ( ) ;
348
+ this . _overlayRect = getRoundedBoundingClientRect ( this . _pane ) ;
349
349
this . _viewportRect = this . _getNarrowedViewportRect ( ) ;
350
350
351
351
const lastPosition = this . _lastPosition || this . _preferredPositions [ 0 ] ;
@@ -931,8 +931,8 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
931
931
overlayPoint = this . _pushOverlayOnScreen ( overlayPoint , this . _overlayRect , scrollPosition ) ;
932
932
}
933
933
934
- let virtualKeyboardOffset =
935
- this . _overlayContainer . getContainerElement ( ) . getBoundingClientRect ( ) . top ;
934
+ const virtualKeyboardOffset =
935
+ getRoundedBoundingClientRect ( this . _overlayContainer . getContainerElement ( ) ) . top ;
936
936
937
937
// Normally this would be zero, however when the overlay is attached to an input (e.g. in an
938
938
// autocomplete), mobile browsers will shift everything in order to put the input in the middle
@@ -998,13 +998,13 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
998
998
private _getScrollVisibility ( ) : ScrollingVisibility {
999
999
// Note: needs fresh rects since the position could've changed.
1000
1000
const originBounds = this . _getOriginRect ( ) ;
1001
- const overlayBounds = this . _pane . getBoundingClientRect ( ) ;
1001
+ const overlayBounds = getRoundedBoundingClientRect ( this . _pane ) ;
1002
1002
1003
1003
// TODO(jelbourn): instead of needing all of the client rects for these scrolling containers
1004
1004
// every time, we should be able to use the scrollTop of the containers if the size of those
1005
1005
// containers hasn't changed.
1006
1006
const scrollContainerBounds = this . _scrollables . map ( scrollable => {
1007
- return scrollable . getElementRef ( ) . nativeElement . getBoundingClientRect ( ) ;
1007
+ return getRoundedBoundingClientRect ( scrollable . getElementRef ( ) . nativeElement ) ;
1008
1008
} ) ;
1009
1009
1010
1010
return {
@@ -1109,12 +1109,12 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
1109
1109
const origin = this . _origin ;
1110
1110
1111
1111
if ( origin instanceof ElementRef ) {
1112
- return origin . nativeElement . getBoundingClientRect ( ) ;
1112
+ return getRoundedBoundingClientRect ( origin . nativeElement ) ;
1113
1113
}
1114
1114
1115
1115
// Check for Element so SVG elements are also supported.
1116
1116
if ( origin instanceof Element ) {
1117
- return origin . getBoundingClientRect ( ) ;
1117
+ return getRoundedBoundingClientRect ( origin ) ;
1118
1118
}
1119
1119
1120
1120
const width = origin . width || 0 ;
@@ -1219,3 +1219,22 @@ function getPixelValue(input: number|string|null|undefined): number|null {
1219
1219
1220
1220
return input || null ;
1221
1221
}
1222
+
1223
+ /**
1224
+ * Gets a version of an element's bounding `ClientRect` where all the values are rounded down to
1225
+ * the nearest pixel. This allows us to account for the cases where there may be sub-pixel
1226
+ * deviations in the `ClientRect` returned by the browser (e.g. when zoomed in with a percentage
1227
+ * size, see #21350).
1228
+ */
1229
+ function getRoundedBoundingClientRect ( element : Element ) : ClientRect {
1230
+ const clientRect = element . getBoundingClientRect ( ) ;
1231
+
1232
+ return {
1233
+ top : Math . round ( clientRect . top ) ,
1234
+ right : Math . round ( clientRect . right ) ,
1235
+ bottom : Math . round ( clientRect . bottom ) ,
1236
+ left : Math . round ( clientRect . left ) ,
1237
+ width : Math . round ( clientRect . width ) ,
1238
+ height : Math . round ( clientRect . height )
1239
+ } ;
1240
+ }
0 commit comments