fix(compiler): strip scoped selectors from @font-face rules (#41815)
				
					
				
			`@font-face` rules cannot contain nested selectors. Nor can they be nested under a selector. Normally this would be a syntax error by the author of the styles. But in some rare cases, such as importing styles from a library, and applying `:host ::ng-deep` to the imported styles, we can end up with broken css if the imported styles happen to contain `@font-face` rules. This commit works around this problem by sanitizing such cases (erasing any scoping selectors) during emulated ShadowDOM encapsulation style processing. Fixes #41751 PR Close #41815
This commit is contained in:
		
							parent
							
								
									af12d8deaa
								
							
						
					
					
						commit
						da6ed1562e
					
				| @ -374,11 +374,40 @@ export class ShadowCss { | ||||
|           rule.selector.startsWith('@media') || rule.selector.startsWith('@supports') || | ||||
|           rule.selector.startsWith('@page') || rule.selector.startsWith('@document')) { | ||||
|         content = this._scopeSelectors(rule.content, scopeSelector, hostSelector); | ||||
|       } else if (rule.selector.startsWith('@font-face')) { | ||||
|         content = this._stripScopingSelectors(rule.content, scopeSelector, hostSelector); | ||||
|       } | ||||
|       return new CssRule(selector, content); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Handle a css text that is within a rule that should not contain scope selectors by simply | ||||
|    * removing them! An example of such a rule is `@font-face`. | ||||
|    * | ||||
|    * `@font-face` rules cannot contain nested selectors. Nor can they be nested under a selector. | ||||
|    * Normally this would be a syntax error by the author of the styles. But in some rare cases, such | ||||
|    * as importing styles from a library, and applying `:host ::ng-deep` to the imported styles, we | ||||
|    * can end up with broken css if the imported styles happen to contain @font-face rules. | ||||
|    * | ||||
|    * For example: | ||||
|    * | ||||
|    * ``` | ||||
|    * :host ::ng-deep { | ||||
|    *   import 'some/lib/containing/font-face'; | ||||
|    * } | ||||
|    * ``` | ||||
|    */ | ||||
|   private _stripScopingSelectors(cssText: string, scopeSelector: string, hostSelector: string): | ||||
|       string { | ||||
|     return processRules(cssText, rule => { | ||||
|       const selector = rule.selector.replace(_shadowDeepSelectors, ' ') | ||||
|                            .replace(_polyfillHostNoCombinatorRe, ' '); | ||||
|       const content = this._scopeSelectors(rule.content, scopeSelector, hostSelector); | ||||
|       return new CssRule(selector, content); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   private _scopeSelector( | ||||
|       selector: string, scopeSelector: string, hostSelector: string, strict: boolean): string { | ||||
|     return selector.split(',') | ||||
|  | ||||
| @ -369,6 +369,18 @@ import {normalizeCSS} from '@angular/platform-browser/testing/src/browser_util'; | ||||
|       expect(s(css, 'contenta', 'h')).toEqual('[h] > > .x {}'); | ||||
|     }); | ||||
| 
 | ||||
|     it('should strip ::ng-deep and :host from within @font-face', () => { | ||||
|       expect(s('@font-face { font-family {} }', 'contenta', 'h')) | ||||
|           .toEqual('@font-face { font-family {}}'); | ||||
|       expect(s('@font-face { ::ng-deep font-family{} }', 'contenta', 'h')) | ||||
|           .toEqual('@font-face { font-family{}}'); | ||||
|       expect(s('@font-face { :host ::ng-deep font-family{} }', 'contenta', 'h')) | ||||
|           .toEqual('@font-face { font-family{}}'); | ||||
|       expect(s('@supports (display: flex) { @font-face { :host ::ng-deep font-family{} } }', | ||||
|                'contenta', 'h')) | ||||
|           .toEqual('@supports (display:flex) { @font-face { font-family{}}}'); | ||||
|     }); | ||||
| 
 | ||||
|     it('should pass through @import directives', () => { | ||||
|       const styleStr = '@import url("https://fonts.googleapis.com/css?family=Roboto");'; | ||||
|       const css = s(styleStr, 'contenta'); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user