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

Dark theme experiment, design token thoughts, and theming improvements #381

Closed
claviska opened this issue Mar 21, 2021 · 19 comments
Closed
Assignees
Labels
themes Anything to do with the theming.

Comments

@claviska
Copy link
Member

claviska commented Mar 21, 2021

We already have a dark theme but, based on user feedback, I'd like to experiment a bit more before calling it stable.

Currently, the dark theme uses the same color tokens as the base (light) theme. The idea was that --sl-color-gray-100 would always be light and --sl-color-gray-900 would always be dark. In other words, the color scale never changes.

The problem with this approach is that themes require more than just token changes. Take a look at the current dark theme: https://github.com/shoelace-style/shoelace/blob/next/src/styles/dark.scss

There are many component-specific selectors that become harder to manage as components evolve and new ones are added. Furthermore, third-party components that use the design tokens have to be styled independently.

This experiment will change the context of the color scale for dark themes, effectively reversing the lightness of each color so dark themes can be crafted solely from design token changes. This is a lot like inverting the light theme, but color tokens will be tweaked for better aesthetics.

TL;DR – The goal of this experiment is to produce a dark theme that only modifies color tokens while enabling the dark theme to apply to all components, including those made by third-parties that utilize Shoelace's design tokens.

I also want to use this experiment as a vehicle for exploring design token improvements (see #423) and other general theming improvements (#437, #438).

@claviska claviska added the themes Anything to do with the theming. label Mar 21, 2021
@claviska claviska added this to the v2.0.0 release milestone Mar 21, 2021
@claviska claviska self-assigned this Mar 21, 2021
@claviska
Copy link
Member Author

claviska commented Apr 2, 2021

Another important thing to call out with the current dark theme approach is that it uses a number of light DOM styles. This is problematic for users who nest themed components inside of their own shadow roots (see #390).

This won't be an issue if we can make theming depend solely on design tokens. I think this is the approach @mcjazzyfunky was suggesting early on and would like to acknowledge that. 😄

@mcjazzyfunky
Copy link

mcjazzyfunky commented Apr 8, 2021

Just a few comments as I have noodled around a little with alternative dark themes. Just in case that your experiment will be successful, the following three minor changes might be useful:

  • renaming --sl-color-black to --sl-color-front (or whatever, but should be a semantic name)

  • renaming --sl-color-white to --sl-color-back (or whatever, but should be a semantic name)

  • [Edit]: Renaming --sl-color-gray to --sl-color-neutral would also be nice (=> semantic name)

  • currently, default buttons and dropdowns use a grayish text color, for example

        .button.button--default {
          color: var(--sl-color-gray-600);
        }

    this is not optimal regarding light vs dark themes or regarding providing proper accessible color contrasts.
    Maybe a new token similar to --sl-primary-text could be useful [Edit - changed my mind a bit] (I personally would just use --sl-color-black, or whatever it will be called then ... I personally (and I guess most others with bad eyes) do not like grayish text colors at all).

@mcjazzyfunky
Copy link

mcjazzyfunky commented Apr 9, 2021

To visualize some of the ideas behind this experiment, please find below a desktop-first-and-only protoype of a shoelace theme designer (=> "prototype" as in "don't expect anything to work" 😉).
This theme designer is inspired by an earlier work by @frederik-jatzkowski, thanks for that Frederik). In that theme designer you'll find a button invert theme which has only the purpose to visualize one of the base ideas behind this "dark theme experiment" (this button will be removed later).
Very important: In the select box "Base theme" you'll find two non-optimized auto-generated dark themes, which are of course only placeholders as long as there are no other compatible dark themes available (they are just the result of modifying the shoelace light theme a bit with the theme designer). Also the "Light (level AA)" theme is just a fake/placeholder.
[Edit]: Later, two other base themes called "Experimental" and "Experimental dark" were added to the theme designer. Just see them as additional examples.

Ideas behind this theme designer:

  • All two (or four, or six ... light/dark + plus maybe some day accessibility level AA + level AAA) base themes will be hand-crafted (none of these "base themes" will be the result of using this theme designer).
  • The output of this theme editor will ALWAYS be a modification of one of the base templates - means the output does not only depend on the color parameters that can be configured in the theme designer itself.

https://shoelace-theme-designer.vercel.app/

Here is for example a bootstrapish Shoelace light theme.

@jaredcwhite
Copy link
Contributor

Wow @mcjazzyfunky, that looks awesome! 👍👍

@claviska
Copy link
Member Author

This is really, really nice. Let's work on #413 (since it will add more core design tokens) and revisit this afterwards.

@mcjazzyfunky is this something you'd be interested in contributing to the project as an official theme generator? I could see something like it being hosted at themes.shoelace.style or maybe even as a special page in the docs.

@mcjazzyfunky
Copy link

[...] is this something you'd be interested in contributing to the project as an official theme generator?

@claviska
Sure, but please be aware that - like I've already said - it's just a prototype yet. The current feature set is okay, I guess (except for not showing all components yet), but under the hood there's still a lot to do (especially I've to switch to a common UI library - like Preact or whatever ... currently I am using an experimental UI lib, which has to be replaced) ... anyway, when #413 will be done and you'll find some time, we can discuss more.

