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

Investigate ways to let users customise the typography scale in govuk-font #3837

Closed
5 tasks done
Tracked by #2289
owenatgov opened this issue Jun 21, 2023 · 11 comments
Closed
5 tasks done
Tracked by #2289

Comments

@owenatgov
Copy link
Contributor

owenatgov commented Jun 21, 2023

What

Investigate how we could extend the govuk-font mixin to allow users to, where necessary, bypass the responsive scale.

Why

During the audit of our components against the new typography scale (alphagov/govuk-design-system#2299) we noticed there are some instances where we do still want values that we've now set to not drop down a size on small screens to still drop down. For example: table cell content in the new type scale is now 19 on big and small screens by default, where it actually would be more readable if it was 16 on small screens.

Developers using govuk-frontend currently have a couple of hacky options to do achieve this:

1: apply 2 govuk-font's between breakpoints

.my-class {
  @include govuk-font($size: 16);

  @include govuk-media-query($from: tablet) {
    @include govuk-font($size: 19);
  }
}

This works, however it creates a lot of repeated code as govuk-font includes several useful typography rules as well as the corresponding font size.

2: use $size: false to only need to call govuk-font once

.my-class {
  @include govuk-font($size: false);
  font-size: govuk-px-to-rem(16px);

  @include govuk-media-query($from: tablet) {
    font-size: govuk-px-to-rem(19px);
  }
}

This solves the precise problem in option 1, but is itself quite messy. It's trickier to parse at a glance, actively advises misusing our own tooling and potentially encourages ignoring the typography scale at all. We should avoid this solution where possible.

Related issue: #2456

Part of alphagov/govuk-design-system#2289

Timebox

1 sprint (2 weeks)

Who is working on this?

Developers

Spike lead:
@owenatgov

Spike buddy:
TBD

Questions to answer

  • How do we implement a means to customise govuk-font without letting teams ignore our typography scale recommendations?
  • How can we document this?

Done when

  • Questions have been answered or we have a clearer idea of how to get to our goal
  • Findings have been reviewed and agreed with at least one other person
  • Findings have been shared, e.g: via a write-up on the ticket, at a show & tell or team meeting
@owenatgov
Copy link
Contributor Author

Initial investigation

I explored 4 initial solutions:

  • Letting users pass a map of scale values by breakpoint into $size as well as a single scale value
  • Adding boolean values to control if the loop over the breakpoints in the scale map happens or not
  • Adding extra params that override $size based on breakpoint eg: having a $size of 16 but a $tablet of 19 would (at this time) result in a small screen font size of 14px and a large screen size of 19px
  • Adding a map param that allows users to specify a breakpoint, scale value and breakpoint within that scale to pick a specific font size/line height map within the scale to override the equivalent map within the scale value they picked

Draft implementations for these solutions can be found in the commits of my test branch. Further details can be found in the comments under each commit.

Summary of findings

A problem which ran through the first 3 solutions is: what does the user think the scale value will result in? For example if in any of the solutions a user picks a "default" of 24 and an "override" of 19, what should we return? Should we return "tablet" map with a 19px font size or the "null" map which is a 16px font size, intended for small screens? The ideology of our font scale maps within maps within a map system and the naming therein doesn't make it clear what a scale value's "default" will be.

This led to solution 4 where the user can pick a specific font map by scale value and breakpoint and reapply it to the scale map they initially picked.

Further thoughts

This was discussed with the other design system devs and the followings ideas and points were raised:

Letting users build their own font maps

Could we simply pass a map to $size instead of a value which was off the format of one of our scale maps as a way to "customise" the scale? Example:

@include govuk-font(
  $size: (
    null: (
      font-size: 15px,
      line-height: 2
    ),
    print: (
      font-size: 10pt,
      line-height: 2
    )
  )
);

You could extend this by combining it with my 4th solution where the override map we use isn't itself navigation to a point on the scale but a font-scale format map which we just replace on the pulled scale map at the specified breakpoint:

@include govuk-font(
  $size: 19,
  $scale-override: (
    tablet: (
      font-size: 21px,
      line-height: 2
    )
  )
);

You could add checks to make sure that the map passed followed the format of our font maps. This would reduce how much interaction we have with $govuk-typography-scale within our own mixins and generally reduce the heavy lifting that govuk-font and govuk-typography-responsive do. A risk introduced here is that it means users can undermine our scale very easily by passing non-scale values such as 12px. Is this a risk we're will to absorb?

Is govuk-font doing too much?

Right now, the mixin is doing the following:

  • applying the govuk-typography-common mixin
  • adding rules for tabular font settings
  • adding rules for font weight
  • adding font size and line height
  • adding font size and line height for the "tablet" breakpoint
  • adding font size and line height for print

Whilst a single mixin to control everything to do with fonts is simple in theory, especially if what you're styling doesn't deviate from the type scale, it creates complexity for us in maintaining the mixin and accidental complexity for users who want to interact with our scale more. Is this still fit for purpose or is there an opportunity to reconsider our approach to the type scale API?

There is already an issue for splitting out tabular functions from govuk-font so there's a case for breaking the mixin down further and asking users to include more mixins in their custom styling, which is more lines of sass for them at the benefit of an easier to understand API.

A thought off of this on how to break it down is that we firstly do something similar to our model for the spacing scale where we have one mixin that includes the specified spacing value and automates authoring of the the breakpoints (govuk-responsive-spacing) and a function that just get's the top-level scale value (govuk-spacing). It could look like this:

// get the font size and line height based on scale value and breakpoint
@include govuk-font-size($size: 19, $breakpoint: tablet);

// like above but handle breakpoints for the user
@include govuk-responsive-font-size($size: 19);

You could take this further by making font-size and line-height functions (line height is already a private function: _govuk-line-height) and make print styles a separate mixin.

Common items like govuk-typography-common and font weight could then be moved into their own mixin with the former potentially absorbing the latter and tabular could be a separate mixin.

Next steps

I will explore the proposals outlined in the above 2 headings and start thinking about how they could be documented.

@owenatgov
Copy link
Contributor Author

owenatgov commented Sep 18, 2023

I've explored the 2nd heading aka: changing how users interact with fonts and the typography scale. I've made a proof of concept in this commit. Breaking it down, I'm proposing to split govuk-font into 4 mixins:

  1. govuk-font-size: takes a typography scale value and a breakpoint on that font map as arguments and returns a font size and line height relative to the scale value and breakpoint specified. Also handles line height overrides and if you also want the print map with a media query.
  2. govuk-responsive-font-size: Like govuk-font-size but presumes you want the entire font map with automated media queries. Functionally identical to govuk-typography-responsive.
  3. govuk-typography: Specifies font family and some useful rules like anti-aliasing as well as font weight. A combination of govuk-typography-common and the 2 govuk-typography-weight-[weight] mixins.
  4. govuktypography-tabular: Tabular rules and settings. Essentially solves Split tabular numbers functionality out from the govuk-font mixin #3778.

You can see an example of how this would be implemented in my proof of concept commit where I apply it to the table component, both refactoring the component and applying needs from #3778 and #3922 to the component to test it completely. Broadly speaking, a user refactoring govuk-font to this method could do the following:

// current setup
.my-class {
  @include govuk-font($size: 19, $weight: bold);
}

// with proposed mixin setup
.my-class {
  @include govuk-typography($weight: bold);
  @include govuk-responsive-font-size($size: 19);
}

This would result in more lines of code for users but I would argue it makes it clearer what the user is getting in the 2 mixins rather than just govuk-font and makes it much better for customisation.

Some additional considerations not explored in this proof of concept:

  • The $important param and how and where to apply it
  • Do we actually need a $print param or should we just let users retrieve this from the breakpoint map like the other breakpoints?
  • Automated testing

@colinrotherham
Copy link
Contributor

Great proposal @owenatgov, keeps breaking changes away too

With typefaces or font families (GDS Transport) coming in multiple styles (Regular, Bold) how about:

govuk-typography() govuk-font-style()

Helps follow that A-Z of our font utilities starting with govuk-font-*

@owenatgov
Copy link
Contributor Author

@colinrotherham I like it! As you've said it sticks to the namespacing convention laid out in the other mixins.

@36degrees
Copy link
Contributor

Given how pervasive it is, I don't think we should get rid of govuk-font unless we have a very good reason for doing so. I think there's a significant difference between splitting out the tabular numbers (which are rarely used) and removing the mixin entirely.

I'm still really not sure about the govuk-font-size mixin. I get the desire is to pluck values from the existing spacing scale but unfortunately I think it's just too unintuitive. Look again at the implementation for .govuk-table--complex:

.govuk-table--complex {
@include govuk-font-size($size: 16, $breakpoint: "null");
}

Based on previous discussions, I believe your intention here was to get 16px on mobile, 19px on tablet and desktop.

But what govuk-font-size($size: 16, $breakpoint: null) actually gives you is 14px at all breakpoints, because it's getting the equivalent mobile font size for the 16px point in the scale based on desktop size.

What you'd actually need to do is something like this:

.govuk-table--complex {
  @include govuk-font-size($size: 16, $breakpoint: tablet);

  @include govuk-media-query($from: tablet) {
    @include govuk-font-size($size: 19, $breakpoint: tablet);
  }
}

As I understand it, the main thing we want to solve here is that there are some instances where dropping from 19px to 16px on desktop makes sense, and we want to allow that.

Can I suggest we consider a much simpler alternative, which is to preserve the existing version of the 19px point in the scale with a different key?

$govuk-typography-scale: (
  // ...
  19: (
    null: (
      font-size: 19px,
      line-height: 25px
    ),
    print: (
      font-size: 14pt,
      line-height: 1.15
    )
  ),
  19r: (
    null: (
      font-size: 16px,
      line-height: 20px
    ),
    tablet: (
      font-size: 19px,
      line-height: 25px
    ),
    print: (
      font-size: 14pt,
      line-height: 1.15
    )
  ),
  // ...
)

We can then just do:

  .govuk-table--complex {
    @include govuk-font($size: 19r);
  }

@owenatgov
Copy link
Contributor Author

owenatgov commented Sep 19, 2023

@36degrees Thanks for the comment. I have some thoughts.

Firstly, could you go more into why removing govuk-font isn't good? Are you thinking that it should stay to avoid deprecation and refactoring work and replace of of the above proposed split out mixins or do you think it should stay as it is?

Secondly, good catch on govuk-font-size. I should've really done this spike against the new scale and I would've caught this. However, is the user managing their own breakpoints (in this case it's us doing it) if they need to break from the standard so bad? This might be my bias based on my govuk experience where we had to do a lot of "hacking" of govuk-font to meet specific needs. In these cases I'd be willing do do something like that to manage this.

This leads into my last point on the extra scale map idea. This solves #3922 but I think there's still value in scrutinising govuk-font since it hides things like govuk-typography-common behind an assumption that it just handles font size (that's a bold statement based on light anecdotal evidence from my time on govuk, being surprised at what happened when I would stretch the needs of govuk-font).

@colinrotherham
Copy link
Contributor

Ah I missed that govuk-font() was up for removal

Liked how the "split out" mixins would let us reduce all the font-family boilerplate repeated in lots of places

@36degrees
Copy link
Contributor

@36degrees Thanks for the comment. I have some thoughts.

Firstly, could you go more into why removing govuk-font isn't good? Are you thinking that it should stay to avoid deprecation and refactoring work and replace of of the above proposed split out mixins or do you think it should stay as it is?

I think we need a really good reason to make breaking changes and I just don't see what that is at the minute, but maybe I'm missing something. Generally I think it's a useful mixin that works in the vast majority of cases to give users everything they need to typographically style an element.

Referring back to your earlier comment:

it creates complexity for us in maintaining the mixin and accidental complexity for users who want to interact with our scale more

Can you give an example of a time that the govuk-font mixin created overhead (additional work or complexity) for us as a team?

Whilst it's true it doesn't meet every need, in instances where users want to do something 'custom' they still have the underlying mixins which they can compose instead.

Secondly, good catch on govuk-font-size. I should've really done this spike against the new scale and I would've caught this. However, is the user managing their own breakpoints (in this case it's us doing it) if they need to break from the standard so bad? This might be my bias based on my govuk experience where we had to do a lot of "hacking" of govuk-font to meet specific needs. In these cases I'd be willing do do something like that to manage this.

IMO we're taking something that's currently relatively simple (and well understood by our users) and adding a lot of complexity to try and enable users to solve problems we don't really understand ourselves yet.

I think in the vast majority of cases we want users to stick to the typography scale. If the typography scale isn't meeting user's needs, we should revisit it rather than optimising for people deviating from it.

I think we should find the easiest way to solve the specific problem we have at hand (a way to preserve specifically 16px mobile / 19px tablet and above in certain situations).

This leads into my last point on the extra scale map idea. This solves #3922 but I think there's still value in scrutinising govuk-font since it hides things like govuk-typography-common behind an assumption that it just handles font size (that's a bold statement based on light anecdotal evidence from my time on govuk, being surprised at what happened when I would stretch the needs of govuk-font).

Paraphrasing to check I'm understanding this correctly – the issue is that some users think that govuk-font only sets the font size, and don't realise that it also sets the font family, font smoothing and font-weight properties? Is that right?

I agree that there are plenty of examples of people using govuk-font where they could just use govuk-typography-responsive (they don't need to re-set the font family etc).

I don't think that this provides enough justification to remove the mixin entirely (especially as although there is repetition, it compresses really well as the properties appear in the same order every time)

Before we remove the mixin I think we should first try:

  • improving the documentation so that users understand what our mixins are and how to use them
  • renaming govuk-typography-responsive to something shorter and more obvious (like govuk-font-size)

@colinrotherham
Copy link
Contributor

@36degrees Here's an example I shared on Slack in alphagov/govuk-design-system@d53ca8c

E.g. Having to use govuk-typography-responsive() because govuk-font() keeps writing out font-family styles

@owenatgov
Copy link
Contributor Author

@36degrees I'm gonna try to answer your questions holistically.

Firstly, I think the overall proposal is too contentious and isn't backed up enough to go ahead with. The new scale and specifically the fact that for 16 and 19 we're not producing separate tablet breakpoints is going to likely remove a lot of the need for any sort of customisation. Looking again at the govuk-table--complex example, with the new scale you could actually do it like this with no repetition of breakpoints or common typography:

.govuk-table {
  @include govuk-font($size: 19);
}
// ...
.govuk-table--complex {
  @include govuk-typography-responsive($size: 16);

  @include govuk-media-query($from: tablet) {
    @include govuk-typography-responsive($size: 19);
  }
}

That's identical to the govuk-font-size solution you gave above which I know you felt was unintuitive but I think it's fine personally. I'm still a little unsure of adding an extra scale map just for this as it feels like an addition to a global setting for a specific use case.

IMO this discussion has uncovered the root problem which is our typography documentation. I think therefore going with your ideas of improving our documentation and renaming govuk-typography-responsive to something easier to understand (I like govuk-font-size 😃) covers both exposing how to use the typography scale and "API as documentation" mixin ecosystem naming, which was a secondary aim of my throw it away adn start again proposal above.

Having said all that, I'm going to record some examples where govuk-font hasn't been perfect here so we have it written down (besides Colin's example above). All of these examples would be solved by the amended scale and clearer documentation around the use of our non govuk-font font ecosystem mixins:

My instinct now is to close this issue, create a new one to reconsider the name of govuk-typography-responsive, move the findings of this spike into alphagov/govuk-design-system#2300 and filter #3922 into the typography epic work. Any objections?

@owenatgov
Copy link
Contributor Author

New issues have been jotted up. I'm therefore going to close this as the investigation is concluded.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

No branches or pull requests

3 participants