digdir / designsystemet

Designsystemet
https://designsystemet.no
MIT License
84 stars 38 forks source link

Font based sizing #2508

Open eirikbacker opened 2 months ago

eirikbacker commented 2 months ago

TL;DR: Her er et kjørende eksempel: https://codepen.io/eirikbacker/pen/RwXNpXo

Prerequisite #2526

### Tasks
- [ ] Document how data-size (and data-color) works: globally and on components
- [ ] Update Figma
- [ ] https://github.com/digdir/designsystemet/issues/2674
- [ ] https://github.com/digdir/designsystemet/issues/2665
- [x] #2541
- [ ] https://github.com/digdir/designsystemet/issues/2671
- [ ] https://github.com/digdir/designsystemet/issues/2673

Har tenkt en stund på dette med size. I de fleste tilfeller, vil vi at når man setter size, på en komponent, så påvirker det også bestanddelene inni. F.eks; Pagination size="sm" gjør at Pagination.Button også skal ha size="sm", Dropdown size="sm" gjør at Dropdown.Item skal ha size="sm" og så videre.

La oss ta et eksempel med Pagination:

  1. CSS er skikkelig god på å arve en stil fra forelder og nedover til barna.
  2. Enste utfordringen er da at det må være samme stil, så f.eks setter jeg padding: 5px på Pagination, så er det lett å arve padding: 5pxPagination.Button.
  3. Men, vi vil jo ikke ha padding: 5pxPagination, vi vil ha padding: 0Pagination, men fortstatt ha padding: 5pxPagination.Button - hvordan får vi til det?
  4. Jo, det er én ting vi vil at skal arves nedover: font-size
  5. Det betyr, at hvis padding kan basere seg på font-size, så får vi til noen nydelige padding-skalaer - også på Pagination.Button - som blir større og mindre, når font-size justeres.
  6. Det vil også bety, at når gap skal øke på selve Pagination, så trenger vi ikke å definere gap mange ganger, fordi gap også kan basere seg på font-size.

Dette vil være relevant for gap/padding/margin/width/height - alt som handler om størrelse, kan være skala-basert på font-size

I stede for å skrive slik som i dag:

.ds-button {
  --dsc-button-font-size: var(--ds-font-size-5);
  --dsc-button-gap: var(--ds-spacing-2);
  --dsc-button-padding-block: var(--ds-spacing-2);
  --dsc-button-padding-inline: var(--ds-spacing-4);

  font-size: var(--dsc-button-font-size);
  gap: var(--dsc-button-gap);
  padding: var(--dsc-button-padding-block) var(--dsc-button-padding-inline);

  &[data-size='sm'] {
    --dsc-button-font-size: var(--ds-font-size-4);
    --dsc-button-gap: var(--ds-sizing-1);
    --dsc-button-padding-block: var(--ds-spacing-2);
    --dsc-button-padding-inline: var(--ds-spacing-3);
  }

  &[data-size='lg'] {
    --dsc-button-font-size: var(--ds-font-size-6);
    --dsc-button-gap: var(--ds-sizing-3);
    --dsc-button-padding-block: var(--ds-spacing-3);
    --dsc-button-padding-inline: var(--ds-spacing-5);
  }
}

Kunne vi ha skrevet dette:

.ds-button {
  --dsc-button-font-size: var(--ds-font-size-5);

  font-size: var(--dsc-button-font-size);
  gap: var(--ds-sizing-scale-2);
  padding: var(--ds-sizing-scale-2) var(--ds-sizing-scale-4);

  &[data-size='sm'] { --dsc-button-font-size: var(--ds-font-size-4); }
  &[data-size='lg'] { --dsc-button-font-size: var(--ds-font-size-6); }
}

Og isteden for å skrive slik når (man ikke bruker React):

<nav class="ds-pagination" data-size="sm"> <-- data-size må gjentas
  <ol>
    <li><button type="button" data-size="sm">1</button></li> <-- data-size må gjentas
    <li><button type="button" data-size="sm">2</button></li> <-- data-size må gjentas
    <li><button type="button" data-size="sm">3</button></li> <-- data-size må gjentas
    <li><button type="button" data-size="sm">4</button></li> <-- data-size må gjentas
    <li><button type="button" data-size="sm">5</button></li> <-- data-size må gjentas
    <li><button type="button" data-size="sm">6</button></li> <-- data-size må gjentas
  </ol>
