Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(makeStyles): support ordering for pseudo selectors #17669

Merged
merged 11 commits into from
Apr 7, 2021

Conversation

layershifter
Copy link
Member

@layershifter layershifter commented Apr 1, 2021

Description of changes

This PR adds the concept of style buckets inspired by Compiled: style rules insertion is ordered to follow LVFHA order.

  • Link
  • Visited
  • Focus within, Focus, Focus visible
  • Hover
  • Active

What it means on practice? The behavior of pseudo selectors becomes predictable as they will be inserted always in the same order: rules will be inserted into different style nodes are ordered.

How it works?

Styles are inserted into different nodes based on their priority, see styleBucketOrdering. Style nodes are created on demand, a sample output is below:

<style data-make-styles-bucket>
  .abc {
    color: red;
  }
  .def {
    color: blue;
  }
</style>
<style data-make-styles-bucket="focus">
  .hkl:focus {
    color: green;
  }
  .mno:focus {
    color: magenta;
  }
</style>
<style data-make-styles-bucket="hover">
  .prq:hover {
    color: orange;
  }
</style>

Implementation details

A signature of resolved rules was changed to include a style bucket name:

// before
const ruleBefore = [
  "abcd" // className,
  ".abcd { color: red }", // CSS rule
 // optional CSS rule for RTL
];
// after
const ruleAfter = [
  "", // style bucket name, "" means default
  "abcd" // className,
  ".abcd { color: red }", // CSS rule
 // optional CSS rule for RTL
];

Why we have this in resolved rules? This allows us to perform style bucket computations during build step and avoid runtime work.

I also changed the process of insertion to DOM (createDOMRenderer.ts), now it creates style nodes on demand to have style rules ordered.

Trade-offs

Other pseudo selectors including media queries may unexpectedly clash:

makeStyles({
  root: {
    ":hover": {}, // will be inserted to ":hover" bucket
    ".some-class :hover": {} // will be inserted to "default" bucket
    ":hover:focus": {} // will be inserted to ":hover" bucket
  }
});

@size-auditor
Copy link

size-auditor bot commented Apr 1, 2021

Asset size changes

Project Bundle Baseline Size New Size Difference
office-ui-fabric-react fluentui-react-components-Link 32.916 kB 33.301 kB ExceedsBaseline     385 bytes
office-ui-fabric-react fluentui-react-components-makeStyles 21.878 kB 22.239 kB ExceedsBaseline     361 bytes
office-ui-fabric-react fluentui-react-components-Avatar 45.351 kB 45.703 kB ExceedsBaseline     352 bytes
office-ui-fabric-react fluentui-react-components-Menu 66.431 kB 66.78 kB ExceedsBaseline     349 bytes
office-ui-fabric-react fluentui-react-components-Button 38.023 kB 38.371 kB ExceedsBaseline     348 bytes
office-ui-fabric-react fluentui-react-components-Divider 32.973 kB 33.319 kB ExceedsBaseline     346 bytes
office-ui-fabric-react fluentui-react-components-Image 32.721 kB 33.067 kB ExceedsBaseline     346 bytes

ExceedsTolerance Over Tolerance (1024 B) ExceedsBaseline Over Baseline BelowBaseline Below Baseline New New Deleted  Removed 1 kB = 1000 B

Baseline commit: db4ef40e7be2a30b47e73dd0f0ec9ab17b31f241 (build)

@codesandbox-ci
Copy link

codesandbox-ci bot commented Apr 1, 2021

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 8dd453a:

Sandbox Source
Fluent UI Button Configuration
codesandbox-react-template Configuration
codesandbox-react-northstar-template Configuration
CSS pseudo order Issue #17607

@fabricteam
Copy link
Collaborator

fabricteam commented Apr 1, 2021

Perf Analysis

No significant results to display.

All results

