npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@chrisburnell/bowhead

v0.3.4

Published

Memorable and maintainable design tokens in SCSS

Downloads

59

Readme

Bowhead

Memorable and maintainable design tokens in SCSS.

What?

Bowhead is a small SCSS framework on which to implement your design tokens, spitting out CSS Variables with optional fallbacks.

Why?

Implementing a design system or even a series of simple design tokens can come with some unpredictable mental overhead. Bowhead aims to reduce that mental overhead by abstracting the specifics of design tokens into human-sensible formats and nomenclature.

This has a positive effect that ranges from giving the colours in your design system fun and memorable names, to the time and effort saved when communicating about these colours with collaborators without getting bogged down by details, because let’s be real: you don’t want or need to memorise the six-character hex value for all your colours, nor does anyone else! Now imagine that scenario when applied to multiple times more design tokens.

Installation

CSS Data Types

CSS data types define typical values (including keywords and units) accepted by CSS properties and functions. https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types

An important first step to using Bowhead is to understand how it categorises CSS properties by the different CSS data types. By and large, this is done by looking at what the expected values for a given property are:

selector {
    background-color: #b22222;
    color: #3cb371;
    outline-color: #d2b48c;

    padding: 0.5rem;
    margin: 2rem;

    display: flex;
    align-items: flex-start;
    justify-content: flex-end;
}

If we take the above snippet as an example, we can quickly identify two types of values present: colors and sizes. Colors typically stand out quite easily, and, historically, developers have done well to assign colors to variables to simplify their use throughout the codebase. Sizes, on the other hand, are rarely seen reflected as design tokens in CSS despite their frequent prescence in other forms of design tokens, e.g. the space around a logo or iconography is usually defined in a brand's guidelines.

Despite being presented in different formats, we can confidently say that background-color, color, and outline-color expect a color-type value, not only because color is in their names, but because we can interchange the values between the properties and they still make sense.

Sizes can take trickier forms to identify and categorise, and I recommend allowing for more sizes than you might expect at first and paring it back later. Getting everything categorised is the hard part; swapping tokens later becomes very trivial off the back of this up-front effort. Regardless, I attach any kind of distance-related value to a size, and, once again, we could interchange any of the values between padding, margin, border-width, or width and the CSS still makes sense.

Extrapolating from here across the vast variety of CSS properties and the data type of the values they expect, you end up with a map of most properties against value types:

With this knowledge under our belt, we can begin to define the design tokens for our particular project by fleshing out what values are available underneath each type:

Usage

$bowhead-variable-as-default: true;

body {
    color: v(color, brick);
}
body {
    color: var(--color-brick);
}
$bowhead-variable-as-default: false;

body {
    color: v(color, brick);
}
body {
    color: #b22222;
}
$bowhead-variable-as-default: true;
$bowhead-show-fallback: true;

body {
    @include v(color, desert);
}
body {
    color: #d2b48c;
    color: var(--color-desert);
}
$bowhead-variable-as-default: true;
$bowhead-show-fallback: false;

body {
    @include v(color, desert);
}
body {
    color: var(--color-desert);
}

When $bowhead-variable-as-default is false, $bowhead-show-fallback has no effect.

$bowhead-variable-as-default: false;
$bowhead-show-fallback: true;

body {
    @include v(color, desert);
}
body {
    color: #d2b48c;
}
$bowhead-variable-as-default: false;
$bowhead-show-fallback: false;

body {
    @include v(color, desert);
}
body {
    color: #d2b48c;
}
$bowhead-generate: true;
:root {
    --size-small: 0.5rem;
    --size-medium: 1rem;
    --size-large: 2rem;
    --color-brick: #b22222;
    --color-plankton: #3cb371;
    --color-desert: #d2b48c;
    --opacity-alpha: 0.8;
    --opacity-beta: 0.5;
    --opacity-gamma: 0.2;
    --z-index-below: -1;
    --z-index-root: 0;
    --z-index-default: 1;
    --z-index-above: 2;
}
$bowhead-generate: false;