</nav>

Vil man kunne skrive dette:

<nav class="ds-pagination" data-size="sm"> <-- data-size er satt én gang wee
  <ol>
    <li><button type="button">1</button></li>
    <li><button type="button">2</button></li>
    <li><button type="button">3</button></li>
    <li><button type="button">4</button></li>
    <li><button type="button">5</button></li>
    <li><button type="button">6</button></li>
  </ol>
</nav>

Systemet baserer seg på at man lager en (eller flere) skala, basert på font-size:

:root {
  --ds-sizing-scale: .875rem;
  /* 👆 14px at 1rem, must be smaller than smallest font-size to have effect (because 14px font size - 14px scale = 0) */

  --ds-sizing-scale-1: calc(1em - var(--ds-sizing-scale) * 1);
  /* 👆 4px at sm, 8px at md, 12px at lg */
  --ds-sizing-scale-2: calc(2em - var(--ds-sizing-scale) * 2);
  /* 👆 6px at sm, 12px at md, 18px at lg */
  --ds-sizing-scale-3: calc(3em - var(--ds-sizing-scale) * 3);
  /* 👆 8px at sm, 16px at md, 24px at lg */
  --ds-sizing-scale-4: calc(4em - var(--ds-sizing-scale) * 4);
}

Da går det også an å gjøre:

/* For å endre størrelse til mobil med ren CSS: */
@media(max-width: 80em) {
  .ds-button { --dsc-button-font-size: var(--ds-font-size-4) }
}

...så dette tror jeg vil være mulig å gjenskape i Figma også?

Ser at det vil kreve en liten opprydding; er ikke alltid vi skalerer gap f.eks konsekvent, men det tror jeg er fint å rydde i uansett. Vil gjerne høre hva dere tenker og gjerne sparre med @Thunear og @Febakke litt på om det designmessig gir mening også.

Vil også løst #1781 Vil også påvirke #1583

mimarz commented 2 months ago

Good suggestion. We'll definitely have a look at this.

To avoid more subject and ongoing refactors, I suggest we have a look at this after we finish issues we have already comited to doing.

Relevant issues on this subject:

Edit: Updated list of finished issues before this as we are able to do more things in parallel now.

unekinn commented 2 months ago

A less radical approach to solve only #2453 and getting rid of useContext would be stuff like this:

.ds-pagination {
  &[data-size='sm'] .ds-button {
    --dsc-button-font-size: var(--ds-font-size-4);
    --dsc-button-gap: var(--ds-sizing-1);
    --dsc-button-padding-block: var(--ds-spacing-2);
    --dsc-button-padding-inline: var(--ds-spacing-3);
  }

  &[data-size='lg'] .ds-button {
    --dsc-button-font-size: var(--ds-font-size-6);
    --dsc-button-gap: var(--ds-sizing-3);
    --dsc-button-padding-block: var(--ds-spacing-3);
    --dsc-button-padding-inline: var(--ds-spacing-5);
  }
}

Which would still make this work

<nav class="ds-pagination" data-size="sm"> <-- data-size er satt én gang wee
  <ol>
    <li><button type="button">1</button></li>
    <li><button type="button">2</button></li>
    <li><button type="button">3</button></li>
    <li><button type="button">4</button></li>
    <li><button type="button">5</button></li>
    <li><button type="button">6</button></li>
  </ol>
</nav>

As for scaling sizes based on font-size, this warrants further consideration:

Also, I can't seem to get your example to work. I tried setting it up in a codesandbox but the relative sizing variables don't actually do anything – see the missing padding. image

eirikbacker commented 2 months ago

@unekinn The approach of

.ds-pagination {
  &[data-size='sm'] .ds-button {
    --dsc-button-font-size: var(--ds-font-size-4);
    --dsc-button-gap: var(--ds-sizing-1);
    --dsc-button-padding-block: var(--ds-spacing-2);
    --dsc-button-padding-inline: var(--ds-spacing-3);
  }
}

