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

Proposal: adding backwards compatible support for full color theming via css variables #4029

Open
lottamus opened this issue Mar 26, 2020 · 3 comments

Comments

@lottamus
Copy link
Contributor

lottamus commented Mar 26, 2020

TLDR: If we make sure all color variable usage in Blueprint is wrapped in rgba($var), we become css variable compatible, which allows for custom color theming at runtime instead of compile time. This involves no breaking changes to Blueprint.

Goal


Within our application, we want to allow users to provide their own theme similar to Slack or VSCode. In order to accomplish this, we need to be able to dynamically update the theme colors used by Blueprint's components.

CSS variables support this concept and are very similar to SCSS variables except that they are replaced at runtime rather than during compilation. https://css-tricks.com/difference-between-types-of-css-variables/

Issue


Blueprint uses SCSS's rgba function to lighten/darken colors for different states such as disabled or hovering. This works great if the colors are valid CSS such as hex codes, rgba, or hsl.

If the SCSS variables are set to a special function, such as the CSS variable syntax var(--color-primary), SCSS's rgba function compiles to the CSS rgba function.

https://sass-lang.com/documentation/modules#rgb
image

However, unfortunately the CSS rgba function does not support hex, rgba, or hsl. It requires that you pass in 4 parameters (red, green, blue, alpha/opacity).

https://developer.mozilla.org/en-US/docs/Web/CSS/color_value
image

Example


Imagine we have the following CSS variable in our App.

:root {
  --pt-intent-primary: #1d7ebb;
}


We set our Blueprint SCSS variables to use the CSS variables.

$pt-intent-primary: var(--pt-intent-primary);


Then imagine somewhere within Blueprint's SCSS, those variables are transformed using rgba.

.#{$ns}-button.#{$ns}-intent-primary {
  background-color: $pt-intent-primary;
  
  &:hover: {
    background-color: rgba($pt-intent-primary, 0.2);
  }
}


The SCSS is compiled to the following CSS:

.bp3-button.bp3-intent-primary   {
  background-color: var(--pt-intent-primary);
}
.bp3-button.bp3-intent-primary:hover {
  background-color: rgba(var(--pt-intent-primary), 0.2);
}


But when the browser replaces the CSS variables with the hex code, it results in invalid CSS.

.bp3-button.bp3-intent-primary   {
  background-color: #1d7ebb; // This is valid
}

.bp3-button.bp3-intent-primary:hover {
  background-color: rgba(#1d7ebb, 0.2); // This is invalid
}

Proposed Solution


In order to get around the issue described above, we can set our CSS variables to the rgb values for the given hex code.

:root {
  --pt-intent-primary: 29, 126, 187;
}


But the example above still results in invalid CSS in the browser for some portions of the blueprint scss. This is because blueprint does not consistently use rgba when accessing colors.

.bp3-button.bp3-intent-primary   {
  background-color: 29, 126, 187; // This is invalid, and how it replaces in spots where a color variable is accessed if it is not wrapped in rgba
}

.bp3-button.bp3-intent-primary:hover {
  background-color: rgba(29, 126, 187, 0.2); // This is valid
}


There is a relatively easy and NON-BREAKING change we can make to Blueprint to support css variables, and thus fully customizable themeing.

I propose updating Blueprint's usage of color variables to consistently use rgba across the board.

.#{$ns}-button.#{$ns}-intent-primary {
// anything that does not use rgba is replaced to use rgba with a 1 opacity
- background-color: $pt-intent-primary;
+ background-color: rgba($pt-intent-primary, 1);
  
  &:hover: {
    // anything that already uses rgba remains unchanged
    background-color: rgba($pt-intent-primary, 0.2);
  }
}


This solution does not require any changes to existing (or future) projects using Blueprint's SCSS variables, because the compiled CSS will result in the same output in the browser.

Additional Context


I've tested this solution out on a small scale and the idea originated after reading the following article: https://www.techhive.io/our-insights/how-to-use-css-variables-with-sass-mixins

Is there anything within the Blueprint codebase that this might not work for or something I'm missing?

I'm already planning to fork Blueprint to get this working in our application. Would you be open to accepting a PR with these proposed changes?

@capacman
Copy link

capacman commented Apr 9, 2020

+1

@maticrivo
Copy link

@lottamus this proposal seems great, did you happen to do it eventually on your own fork? if so, i would like to take a look.
thanks

@adidahiya
Copy link
Contributor

@lottamus sorry for the delayed feedback. I would definitely review a PR with your proposed changes, it sounds promising.

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

No branches or pull requests

4 participants