style-dictionary
style-dictionary copied to clipboard
How would I use style-dictionary with a "platform-scale"
I'm a big fan of Adobes Design System in which they talk about "platform scales". Simply put, they have split their spacing, dimension etc. design tokens into two scales. Desktop and Mobile (for Web). More about that here: https://spectrum.adobe.com/page/platform-scale/
I really like this style and would love to do the same thing with style-dictionary. Would this be possible currently and if so, how?
When taking a look at this picture from style-dictionaries website:
I would say that this platform-scale would actually be a new "type", right between category
and type
here on the picture. So I'm not sure how I would tackle this currently with style-dictionary. Hope that makes sense!
Sorry for the slow response here - we were busy pushing 3.0 out the door. @dbanksdesign did you have thoughts on this? It is sensible and doable in our current form, but messes with the "nice" CTI features we include...
My bad! Having different scales for mobile and desktop, or really having just different values for any platform is possible. The best way to accomplish that is to follow the multi-brand-multi-platform example. At a high level what this is doing is running Style Dictionary multiple times with slightly different configurations where you swap out different token files based on the platform. Let me know if that makes sense!
@mrtnbroder Did the response help? Do you have more questions?
Another thought that just came up was you could also use basePxFontSize
on the platform configuration as a way to have different scales for different platforms. It is a bit blunt of a solution, but could work as well.
I wonder if an example or guide would be beneficial to target "platform-scale". I am just starting to think about this topic and for my use case we have approached the problem in the following:
- Design responsive web (e.g. 1x)
- Fast follow, Design scaled experience for quick, on the move (e.g. 2x)
- Future, Design scaled experience for constrained, dark environments (e.g. 3x)
Currently, I have a spacing scale that assumes 16px is the default and transform values into rem
:
$size-space-50: 0.25rem; // 4px
$size-space-100: 0.5rem; // 8px
$size-space-200: 1rem; // 16px
// other stuffs
For web, updating the html { font-size: 24px }
will increase the experience from 16px
to 24px
, thereby scaling the experience by 1.5
, but I don't think this can scaled to other platforms…?
basePxToFontSize
basePxFontSize
isn't documented per https://github.com/amzn/style-dictionary/issues/663 and https://github.com/amzn/style-dictionary/pull/491 doesn't provide enough context on original intent or how this may scale out to other platforms via https://github.com/amzn/style-dictionary/issues/577#issuecomment-876007006.
I assume basePxFontSize
is just a safety net for converting pxToRem
? And then brought over to other transforms? But, might not make sense in terms of scaling the experience (I don't have experience with native or react native scaling so its difficult for me to understand if this is a scaling solution)? It seems beneficial if an application has a different base font size than 16, but not sure if it will scale to other use cases.
Given the comment above, basePxFontSize: 12.8
will scale the system up by 25% if we assume that the default font size will stay at 16px
. The math works well for this increase, not so much for many other values. Unless I am missing something, this option doesn't seem scalable.
Separate, but related, I am not sure how https://amzn.github.io/style-dictionary/#/transforms?id=sizeobject is useful for react native so I don't know how basePxFontSize
is used or if it fits "platform-scale".
multi-brand multi-platform
Assumes that https://github.com/amzn/style-dictionary/issues/577#issuecomment-848315939 means following the same structure as brands/brand/color.json
I have found this example to work well with color, but not with space. Spacing values, "can" be treated the same, but it is much more difficult to create semantic values for space (similar to https://css-tricks.com/the-dilemma-of-naming-font-size-variables/) and more often than not, there are one-offs. These one-offs won't be able to be captured by "global" tokens and will otherwise require a ton of files to be overridden for them to be scaled correctly.
These values include, border
, box-shadow
, height
, line-height
, padding
, margin
, width
, etc.
custom transform
Perhaps it is better for a custom transform to blindly scale all size values?
module.exports = {
matcher: (token) => typeof token.value === "string" && token.value.indexOf("px") !== -1,
transformer: (token, option) => {
// leverage multi-brand multi-platform build file to pass in `option.scale`
token.value = token.value * option.scale;
return styleDictionary.transform["size/pxToRem"].transformer(token, options);
},
};
Question
I am in the middle of exploring the following and any other options I stumble upon along the way. Does this make sense or am I missing something that has already been thought through?
@dbanksdesign thoughts on a direction or contribution that would provide benefit?
Apologies for the delay...
basePxFontSize
is used in any transform that is remTo*
, for example size/remToPt
or size/remToDp
. This allows you to scale font and padding sizes for native platforms. Originally, these transforms just assumed a multiplier of 16, where a font or padding of 1rem is roughly equivalent to 16 pt/dp/sp on native platforms. Using basePxFontSize
you could scale up or down all your font size and padding values by a uniform amount. So if you wanted your sizes on Android and iOS to be little bit smaller, you could set it to 14, or a little bit bigger and set it to 18. It is a 'blunt' tool because it will affect all font and padding tokens for that platform configuration, which might not always be the right solution.
Your example is basically doing what the transformer is already doing, but just with a different matcher function and name for where the multiplier is store (scale
v. basePxFontSize
). https://github.com/amzn/style-dictionary/blob/ad7f6ea555ec77defd264c9ade9628aefd108959/lib/common/transforms.js#L837-L854
You could write it like this (if you changed scale to basePxFontSize in your config):
module.exports = {
matcher: (token) => typeof token.value === "string" && token.value.indexOf("px") !== -1,
transformer: styleDictionary.transform["size/pxToRem"].transformer
};
In one of those PRs where we added basePxFontSize we had talked about adding a more generic transform that would work on any size rather than forcing all values to be rem or px units. I think that might be something you are looking for? A transform that would be size/rem
and if it detects a value with 'px' it will divide the value by the scale or basePxFontSize and if it detects a rem value it will pass it through. I think that would be a good contribution if you'd like to try it.
Thanks for the reply.
I totally miss understood the purpose of size/pxToRem
. Since remTo
and pxTo
were using basePxFontSize
, I incorrectly assumed they would work together somehow—they obviously don't since tokens need to be constructed differently. I still don't understand the purpose of basePxFontSize
in size/pxToRem
, but :shrug:.
In my use case I want to define all values by px (easier to author), scale all values up 25%, then transform into platform. So yea, I think I am looking for the generic transform. Whoops.