Might be a direction, but I'm concerned of:

Sorry - some errors in initially posted pseudo-code 😇 Here is a corrected working example: https://codepen.io/eirikbacker/pen/RwXNpXo

As we only multiply by whole numbers, there is no chance of half-pixels ❤️ (unless changing the root font-size to something like 16.5px but that is indeed forcing a wave of half-pixel-problems anyway ☺️ )

eirikbacker commented 1 month ago

Status: Lasse is experimenting with this setup as "modes" in Figma

eirikbacker commented 1 month ago

Oppdatert matematisk formel, som tilpasser skalaen basert på font-størrelse, og setter en minimum skala: Se demo

:root {
  /* The config */
  --ds-sizing-scale-base: var(--ds-font-size-5); /* 18px */
  --ds-sizing-scale-min: 0.125rem; /* Minimum 2px steps */
  --ds-sizing-scale: 0.25rem; /* Default 4px steps */
  --ds-sizing-adjust: calc((var(--ds-sizing-scale-base) - 1em) * .5); /* Fallback if not supporting round() */
  --ds-sizing-adjust: round(up, calc((var(--ds-sizing-scale-base) - 1em) * .5), 0.0625rem); /* stylelint-disable-line declaration-block-no-duplicate-custom-properties */

  /* The scale */
  --ds-sizing-scale-1: max(calc((var(--ds-sizing-scale) - var(--ds-sizing-adjust)) * 1 + var(--ds-sizing-adjust)), calc(var(--ds-sizing-scale-min) * 1));
  --ds-sizing-scale-2: max(calc((var(--ds-sizing-scale) - var(--ds-sizing-adjust)) * 2 + var(--ds-sizing-adjust)), calc(var(--ds-sizing-scale-min) * 2));
  --ds-sizing-scale-3: max(calc((var(--ds-sizing-scale) - var(--ds-sizing-adjust)) * 3 + var(--ds-sizing-adjust)), calc(var(--ds-sizing-scale-min) * 3));
  --ds-sizing-scale-4: max(calc((var(--ds-sizing-scale) - var(--ds-sizing-adjust)) * 4 + var(--ds-sizing-adjust)), calc(var(--ds-sizing-scale-min) * 4));
  --ds-sizing-scale-5: max(calc((var(--ds-sizing-scale) - var(--ds-sizing-adjust)) * 5 + var(--ds-sizing-adjust)), calc(var(--ds-sizing-scale-min) * 5));
  --ds-sizing-scale-6: max(calc((var(--ds-sizing-scale) - var(--ds-sizing-adjust)) * 6 + var(--ds-sizing-adjust)), calc(var(--ds-sizing-scale-min) * 6));
  --ds-sizing-scale-7: max(calc((var(--ds-sizing-scale) - var(--ds-sizing-adjust)) * 7 + var(--ds-sizing-adjust)), calc(var(--ds-sizing-scale-min) * 7));
  --ds-sizing-scale-8: max(calc((var(--ds-sizing-scale) - var(--ds-sizing-adjust)) * 8 + var(--ds-sizing-adjust)), calc(var(--ds-sizing-scale-min) * 8));
  --ds-sizing-scale-9: max(calc((var(--ds-sizing-scale) - var(--ds-sizing-adjust)) * 9 + var(--ds-sizing-adjust)), calc(var(--ds-sizing-scale-min) * 9));
  --ds-sizing-scale-10: max(calc((var(--ds-sizing-scale) - var(--ds-sizing-adjust)) * 10 + var(--ds-sizing-adjust)), calc(var(--ds-sizing-scale-min) * 10));
}
eirikbacker commented 1 month ago

Forenklet:

skala: 4px
minimum: 2px
fontStørrelseStart: 18px;

justering: (fontStørrelseStart - fontStørrelseNå) * .5;
skala-1: (skala - justering) * 1 + justering

==========================================================================================

så f.eks med tall, dersom fontStørrelseNå = 20px:

justering: (18px - 20px) * .5 = 1px;
skala-1: (4px - 1px) * 1 + 1px;
mrosvik commented 1 month ago

Next step: Should be tested in Figma. Create some sketches/ user interfaces with the suggested scale.