@claviska
Copy link
Member Author

Absolutely. I have ideas to expand on it — just feeling out whether you'd be open to sharing it with the community. 🙌

@UserGalileo
Copy link

+1 for using just the Design Tokens instead of parts, parts are great for specific overrides but other than that they seem limiting :)

+1 also for the Theme Generator, which could also be very useful in order to test how flexible Shoelace is in terms of "adapting to a style" or design system, if this is something that matters for the scope of this project of course. Given how flexible and agnostic WCs are, I believe having the ability to use the same components in multiple projects which adopt different Design Systems [by tweaking them in order to resemble the rest of the projects' styles] would be great!

@claviska claviska changed the title Dark theme experiment Dark theme experiment (and design token and theming improvements) May 10, 2021
@claviska claviska changed the title Dark theme experiment (and design token and theming improvements) Dark theme experiment, design token thoughts, and theming improvements May 10, 2021
@claviska
Copy link
Member Author

+1 for using just the Design Tokens instead of parts, parts are great for specific overrides but other than that they seem limiting :)

From my comment here:

We need to be careful not to get crazy, though, as we can quickly end up in variable hell.

I feel pretty strongly about not being able to customize individual components with design tokens. Those are best suited for high-level changes that components can share, but most component-specific customizations should be done with parts. (There's more explanation about this in the comment I linked above.)

@UserGalileo
Copy link

UserGalileo commented May 12, 2021

Yeah I see your point, the Bootstrap example you made was pretty clear. Also I've been looking at other WC kits these days (eg. Ionic) and it seems that most of them indeed offer a decent amount of customization via CSS Variables, but not for everything. Because obviously there'd be the need to just create an infinite amount of variables to support any kind of customization, and you'd never be fully satisfied I guess.

Parts seem indeed the optimal solution for customizing in detail, it's a pity Constructable Stylesheets are not yet adopted by all browsers.

Actually this "issue" made me think about how I'm structuring my apps (since I'd like to build entire apps with a tool like Lit) and I'm thinking about not using Shadow DOM for my own components (unless they're leaf nodes, or part of an UI Kit)! Let's see where it goes :) Thanks!

@jaredcwhite
Copy link
Contributor

@UserGalileo I think it's pretty reasonable to build app-level components without Shadow DOM since you know the general lay of the land in terms of styling and markup structure — with the escape hatch that you can always switch it on if you need a more reusable/encapsulation behavior.

@UserGalileo
Copy link

@jaredcwhite Yep honestly I'm not particularly concerned about styles but more about losing Slots and the fact that I once saw the argument made by Lit's creator that removing it would not be a best practice. But I think it's fair to say that you can remove it when talking about app-level components, and although it's not the same thing I'll experiment using "render props" instead of slots!

@mcjazzyfunky
Copy link

mcjazzyfunky commented Jul 9, 2021

Here's an example that shows why this "dark theme experiment" is so important.

We surely all agree that @hanc2006 's new date picker is looking awesome - here's how it looks in light theme:

This is how it currently looks with dark theme (the implementation of the date picker has not been finished, the necessary dark theme adjustments have not been implemented yet):

