From c223dfc008c4fb041c5432d26aab8a3f426a0998 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Sat, 11 Sep 2021 10:31:17 +0200 Subject: [PATCH] fix(cdk/layout): breakpoint observer not firing callback on chrome in specific cases There appears to be a bug in Chrome, where if we try to use `matchMedia` on a media query that doesn't match anything on the page and a style recalculation is trigger on the `body`, the `matchMedia` callback stops firing which in turn breaks `BreakpointObserver`. These changes expand an existing workaround that we had for WebKit browsers involving inserting a dummy `style` tag on the page so that there's always at least one matching element. Fixes #23546. --- src/cdk/layout/media-matcher.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/cdk/layout/media-matcher.ts b/src/cdk/layout/media-matcher.ts index 25983e73d917..9fcf618a0931 100644 --- a/src/cdk/layout/media-matcher.ts +++ b/src/cdk/layout/media-matcher.ts @@ -35,7 +35,7 @@ export class MediaMatcher { * MediaQueryList for the query provided. */ matchMedia(query: string): MediaQueryList { - if (this._platform.WEBKIT) { + if (this._platform.WEBKIT || this._platform.BLINK) { createEmptyStyleRule(query); } return this._matchMedia(query); @@ -43,8 +43,13 @@ export class MediaMatcher { } /** - * For Webkit engines that only trigger the MediaQueryListListener when - * there is at least one CSS selector for the respective media query. + * Creates an empty stylesheet that is used to work around browser inconsistencies related to + * `matchMedia`. At the time of writing, it handles the following cases: + * 1. On WebKit browsers, a media query has to have at least one rule in order for `matchMedia` + * to fire. We work around it by declaring a dummy stylesheet with a `@media` declaration. + * 2. In some cases Blink browsers will stop firing the `matchMedia` listener if none of the rules + * inside the `@media` match existing elements on the page. We work around it by having one rule + * targeting the `body`. See https://github.com/angular/components/issues/23546. */ function createEmptyStyleRule(query: string) { if (mediaQueriesForWebkitCompatibility.has(query)) { @@ -59,8 +64,7 @@ function createEmptyStyleRule(query: string) { } if (mediaQueryStyleNode.sheet) { - (mediaQueryStyleNode.sheet as CSSStyleSheet) - .insertRule(`@media ${query} {.fx-query-test{ }}`, 0); + mediaQueryStyleNode.sheet.insertRule(`@media ${query} {body{ }}`, 0); mediaQueriesForWebkitCompatibility.add(query); } } catch (e) {