alphagov / govuk-frontend

GOV.UK Frontend contains the code you need to start building a user interface for government platforms and services.
https://frontend.design-system.service.gov.uk/
MIT License
1.16k stars 320 forks source link

Add documentation on best practices for deduplicating CSS classes and using `initAll` #3940

Open dabreegster opened 1 year ago

dabreegster commented 1 year ago

Hi, I'm working on converting a mostly-unstyled prototype Svelte app to using GOV.UK. IIUC, everything is defined through CSS classes, so <p>text</p> should generally become <p class="govuk-body">text</p>, and a classless <p> is invalid. I'm concerned specifying a class for every element makes the code less maintainable, and makes it easy for someone to use plain HTML and forget a class. Are there any recommendations or real-world examples we should follow?

Some ideas:

CC @Pete-Y-CS and @ADD-William-WaltersDavis. A real example of manually specifying classes everywhere is in Will's project, https://github.com/ADD-William-WaltersDavis/planning_tool/blob/a586a944c31619ccc12f38f23b800263dbb0f703/components/HoverScores.svelte#L185.

Thanks! (And apologies for not following the issue template; there wasn't any for questions. I'm on secondment to Active Travel England, don't have a gov.uk email, and thus can't join the Slack to ask there)

Pete-Y-CS commented 1 year ago

Happy to be the contact point if you need a govuk email

querkmachine commented 1 year ago

The main GOV.UK website has a specific global class for long-form text content, .govspeak, which automatically applies the styles from those classes to the paragraphs, lists, headings and other elements that appear within it.

We expose many of our text styles as Sass mixins placeholders, so if you have Sass available you could make your own version of the govspeak class that incorporates said mixins placeholders.

// Import govuk-frontend's Sass somewhere in your code

.prose {
  p {
    @extend %govuk-body;
  }
  ul,
  ol {
    @extend %govuk-list;
  }
  ul {
    @extend %govuk-list--bullet;
  }
  ol {
    @extend %govuk-list--number;
  }
  // ...and so on and so forth
}

If you're working without Sass, you may still want to make an equivalent class, but it woud involve more copying and pasting and more effort to ensure it all stays up-to-date with changes.

Regarding the point about maintainability specifically, we never remove classes without issuing some kind of deprecation warning in release notes and, where possible, in code. Renamed classes will also have aliases to the old versions for quite some time. There's a fairly low risk of them being disappeared any time in future!

dabreegster commented 1 year ago

Thanks so much! Hadn't even started looking into Sass yet, but we're happy to take a dependency on it. This approach seems great -- it lets us define the mapping between HTML elements and govuk classes clearly. Pete also just found https://frontend.design-system.service.gov.uk/sass-api-reference/#govuk-compatibility-govukelements-default-value, which appears to do the trick for <p> and <a> already.

Regarding the point about maintainability specifically

Thanks for clarifying that! The concern wasn't govuk classes changing, but about us forgetting to write class="x" on some element as our codebase evolves. I guess also some kind of linter could help with that, but the Sass approach is much, much nicer.

querkmachine commented 1 year ago

Pete also just found https://frontend.design-system.service.gov.uk/sass-api-reference/#govuk-compatibility-govukelements-default-value, which appears to do the trick for <p> and <a> already.

Note that this is a compatibility setting for Elements, one of the frameworks that pre-dated the Design System. We're currently in the process of removing those compatibility settings, so definitely not something to rely upon!

36degrees commented 1 year ago

In terms of extending the placeholder classes to apply to HTML elements, I would recommend doing this inside a specific selector (like .prose as @querkmachine suggested above) and only using it for large areas of text, for example if there is text content provided by a CMS.

If you put other components from the Design System inside an element that has styles applied to type selectors, you may find that they override the component's styles and can cause them to display incorrectly.

Pete also just found https://frontend.design-system.service.gov.uk/sass-api-reference/#govuk-compatibility-govukelements-default-value, which appears to do the trick for <p> and <a> already.

Note that this is a compatibility setting for Elements, one of the frameworks that pre-dated the Design System. We're currently in the process of removing those compatibility settings, so definitely not something to rely upon!

I suspect the link was intended to go to $govuk-global-styles (the next setting on from the one that's linked) which is not part of compatibility mode, but was mainly designed for prototyping rather than use in production.

dabreegster commented 1 year ago

Thank you both for the help! https://github.com/acteng/atip/pull/267 is a minimal start. As we migrate our app over to the styles, we'll use Sass in scoped blocks as suggested to save us some boilerplate.

I'm happy to close this issue, but I'm wondering about updating the docs to save the next person a bit of time. What if we added a step 6 to https://frontend.design-system.service.gov.uk/get-started/ that:

I can send a PR if this makes sense.

Also, another possible update to docs is about where to call initAll: https://github.com/acteng/atip/pull/267#discussion_r1260084593. I don't understand why one worked and the other didn't, but documenting could help other Svelte users. (Or maybe it's a Vite specific issue?) I know @ADD-William-WaltersDavis hit the same thing.

I suspect the link was intended to go to $govuk-global-styles

Oops, correct!