Skip to content

Commit 0c27d02

Browse files
m-akincchrisdholt
andauthored
Fix CSS custom property precedence issue and work around Chromium bug (#6906)
* Workaround Chrome bug by prepending custom property stylesheet * Switch to Symbol instead of string property name * Change files --------- Co-authored-by: Chris Holt <[email protected]>
1 parent 2bebec0 commit 0c27d02

7 files changed

+58
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "minor",
3+
"comment": "Export Symbol to allow prepending specific stylesheets to adoptedStyleSheets",
4+
"packageName": "@microsoft/fast-element",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "patch",
3+
"comment": "Fix CSS custom property precedence issue and work around Chromium bug",
4+
"packageName": "@microsoft/fast-foundation",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}

packages/web-components/fast-element/docs/api-report.md

+3
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,9 @@ export interface PartialFASTElementDefinition {
463463
readonly template?: ElementViewTemplate;
464464
}
465465

466+
// @public
467+
export const prependToAdoptedStyleSheetsSymbol: unique symbol;
468+
466469
// @public
467470
export class PropertyChangeNotifier implements Notifier {
468471
constructor(source: any);

packages/web-components/fast-element/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export {
1414
ElementStyleFactory,
1515
ComposableStyles,
1616
StyleTarget,
17+
prependToAdoptedStyleSheetsSymbol,
1718
} from "./styles/element-styles.js";
1819
export { css, cssPartial } from "./styles/css.js";
1920
export { CSSDirective } from "./styles/css-directive.js";

packages/web-components/fast-element/src/styles/element-styles.ts

+26-2
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,33 @@ function reduceBehaviors(
133133
return prev.concat(curr);
134134
}, null as Behavior[] | null);
135135
}
136+
137+
/**
138+
* A Symbol that can be added to a CSSStyleSheet to cause it to be prepended (rather than appended) to adoptedStyleSheets.
139+
* @public
140+
*/
141+
export const prependToAdoptedStyleSheetsSymbol = Symbol("prependToAdoptedStyleSheets");
142+
143+
function separateSheetsToPrepend(
144+
sheets: CSSStyleSheet[]
145+
): {
146+
prepend: CSSStyleSheet[];
147+
append: CSSStyleSheet[];
148+
} {
149+
const prepend: CSSStyleSheet[] = [];
150+
const append: CSSStyleSheet[] = [];
151+
sheets.forEach(x =>
152+
(x[prependToAdoptedStyleSheetsSymbol] ? prepend : append).push(x)
153+
);
154+
return { prepend, append };
155+
}
156+
136157
let addAdoptedStyleSheets = (
137158
target: Required<StyleTarget>,
138159
sheets: CSSStyleSheet[]
139160
): void => {
140-
target.adoptedStyleSheets = [...target.adoptedStyleSheets!, ...sheets];
161+
const { prepend, append } = separateSheetsToPrepend(sheets);
162+
target.adoptedStyleSheets = [...prepend, ...target.adoptedStyleSheets!, ...append];
141163
};
142164
let removeAdoptedStyleSheets = (
143165
target: Required<StyleTarget>,
@@ -157,7 +179,9 @@ if (DOM.supportsAdoptedStyleSheets) {
157179
(document as any).adoptedStyleSheets.push();
158180
(document as any).adoptedStyleSheets.splice();
159181
addAdoptedStyleSheets = (target, sheets) => {
160-
target.adoptedStyleSheets.push(...sheets);
182+
const { prepend, append } = separateSheetsToPrepend(sheets);
183+
target.adoptedStyleSheets.splice(0, 0, ...prepend);
184+
target.adoptedStyleSheets.push(...append);
161185
};
162186
removeAdoptedStyleSheets = (target, sheets) => {
163187
for (const sheet of sheets) {

packages/web-components/fast-foundation/src/design-token/custom-property-manager.ts

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
FASTElement,
77
observable,
88
Observable,
9+
prependToAdoptedStyleSheetsSymbol,
910
} from "@microsoft/fast-element";
1011

1112
export const defaultElement = document.createElement("div");
@@ -38,6 +39,7 @@ class ConstructableStyleSheetTarget extends QueuedStyleSheetTarget {
3839
super();
3940

4041
const sheet = new CSSStyleSheet();
42+
sheet[prependToAdoptedStyleSheetsSymbol] = true;
4143
this.target = (sheet.cssRules[sheet.insertRule(":host{}")] as CSSStyleRule).style;
4244
source.$fastController.addStyles(ElementStyles.create([sheet]));
4345
}

packages/web-components/fast-foundation/src/design-token/design-token.spec.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,18 @@ describe("A DesignToken", () => {
787787
await DOM.nextUpdate();
788788
expect(window.getComputedStyle(target).getPropertyValue("width")).to.equal("12px");
789789
removeElement(parent)
790-
})
790+
});
791+
it("should allow stylesheet to override token's CSS custom property", async () => {
792+
const target = addElement();
793+
const token = DesignToken.create<number>("test");
794+
const styles = css`:host{${token.cssCustomProperty}: 34; width: calc(${token} * 1px);}`
795+
target.$fastController.addStyles(styles);
796+
token.setValueFor(target, 12);
797+
798+
await DOM.nextUpdate();
799+
expect(window.getComputedStyle(target).getPropertyValue("width")).to.equal("34px");
800+
removeElement(target)
801+
});
791802
});
792803

793804
describe("with a default value set", () => {

0 commit comments

Comments
 (0)