Page MenuHomePhabricator

[Spike] Determine how to prevent styling issues due to load order of component styles
Closed, ResolvedPublicSpike

Description

Problem

When testing this patch, a proof-of-concept of a code-splitting solution that allows features to load only the individual components they need (and their dependencies), this visual regression occurred in the Vector search box:

Screenshot 2023-08-10 at 4.00.27 PM.png (1×3 px, 984 KB)

The misalignment and apparent double-border of the search input and button happen because we expect styles written for the SearchInput component targeting its internal button to overrides styles that appear in the Button component. However, with this new system, the Button styles are apparently being loaded after the SearchInput styles, and both styles are applied to selectors with the same specificity, so the Button styles win out.

Potential solutions

Requirements
  • We should aim to load styles in the same order in all contexts (main Codex bundle, in MediaWiki, on the docs site)
  • We should probably rely on build tooling rather than coding standards/patterns
Option 1: Always load styles alphabetically

The SearchInput button styles previously worked somewhat accidentally because we were loading styles in alphabetical order, and SearchInput comes after Button. We could ensure that ResourceLoader always loads styles alphabetically to match what's happening on the docs site and in the main bundle.

This is arbitrary, though, and should likely only be done as a stop-gap solution until we can implement a longer-term one.

Option 2: Load styles in dependency order

In all contexts, we would need to load styles in dependency order, i.e. load dependencies before dependents. If SearchInput requires Button, then Button styles should be loaded first so that SearchInput styles can override them.

This would require appropriate control of style order in all contexts.

Option 3: Make component style overrides more specific

For all components that require and style other components, we would need to increase the specificity of the selectors. E.g. for the SearchInput end button, instead of the status quo:

.cdx-search-input {
    &__end-button {
        // override styles
    }
}

We would do something like this:

.cdx-search-input {
    .cdx-search-input__end-button {
        // override styles
    }
}

This would enable us to load components in any order, but would require Codex developers to follow this pattern, which they could easily forget to do.


Acceptance criteria

  • Agree on requirements
  • Determine the path forward and open a new task for it

Event Timeline

Restricted Application added a subscriber: Aklapper. · View Herald Transcript
CCiufo-WMF renamed this task from [SPIKE] Determine how to prevent styling issues due to load order of component styles to [Spike] Determine how to prevent styling issues due to load order of component styles.Aug 15 2023, 9:33 PM
CCiufo-WMF changed the subtype of this task from "Task" to "Spike".

It turns out option 2 was already what was happening, so we don't need to do anything here.

Change 972068 had a related patch set uploaded (by Eric Gardner; author: Eric Gardner):

[design/codex@main] Input with Button mixin: Increase specificity of button styles

https://gerrit.wikimedia.org/r/972068

I've re-opened this task, because it is relevant to T350054.

If there are multiple custom CodexModules getting loaded on the same page, this is something that can indeed happen and which we'll need to figure out.

I made an inventory of all components that style one or more of their subcomponents:

  • Accordion: Button, Icon
  • ButtonGroup: Button
  • Card: Icon, Thumbnail
  • Checkbox: Label (via binary-input.less)
  • Combobox: Button, Icon, TextInput
  • Dialog: Button
  • InfoChip: Icon
  • InputChip: Button
  • Label: Icon
  • Lookup: TextInput
  • Menu: MenuItem, ProgressBar
  • MenuItem: Icon, Thumbnail
  • Message: Button, Icon
  • Radio: Label (via binary-input.less)
  • SearchInput: Button, TextInput
  • Select: Icon
  • Tabs: Button (cdx-tabs__list__item)
  • TextArea: Icon
  • TextInput: Icon
  • Thumbnail: Icon
  • ToggleButtonGroup: ToggleButton
  • ToggleSwitch: Label
  • TypeaheadSearch: Icon, MenuItem, SearchInput

Obviously, this is most components. I think we should carefully consider whether and how to increase the specificity of so many styles. My open questions are:

  • Should we do this at all? It seems like there's no alternative other than perfect deduplication, which at the very least we're not implementing now. So we probably do need to increase specificity of at least some styles. Which leads me to...
  • Should we increase specificity of all of these instances, or just some? You could argue that some of these styles do not need to be more specific because they set new styles rather than overriding styles in the original component. However, I think this would be difficult to determine and track, and could be confusing when adding new styles - you'd have to cross-reference the new style with the original component's styles.
  • How should we increase specificity? I see two ways of increasing specificity by adding a class:
    • Repeat the parent class, e.g. .cdx-search-input .cdx-search-input__end-button. This could be done in a mixin by using the parent selector, e.g. & &__end-button
    • Add the subcomponent's class onto the selector, e.g. .cdx-search-input__end-button.cdx-button

I personally think we should:

  • Create and document a standard in the library where we always add specificity when styling a subcomponent
  • Add the subcomponent's class as an additional class selector. I think this makes it very clear which subcomponent you're styling, which is useful when you're just looking at the style block and may not be 100% sure what subcomponent`&__input` refers to

I made an inventory of all components that style one or more of their subcomponents:

Thanks @AnneT, this is great.

I personally think we should:

  • Create and document a standard in the library where we always add specificity when styling a subcomponent
  • Add the subcomponent's class as an additional class selector. I think this makes it very clear which subcomponent you're styling, which is useful when you're just looking at the style block and may not be 100% sure what subcomponent`&__input` refers to

I am in agreement with this. The only situation where things could get tricky is any place that we might be doing <component :is="someComponent" class=".my-override-class"> – in that case we'd have to write multiple rules (.my-override-class.cdx-button, .my-override-class.cdx-icon, etc) or come up with some other means of increasing specificity (& & or something).

In practice I think this will only come up for certain components (i.e. Typeahead, since it loads on every page). But we might as well try to solve this problem in a consistent way.

Catrope assigned this task to AnneT.

I think we've agreed on an approach here, so I have filed T351753 to capture it.