Nothing is generated!

$bowhead-property-map is another map that contains mappings from CSS properties (padding-left, border-bottom-right-radius, etc.) to our defined design token types (size, color, etc.), i.e.

$bowhead-property-map: (
    width: size,
    min-width: size,
    max-width: size,
    height: size,
    min-height: size,
    max-height: size,
    ...,
);

If you wish, you can create new mappings or overwrite existing defaults by defining your own property map, e.g.

$bowhead-property-map: (
    vertical-align: alignments,
);

Where alignments would be one of your design token types, e.g.

$bowhead-tokens: (
    alignments: (
        default: baseline,
        alternate: middle,
    ),
    ...,
);

Bowhead will merge new types in your defined map into its own defaults automatically! Any that you re-declare will overwrite what exists as a default from Bowhead.

$bowhead-type-map is a map that allows defining alternate names for the data types, e.g.

$bowhead-type-map: (
    size: measure,
    ...,
);

$bowhead-tokens expects an SCSS map of types of tokens. These types could be a size, color, opacity, z-index, etc.

$bowhead-tokens: (
    size: (
        small: 0.5rem,
        medium: 1rem,
        large: 2rem,
    ),
    color: (
        brick: #b22222,
        plankton: #3cb371,
        desert: #d2b48c,
    ),
    opacity: (
        alpha: 0.8,
        beta: 0.5,
        gamma: 0.2,
    ),
    z-index: (
        below: -1,
        root: 0,
        default: 1,
        above: 2,
    ),
);

Then you’ll have to include Bowhead in your SCSS somehow. You could use Webpack or something like that, or if you’re using npm, the below code snippet should suffice.

Take note that you need to define any of your Bowhead variables ($bowhead-tokens, $bowhead-show-fallback, $bowhead-generate(, $bowhead-property-map)) before importing Bowhead into your SCSS!

$bowhead-tokens: (...);
$bowhead-show-fallback: true;
$bowhead-generate: true;
$bowhead-property-map: (...);

@import "node_modules/@chrisburnell/bowhead/bowhead";

Finally, you can use either Bowhead's @v function, @v mixin, both, or the CSS Variables it can spit out on their own. However you use it is totally up to you! 😄

.thing {
    @include v(background-color, desert);
    @include v(color, brick);
    border: v(size, small) solid v(color, plankton);
    padding: v(size, medium) v(size, large);
    @include v(z-index, above);
    opacity: var(--opacity-alpha);
    // 1. if you only want the raw value, this is not really recommended:
    text-decoration-color: map-get(map-get($bowhead-tokens, "color"), "brick");
    // 2. this does the same for you:
    text-decoration-color: v(color, brick, true);
    // 3. so does this, although it includes the CSS Variable too:
    @include v(text-decoration-color, brick, true);
}

will generate…

.thing {
    background-color: #d2b48c;
    background-color: var(--color-desert);
    color: #b22222;
    color: var(--color-brick);
    border: var(--size-small) solid var(--color-plankton);
    padding: var(--size-medium) var(--size-large);
    z-index: 2;
    z-index: var(--z-index-above);
    opacity: var(--opacity-alpha);
    /* 1 */
    text-decoration-color: #b22222;
    /* 2 */
    text-decoration-color: #b22222;
    /* 3 */
    text-decoration-color: #b22222;
    text-decoration-color: var(--color-brick);
}

Extras

Need a negative value? Use calc():

.thing {
    margin-left: calc(#{v(size, medium)} * -1);
}

Combining values? Same idea:

.thing {
    margin-left: calc(#{v(size, medium)} + #{v(size, small)});
}

What about multiple values in a function? Make sure you're using the raw values from the v() function:

.thing {
    background-color: rgba(v(color, desert, true), v(opacity, alpha, true));
}

Read more

Contributing

Contributions of all kinds are welcome! Please submit an Issue on GitHub or get in touch with me if you’d like to do so.

License

This project is licensed under an MIT license.