Skip to content

Avoid duplication of utility classes in primer/marketing #1242

@tobiasahlin

Description

@tobiasahlin

The problem

primer/marketing uses a spacing scale that goes further (1-12) than primer proper (1-6). Since all sizing classes can be overridden at certain breakpoints (mt-3 mt-md-5 mt-lg-7), these utility classes need to be generated in a specific order:

  • Global first (mt-3)
  • Followed by the next breakpoint (mt-sm-3)
  • Followed by the next breakpoint (mt-md-3), and so on, so forth

This means that we can't generate the primer proper utility classes (1-6) in primer and then just extend these in primer/marketing: mt-9 will unexpectedly override mt-md-3 (wrong), but not mt-md-7 (correct). For this reason, we're currently generating full scales of utility classes (1-12) in primer/marketing, overriding the primer spacing utilities, and making their inclusion in primer effectively redundant while using primer/marketing. This produces a bigger CSS bundle than necessary, but also a fragmented setup where it can be difficult to get a sense of which utility classes that exists, where, and if there are gaps in our utility class coverage or not.

Possible solutions

While exploring this problem with @simurai, we discussed some possible ways of solving this:

  1. Move all marketing variables to primer/primitives, but then make primer/marketing include all of primer (generated with the same set of primitives). This would enable us to load the primer/marketing bundle instead of the primer bundle on marketing pages, removing all potential overlap. It would also reduce render-blocking requests by one on marketing pages. (For what it's worth, we could check if the primer/marketing bundle is being loaded in the application controller, and if so always exclude the primer bundle to make sure that both are never loaded). Caching would be worse with this setup (the primer bundles wouldn't be shared at all between product and marketing pages), but it might not be a significant performance hit.
  2. Extend primer to include the "marketing" spacing scale, and only use the marketing bundle to include other types of utilities, not extensions of the scales. This would undoubtedly increase the size of the primer bundle somewhat, but would keep our current separation of bundles, that apart from this issue seems to work well (?)
  3. Probably not a good idea, but we could keep the current setup but use multiple instances of !important, and explicitly define the scales with higher and higher specificity for each breaking point modifier, i.e. producing .mt-sm-3 { … !important }, .mt-md-3 { … !important !important }, and .mt-lg-3 { … !important !important !important },etc. This would be a complete mess to override, but would go around the problem by not relying on the order of selectors at all.

Are there other ways of solving this that we should outline? Are some of the outlined options worth exploring?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions