design-tokens / community-group

This is the official DTCG repository for the design tokens specification.
https://tr.designtokens.org
Other
1.53k stars 62 forks source link

How to deal with "fluid" dimensions #188

Open acstll opened 1 year ago

acstll commented 1 year ago

While working on responsiveness and the fluid typography topic we found ourselves wondering whether we should put clamp(0.64rem, 0.69rem + -0.27vw, 0.5rem) in a design token. (We would use this for font sizes, but these can be used for spacing as well.)

According to the current spec, the dimension type is a string ending with either px or rem.

How should we handle this? Has this already been discussed somewhere else?

Many questions arise:

I would imagine something like this:

{
  "fluid-dimension-token": {
    "$type": "clamp", // or fluid-dimension?
    "$value": {
      "min": "32px",
      "max": "48px",
      "preferred": "4vw",
      "fallback": "40px"
    }
  }
}
PavelLaptev commented 1 year ago

Hm… @acstll clamp is a CSS function, you can do many things with it, and "fluid typography" here is a trick. I don't think there should be any declared types for tricks unless we have an official solution. Also it's very specific and work for web only.

Because you use this approach on web, why don't you create a @mixin for this or a CSS variables and store it in the web lib. Then you can take design tokens and your mixins and create a file typography.css where you will sore CSS classes like header1, header2 etc. with included mixins, media-queries etc.

image

In my opinion it better to isolate CSS logic inside the web UI lib. If you need it in other projects, then just import it.

But if you need to make it as a composite design token, I think "groups" it's what fits better here.

mikemai2awesome commented 1 year ago

I 100% agree that there needs to be min and max values for fluid typography and spacing.

{
  "fluid-dimension-token": {
    "$type": "fluid",
    "$value": {
      "min": "32px",
      "max": "48px"
    }
  }
}

How each platform uses this data is up to the coder (eg. whether using clamp or media queries in CSS). min can work as the fallback for static design tools that don't allow fluid typography and spacing.

PavelLaptev commented 1 year ago

@mikemai2awesome agreed that here could be minmax type, but fluid term doesn't fit here. And might be it shouldn't be attached to typography only.

There is another question — how to handle if values more than 2 if we're talking about typography. Many designers prefer to use a specific font-size for tablets. So, there will be at least desktop, tablet and mobile.

I would rather think about breakpoints token in this case 🤔

{
  "heading-level-1": {
    "$type": "typography",
    "$value": {
      "fontFamily": "Roboto",
      "fontSize": "42px",
      "fontWeight": "700",
      "letterSpacing": "0.1px",
      "lineHeight": "1.2"
    },
    "$extensions": {
      "type": "breakpoints",
      "values": {
        "mobile": {
          "fontSize": "32px",
          "lineHeight": "1.1"
        },
        "tablet": {
          "fontSize": "32px",
          "lineHeight": "1.2"
        },
        "desktop": {
          "fontSize": "42px",
          "lineHeight": "1.2"
        }
      }
    }
  }
}
mikemai2awesome commented 1 year ago

@PavelLaptev But that is not fluid design, that's imaginary breakpoint design as a result of the static design tool. There is no such thing as mobile, tablet, and desktop, as the app/website viewport is adjustable across all devices nowadays. Something as opinionated as breakpoints should not be in the spec.

I can agree that the term fluid might not be best to describe the type, neither is clamp. That can be workshopped a bit more. However, I don't agree this is typography only. Spacing can be fluid, too.

PavelLaptev commented 1 year ago

@PavelLaptev But that is not fluid design, that's imaginary breakpoint design as a result of the static design tool. There is no such thing as mobile, tablet, and desktop, as the app/website viewport is adjustable across all devices nowadays.

Yes, but still even if someone design a website in browser he's creating these average imaginary mobile, tablet and desktop breakpoints, because design for desktops wouldn't work on mobiles — different space, different layouts.

ilikescience commented 1 year ago

Like @PavelLaptev suggested, it's worth asking: should this be the job of the token parser (and by extension the concern of the token format), or should it be the responsibility of the platform rendering the UI?

Put another way: what if we had tokens like:

{
    "type-size-large-fluid-min": {
        "$type": "dimension",
        "$value": "32px",
    },
    "type-size-large-fluid-max": {
        "$type": "dimension",
        "$value": "48px",
    },
    "type-size-large-fluid-preferred": {
        "$type": "dimension",
        "$value": "4vw",
    },
    "type-size-large-fixed": {
        "$type": "dimension",
        "$value": "40px",
    },
}

I could then write the css (assuming my tokens were compiled into custom properties):

h1 {
    font-size: var(--type-size-large-fixed);
    font-size: clamp(
        var(--type-size-large-fluid-min),
        var(--type-size-large-fluid-preferred),
        var(--type-size-large-fluid-max)
    );
}

This saves us from having to write logic into our token parser to understand and decide what the equivalent of clamp() is in each target context.

TravisSpomer commented 1 year ago

100% agreed with @PavelLaptev and @ilikescience here—it doesn't make a lot of sense to me for this to be part of the design tokens spec. It's a "trick" that some web designers use that doesn't really have an analog in design tools or other non-CSS platforms. I think that specifying those values as a set of tokens like in the previous comment makes the most sense.

Since font sizes must be in px or rem, that would require alternative units like CSS's vw to be specified as an $extension.

{
    "type-size-large-fluid-preferred": {
        "$type": "dimension",
        "$value": "40px",
        "$extensions": {
            "use-this-instead-if-in-css": "4vw"
        }
    },
}
mikemai2awesome commented 1 year ago

What @ilikescience wrote above is too specific to CSS, I am suggesting just the essential min and max values:

{
    "type-size-large-fluid-min": {
        "$type": "dimension",
        "$value": "2rem",
    },
    "type-size-large-fluid-max": {
        "$type": "dimension",
        "$value": "4rem",
    },
}

Web devs decide what they want to do with those min and max tokens:

h1 {
    font-size: clamp(
        var(--type-size-large-fluid-min),
        var(--type-size-large-fluid-min) * 0.9 + 0.25vw, /* This formula would be situational and completely up to the author. */
        var(--type-size-large-fluid-max)
    );
}

The formula is the trick part, the concept of min and max is not a trick, and eventually iOS and Android would come up with their own fluid method (with their split screen and overlay features becoming more mainstream). The min and max would be applicable on all platforms by then.

Yes, but still even if someone design a website in browser he's creating these average imaginary mobile, tablet and desktop breakpoints, because design for desktops wouldn't work on mobiles — different space, different layouts.

@PavelLaptev I beg to differ on this. Fluid design would produce different layouts just as breakpoint design can, but fluid would account for every viewport, not just specific breakpoints. Someone designing in the browser nowadays has the technologies to do so, modern CSS is very powerful. By removing hundreds of lines of breakpoint media queries, a website would have much greater performance.

PavelLaptev commented 1 year ago

@mikemai2awesome I think that you don't need media-queries or container-queries only if you have a simple website or components, I mean a website where you need to hide a menu if there is not enough space and show a burger icon, or if you have three columns layout then you need to use media-queries so switch e.g. flex-direction: row to flex-deriction: column-reverse etc. don't see how relative aka "fluid" units can handle that

mikemai2awesome commented 1 year ago

@PavelLaptev Your column example is one of the biggest downfalls of breakpoint design. 3 column layout at 1280px viewport looks fine while 3 column layout at 801px viewport looks super awkward. Content is squeezed so much that it becomes hard to read. It is just missing that 1px to shift to a different and better layout. Why utilize such static design approach when the web allows you to be much more dynamic now? A row of content blocks can flow vertically once a block hits a certain width like 25 characters, no media query or container query required. That's 1 line of code vs multiple lines of media queries.

I agree there are certain complex layouts that would require some tricks involving breakpoints still, but breakpoints shouldn't be a core design principle. And this is irrelevant to the fluid typography and spacing tokens we are discussing here, so let's agree to disagree and get back on the main topic.

kevinmpowell commented 1 year ago

@acstll any other thoughts or comments based on the feedback provided on this issue?

tbrasington commented 1 year ago

This dimension token is just what I needed. For context I have been working on utils to generate clamped scales in css and their equivalent px values for a given dartboard size in Figma.

I have been setting a config like this

{
  "config": {
    "range": [-2, -1, 0, 1, 2, 3, 4],
    "sizes": [
      {
        "$name": "BP1",
        "width": 320,
        "fontSize": 16,
        "typeScale": 1.067
      },
      {
        "$name": "BP2",
        "width": 768,
        "fontSize": 16,
        "typeScale": 1.067
      },
      {
        "$name": "BP4",
        "width": 1440,
        "fontSize": 20,
        "typeScale": 1.067
      }
    ]
  },

then referencing it as this, which isn't ideal as fontScale isn't an obvious token.

"Heading 1": {
      "$type": "typography",
      "$value": {
        "fontFamily": "{font.family.heading}",
        "fontWeight": "{font.weight.heading.normal}",
        "letterSpacing": "0px",
        "lineHeight": "{font.lineHeight.heading}",
        "fontSize": null,
        "fontScale": 4
      }
    },

But I think with the approaches above something like

{
   "typography-scale":{
      "$type":"scale",
      "$value":{
         "min":{
            "width":"320px",
            "base":"16px",
            "ratio":1.067
         },
         "max":{
            "width":"1728px",
            "base":"21px",
            "ratio":1.414
         }
      }
   }
}
"Heading 1": {
      "$type": "typography",
      "$value": {
        "fontFamily": "{font.family.heading}",
        "fontWeight": "{font.weight.heading.normal}",
        "letterSpacing": "0px",
        "lineHeight": "{font.lineHeight.heading}",
        "fontSize": "{{scales.typography-step-4}}",
      }
    },

The parser can then work out if it needs to render a px, rem, clamp or array of sizes.

It would also be good to have an array as an option for rendering multiple styles for different artboard sizes in Figma (useful when testing out lots of layout permutations) or if someone wanted to target media queries, or native platforms.

{
   "typography-scale":{
      "$type":"scale",
      "$value":[
         {
            "width":"320px",
            "base":"16px",
            "ratio":1.067
         },
         {
            "width":"1024px",
            "base":"16px",
            "ratio":1.067
         },
         {
            "width":"1728px",
            "base":"21px",
            "ratio":1.414
         }
      ]
   }
}
acstll commented 1 year ago

@acstll any other thoughts or comments based on the feedback provided on this issue?

super sorry for the late reply.

I'm happy with @mikemai2awesome solution above https://github.com/design-tokens/community-group/issues/188#issuecomment-1335476072

I would also like to point out the "agree to disagree" part as well, which I second a 100%.

I agree there are certain complex layouts that would require some tricks involving breakpoints still, but breakpoints shouldn't be a core design principle. And this is irrelevant to the fluid typography and spacing tokens we are discussing here, so let's agree to disagree and get back on the main topic.

Using CSS's clamp may look like a trick now, but fluid design isn't, and to me it looks like the future.

@kevinmpowell should we close this one then?