Scenario Render type Master Ticks PR Ticks Iterations Status
Avatar mount 948 913 5000
BaseButton mount 887 910 5000
Breadcrumb mount 42960 43168 5000
ButtonNext mount 548 549 5000
Checkbox mount 1482 1490 5000
CheckboxBase mount 1262 1269 5000
ChoiceGroup mount 4659 4719 5000
ComboBox mount 950 965 1000
CommandBar mount 10099 10143 1000
ContextualMenu mount 6200 6218 1000
DefaultButton mount 1071 1088 5000
DetailsRow mount 3552 3630 5000
DetailsRowFast mount 3606 3580 5000
DetailsRowNoStyles mount 3412 3462 5000
Dialog mount 1426 1413 1000
DocumentCardTitle mount 1803 1832 1000
Dropdown mount 3170 3181 5000
FocusTrapZone mount 1779 1798 5000
FocusZone mount 1792 1821 5000
IconButton mount 1663 1740 5000
Label mount 327 347 5000
Layer mount 1697 1727 5000
Link mount 443 462 5000
MakeStyles mount 1790 1802 50000
MenuButton mount 1438 1419 5000
MessageBar mount 1978 1982 5000
Nav mount 3177 3203 1000
OverflowSet mount 1048 1005 5000
Panel mount 1384 1410 1000
Persona mount 811 811 1000
Pivot mount 1366 1395 1000
PrimaryButton mount 1260 1273 5000
Rating mount 7495 7508 5000
SearchBox mount 1308 1300 5000
Shimmer mount 2479 2512 5000
Slider mount 1973 1952 5000
SpinButton mount 4893 4852 5000
Spinner mount 409 418 5000
SplitButton mount 3084 3102 5000
Stack mount 484 493 5000
StackWithIntrinsicChildren mount 1519 1532 5000
StackWithTextChildren mount 4464 4417 5000
SwatchColorPicker mount 10069 10005 5000
Tabs mount 1351 1364 1000
TagPicker mount 2796 2732 5000
TeachingBubble mount 11685 11688 5000
Text mount 408 414 5000
TextField mount 1331 1384 5000
ThemeProvider mount 1169 1164 5000
ThemeProvider virtual-rerender 599 603 5000
ThemeProviderNext mount 15906 16153 5000
Toggle mount 762 784 5000
buttonNative mount 111 112 5000

Perf Analysis (Fluent)

Perf comparison
Status Scenario Fluent TPI Fabric TPI Ratio Iterations Ticks
🦄 Avatar.Fluent 0.17 0.47 0.36:1 2000 333
🦄 Button.Fluent 0.11 0.2 0.55:1 5000 540
🔧 Checkbox.Fluent 0.63 0.35 1.8:1 1000 631
🎯 Dialog.Fluent 0.15 0.21 0.71:1 5000 741
🔧 Dropdown.Fluent 3.09 0.39 7.92:1 1000 3092
🔧 Icon.Fluent 0.13 0.06 2.17:1 5000 630
🦄 Image.Fluent 0.08 0.13 0.62:1 5000 382
🔧 Slider.Fluent 1.55 0.44 3.52:1 1000 1554
🔧 Text.Fluent 0.07 0.03 2.33:1 5000 363
🦄 Tooltip.Fluent 0.14 0.87 0.16:1 5000 703

🔧 Needs work     🎯 On target     🦄 Amazing

