Sharing/reusing color values

What is the best practice for storing a palette of colors to be used across a UIElements solution?

I also need access to the colors from C# because I use generateVisualContent where vertices need tints from the palette.

I read that Unity plans to support USS variables, but I can’t find any information on it.

Hi cecarlsen,

I can confirm that USS variables will be available on 2019.3 starting at 2019.3.0a10.

With this you will be able to define your color palette as variables and reuse them across your USS files.

They are compliant with CSS variables so you can refer to this link for more information : Using CSS custom properties (variables) - CSS: Cascading Style Sheets | MDN

To access the variables in C# you need to register to the CustomStyleResolvedEvent which is sent to any elements matching variable definitions. From there you can use the ICustomStyle.TryGetValue interface to retrieve the colors.

Also by registering to the CustomStyleResolvedEvent on your element you can read variables and use them in C#, for example in combination with generateVisualContents.

class MyElement
{

   static CustomStyleProperty<Color> s_MyColor = new CustomStyleProperty("my-color");

   Color m_Color;

   public MyElement()
   {
      RegisterCallback<CustomStyleResolvedEvent>(evt =>
      {
          if (!evt.customStyle.TryGetValue(s_MyColor, out m_Color))
          {
              // assign default color
               m_Color = Color.red
          }
      });
   }
}
2 Likes

Thanks again @antoine-unity It works. I encapsulated USS color palette access in a static class like so because I like to have colors global. I call the method from a callback in EditorWindow.OnEnable after adding the stylesheet to the root element. With the given API I don’t see how to avoid a lot of name repetitions. It’s not pretty and it will get worse as more colors are added.

public static class Colors
{
    public static Color connection;
    public static Color connectionHover;
    public static Color connectionSelected;
    public static Color connectionSelectedHover;

    static CustomStyleProperty<Color> connectionProp = new CustomStyleProperty<Color>( "--connection-color" );
    static CustomStyleProperty<Color> connectionHoverProp = new CustomStyleProperty<Color>( "--connection-hover-color" );
    static CustomStyleProperty<Color> connectionSelectedProp = new CustomStyleProperty<Color>( "--connection-selected-color" );
    static CustomStyleProperty<Color> connectionSelectedHoverProp = new CustomStyleProperty<Color>( "--connection-selected-hover-color" );

    public static void ReadColorsFromUSSProperties( CustomStyleResolvedEvent evt )
    {
        evt.customStyle.TryGetValue( connectionProp, out connection );
        evt.customStyle.TryGetValue( connectionHoverProp, out connectionHover );
        evt.customStyle.TryGetValue( connectionSelectedProp, out connectionSelected );
        evt.customStyle.TryGetValue( connectionSelectedHoverProp, out connectionSelectedHover );
    }
}

EDIT: In USS, all my color variables are defined in :root. Element type specific colors could be placed in their respective USS selectors, but 1) I like to have the colors centralized and 2) it seems like extra work to grab the same colors again and again every time an element of a specific type is created.

This API was mostly designed to be used in the context of a single element. Therefore it shouldn’t be required to use multiple variables for each state like “hover” or “selected”. Instead, if the element is hover and a selector with “:hover” that changes the “–connection-color” exists, the CustomStyleResolvedEvent event will be invoked when the user interacts with it.

Another way to limit the number of variables is to stick to a color palette with descriptive names such as “–highlight-color”, “–accent-color”, “–disabled-color”, etc.

Ah, enlightening. I see that I may be working against your design here.

However, 1) I am drawing many ConnectionElements and I don’t see how it can be performant to pick up colors using callbacks in every element and 2) updating the variables inside selectors spreads out my color palette again, which I find messy. I also cannot use more general global descriptive names, because colors like “–highlight-color”, “–accent-color”, “–disabled-color” varies for my element types.

I’ll get back if find a cleaner solution.

any news on uss variables? I can’t find any mention of them in the current docs and they’d be super helpful to have

They work now. For editor windows they can go into a ‘:root’ selector, or into a top-level container.

UPDATE: got it working!

like jonathanma_unity mentioned, USS vars are compliant with CSS variables, so they’re super easy to use. Here’s how it looks:

/* this selector contains all variables */
:root {
    --accent: rgb(32, 34, 38);
    --bg: rgb(49, 49, 49);
    --bg-light: rgb(46, 46, 46);
    --bg-dark: rgb(51, 51, 51);
    --bg-header: rgb(62, 62, 62);
    --selection: rgb(62, 95, 150);
    --selection-disabled: rgb(65, 65, 65);
}

/* variables are then accessed like this */
.class {
    background-color = var(--bg);
}

EDIT
using the :root selector will work for windows, but not for custom editor/inspectors as some users have mentioned in other threads.

for inspectors, you’ll want to use the top-most available selector and define your USS variables that way, instead of using :root

(I haven’t actually run into this issue yet, just figured I’d pass on this information in case anyone needed it)

2 Likes