And this is how it would look - out of the box, without any special customizations - if this "dark theme experiment" was a success (be aware that the automatically generated dark theme used in the following screenshots is not optimized) [Edit: In case this might be confusing: The images use a background color of #222, this is not part of the theme]:

@mcjazzyfunky
Copy link

mcjazzyfunky commented Jul 9, 2021

@claviska If this "dark theme experiment" turns out to be a success, it may be useful to introduce a new custom CSS property --sl-theme-mode, which is either 0 for light themes and 1 for dark themes.
This would allow a bit of fine-tuning in some cases.
There might be some alternatives to achieve the same aim, so maybe to be discussed somewhere in future.

Example
        /* Hack to switch between background colors depending on theme mode */ 
        background: linear-gradient(
          var(--sl-color-primary-400) calc(100% * (1 - var(--sl-theme-mode))),
          var(--sl-color-primary-600) calc(100% * (1 - var(--sl-theme-mode))),
          var(--sl-color-primary-600) calc(100% * var(--sl-theme-mode)) 
        );
  

@claviska claviska pinned this issue Jul 11, 2021
@claviska
Copy link
Member Author

claviska commented Aug 10, 2021

Here are the upcoming changes to theming scraped from the upcoming changelog:

This release improves theming by offering both light and dark themes that can be used autonomously. It also adds a variety of new color primitives and changes the way color tokens are consumed. Previously, color tokens were in hexidecimal format. Now, Shoelace now uses an R G B format that requires you to use the rgb() function in your CSS.

.example {
  /* rgb() is required now */
  color: rgb(var(--sl-color-neutral-500));
}

This is more verbose than previous versions, but it has the advantage of letting you set the alpha channel of any color token.

.example-with-alpha {
  /* easily adjust opacity for any color token */
  color: rgb(var(--sl-color-neutral-500) / 50%);
}

This change applies to all design tokens that implement a color.

  • 🚨 BREAKING: all design tokens that implement colors have been converted to R G B and must be used with the rgb() function
  • 🚨 BREAKING: removed --sl-color-black|white color tokens (use --sl-color-neutral-0|1000 instead)
  • 🚨 BREAKING: removed --sl-color-primary|success|warning|info|danger-text design tokens (use theme or primitive colors instead)
  • 🚨 BREAKING: removed info variant from sl-alert, sl-badge, sl-button, and sl-tag (use neutral instead)
  • 🚨 BREAKING: removed --sl-color-info-* design token (use --sl-color-neutral-* instead)
  • 🚨 BREAKING: renamed dist/themes/base.css to dist/themes/light.css
  • 🚨 BREAKING: removed --sl-focus-ring-color-primary tokens (use color tokens and --sl-focus-ring-width|alpha instead)
  • Added new color primitives to the base set of design tokens
  • Added --sl-color-*-950 swatches to all color palettes
  • Exposed base and dark stylesheets so they can be imported via JavaScript #438
  • Reworked the dark theme to use an inverted token approach instead of light DOM selectors

Some reiterations and afterthoughts:

The "base" theme is now the "light" theme, and the light theme and dark theme can be consumed independently now (previously you had to load the base theme no matter what). Stylesheets are provided both as raw CSS and as importable Lit's CSSResult modules.

The new "inverted" dark mode is pretty slick. If you adhere to the color scale throughout your app, you get a reasonably nice dark theme for your entire app for free — including future components.

I expect that the rgb() requirement for color tokens will throw some people off, but the ability to tweak alpha is necessary and, IMO, worth the initial confusion.

The additional color primitives might seem unnecessary, but they help maintain consistent color usage when you need to stray from semantic palettes. They also make it easier to adapt your theme by overriding --sl-color-primary-* with --sl-color-<name>-* values.

You'll notice a new CodePen link attached to each code example. When you click on it in the preview link, the stylesheet will 404 because it's looking for light.css which hasn't been published yet. This will be fixed when the next version is published.

I realize the next release will include more breaking changes. I apologize for that, but I'm confident things are heading in the right direction now in terms of theming. I appreciate your continued patience as I work towards the 2.0.0 stable release!

These changes will be available in the 2.0.0-beta.48 release and can be previewed here.

@claviska claviska unpinned this issue Aug 10, 2021
@mcjazzyfunky
Copy link

@claviska Great. Theming is much more flexible now. Thanks.
But I think it's not a good idea to drop the following tokens:
--sl-color-primary-text
--sl-color-success-text
--sl-color-info-text
--sl-color-warning-text
--sl-color-danger-text

and use --sl-color-neutral-1000 instead.

With the new version it is almost impossible to create a good-looking contrast-rich theme as you cannot flexibly customize the text color for the buttons and badges.
Would it be possible to reintroduce those tokens?

@claviska
Copy link
Member Author

These were temporarily removed. Additional design tokens are being added back before this goes out, and something to account for these will be available.

@carlos-verdes
Copy link

Is there a plan to add color variables for buttons @claviska

I'm doing a plugin to get the the variables from Figma where the variables are always design this way:

  • first layer are primitive variables (on this case color palette) and Shoelace follows this with variables like --sl-color-red-50, 100, etc
  • second layer is semantic and always makes reference to to previous layer, I also see Shoelace follows --sl-color-primary-50: var(--sl-color-sky-50);
  • third layer is components and they should make reference to previous layer (using variables)

Here is where Shoelace "breaks the contract" with buttons and colors for example:

  .button--standard.button--primary {
    background-color: var(--sl-color-primary-600);
    border-color: var(--sl-color-primary-600);
    color: var(--sl-color-neutral-0);
  }

This CSS doesn't allow a designer in Figma to change the primary button color from --sl-color-primary-600 to --sl-color-primary-400 for example and it's a big limitation.

I know you are worried about variable hell but I think to add more variable will just provide flexibility when needed and current users can just ignore them without breaking their current design.

We need to add variables like

--sl-button-color-primary: var(--sl-color-primary-600);
...

@claviska
Copy link
Member Author

claviska commented Oct 7, 2024

@carlos-verdes you're really going to love the work that @lindsaym-fa has done for Web Awesome ("Shoelace 3") 😆

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
themes Anything to do with the theming.
Projects
None yet
Development

No branches or pull requests

5 participants