Perf tests with no regressions
Scenario Current PR Ticks Baseline Ticks Ratio
AvatarMinimalPerf.default 215 195 1.1:1
AttachmentMinimalPerf.default 173 159 1.09:1
AccordionMinimalPerf.default 171 161 1.06:1
Avatar.Fluent 333 317 1.05:1
PopupMinimalPerf.default 728 701 1.04:1
RefMinimalPerf.default 256 247 1.04:1
SkeletonMinimalPerf.default 378 365 1.04:1
TableMinimalPerf.default 429 414 1.04:1
Button.Fluent 540 521 1.04:1
Tooltip.Fluent 703 679 1.04:1
ButtonMinimalPerf.default 188 182 1.03:1
CardMinimalPerf.default 563 549 1.03:1
CheckboxMinimalPerf.default 2790 2715 1.03:1
FlexMinimalPerf.default 301 291 1.03:1
FormMinimalPerf.default 413 401 1.03:1
ListMinimalPerf.default 509 494 1.03:1
Text.Fluent 363 353 1.03:1
CarouselMinimalPerf.default 470 459 1.02:1
DatepickerMinimalPerf.default 45946 45034 1.02:1
DividerMinimalPerf.default 374 367 1.02:1
ImageMinimalPerf.default 382 375 1.02:1
ItemLayoutMinimalPerf.default 1259 1231 1.02:1
LoaderMinimalPerf.default 705 688 1.02:1
PortalMinimalPerf.default 178 175 1.02:1
IconMinimalPerf.default 618 606 1.02:1
ToolbarMinimalPerf.default 947 928 1.02:1
Checkbox.Fluent 631 619 1.02:1
Dialog.Fluent 741 726 1.02:1
Dropdown.Fluent 3092 3029 1.02:1
Icon.Fluent 630 618 1.02:1
Image.Fluent 382 376 1.02:1
ChatDuplicateMessagesPerf.default 301 298 1.01:1
ChatWithPopoverPerf.default 385 382 1.01:1
DialogMinimalPerf.default 738 730 1.01:1
DropdownManyItemsPerf.default 685 678 1.01:1
EmbedMinimalPerf.default 4135 4103 1.01:1
HeaderSlotsPerf.default 762 756 1.01:1
ProviderMinimalPerf.default 1004 996 1.01:1
SegmentMinimalPerf.default 362 357 1.01:1
SliderMinimalPerf.default 1588 1567 1.01:1
SplitButtonMinimalPerf.default 3689 3670 1.01:1
StatusMinimalPerf.default 681 676 1.01:1
TextAreaMinimalPerf.default 486 480 1.01:1
AnimationMinimalPerf.default 419 420 1:1
AttachmentSlotsPerf.default 1138 1140 1:1
BoxMinimalPerf.default 359 359 1:1
ButtonSlotsPerf.default 560 560 1:1
ButtonUseCssPerf.default 809 809 1:1
ChatMinimalPerf.default 611 610 1:1
GridMinimalPerf.default 346 345 1:1
HeaderMinimalPerf.default 370 369 1:1
InputMinimalPerf.default 1261 1258 1:1
LabelMinimalPerf.default 396 395 1:1
ListNestedPerf.default 559 558 1:1
ListWith60ListItems.default 618 615 1:1
MenuMinimalPerf.default 862 860 1:1
MenuButtonMinimalPerf.default 1536 1531 1:1
TextMinimalPerf.default 355 354 1:1
CustomToolbarPrototype.default 3832 3834 1:1
TreeMinimalPerf.default 768 769 1:1
Slider.Fluent 1554 1560 1:1
AlertMinimalPerf.default 282 284 0.99:1
DropdownMinimalPerf.default 3034 3050 0.99:1
LayoutMinimalPerf.default 367 370 0.99:1
ProviderMergeThemesPerf.default 1650 1664 0.99:1
RadioGroupMinimalPerf.default 434 440 0.99:1
TableManyItemsPerf.default 1905 1920 0.99:1
ButtonOverridesMissPerf.default 1685 1718 0.98:1
ButtonUseCssNestingPerf.default 1048 1074 0.98:1
ReactionMinimalPerf.default 376 384 0.98:1
TooltipMinimalPerf.default 944 959 0.98:1
ListCommonPerf.default 591 626 0.94:1
RosterPerf.default 1113 1187 0.94:1
TreeWith60ListItems.default 171 184 0.93:1
VideoMinimalPerf.default 595 653 0.91:1

"@supports (display: table-cell){.foo{color:red;}}",
]
`);
});
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests are not related to changes in this PR, but are still valuable.

try {
if (renderer.styleElement.sheet instanceof CSSStyleSheet) {
renderer.styleElement.sheet.insertRule(ruleCSS, renderer.index);
renderer.index++;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't rely on renderer.index for .insertRule() as insertion runs for different style nodes now.

];

// Renderer types

export type MakeStylesMatchedDefinitions = Record<string, MakeStylesResolvedRule>;
export type MakeStylesReducedDefinitions = Record<string, MakeStylesResolvedRule>;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This type was renamed as we don't have "matchers" anymore.

@layershifter layershifter marked this pull request as ready for review April 6, 2021 11:04
@@ -116,11 +116,11 @@ export function ax(dir: 'ltr' | 'rtl', classNames: (string | false | undefined)[
const resultDefinition = resultDefinitions[property];

if (isRtl) {
const rtlPrefix = isRtl && resultDefinition[2] ? RTL_PREFIX : '';
const rtlPrefix = isRtl && resultDefinition[3] ? RTL_PREFIX : '';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the time to introduce constants?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw, is there a way to force-inline a constant?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw, is there a way to force-inline a constant?

Terser will do it for us, I created a sandbox to show it: https://codesandbox.io/s/terser-forked-txjd2?file=/src/index.js

Is this the time to introduce constants?

Great idea, I will add them in a follow up PR, in this case we will be sure that it does not affect bundle size 👍

@layershifter layershifter merged commit 0b50201 into master Apr 7, 2021
@layershifter layershifter deleted the fix/insert-pseudo-order branch April 7, 2021 11:59
@msft-fluent-ui-bot
Copy link
Collaborator

🎉@fluentui/make-styles@v9.0.0-alpha.9 has been released which incorporates this pull request.:tada:

Handy links:

miroslavstastny pushed a commit to miroslavstastny/fluentui that referenced this pull request May 5, 2021
* fix(makeStyles): support ordering for pseudo selectors

* Change files

* fix insertion

* add a VR test

* fix tabIndexes

* update VR tests

* update VR tests

* update VR tests again

* update VR tests

* update VR tests

* update VR tests
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

makeStyles: behavior of pseudo selectors in not deterministic
4 participants