Search Unity

Do css variables (Custom USS Properties) work yet?

Discussion in 'UI Toolkit' started by Stardog, Jan 16, 2020.

  1. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,913
    They don't seem to work for me in 2019.3.0f5.

    Code (csharp):
    1. :root {
    2.    --radius: 10;
    3. }
    4.  
    5. .element {
    6.     border-radius: var(--radius);
    7. }
    They are mentioned in the manual and in this post about 2019.3.0a10.
     
    Last edited: Jan 16, 2020
  2. polerin

    polerin

    Joined:
    Apr 11, 2013
    Posts:
    11
    oooh I didn't know that was a thing. Even if they don't work yet I'm glad you posted about it.
     
  3. SudoCat

    SudoCat

    Joined:
    Feb 19, 2013
    Posts:
    65
    They seem to be a thing, although I'm not sure how public the API is yet, and they don't appear to resemble CSS variables. Here's what I've managed to figure out by trawling some source code.

    They allow you to pass data from your USS into C#, where you can process the data and apply changes to your VisualElement. All custom properties I've seen are specific to one VisualElement type. Some examples of custom properties I've found are:

    • A color property used to set the colour of lines in a curve editor.
    • An int property used to set the height of the items in a list view.
    • A color property used to set the selection colour for a text field.
    • An int property used to set the layer index for nodes on a graph view.

    CustomStyleProperties are defined within classes. Here's an example of how the item height property is implemented in the ListView:

    Code (CSharp):
    1. internal static CustomStyleProperty<int> s_ItemHeightProperty = new CustomStyleProperty<int>("--unity-item-height");
    The class then registers a callback for CustomStyleResolvedEvent within the constructor.

    Code (CSharp):
    1. RegisterCallback<CustomStyleResolvedEvent>(OnCustomStyleResolved);
    Then you can access the property from the callback, and do whatever you want with it!
    Code (CSharp):
    1. private void OnCustomStyleResolved(CustomStyleResolvedEvent e)
    2. {
    3.     int height = 0;
    4.     if (!m_ItemHeightIsInline && e.customStyle.TryGetValue(s_ItemHeightProperty, out height))
    5.     itemHeight = height;
    6. }
    It looks like most of the API is available for use, although mostly undocumented, and probably prone to change. I couldn't see any way to get units out of the values from the few examples I glossed over.
     
    Stardog likes this.
  4. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    1,003
    I think you just need to specify the units to make it work:

    Code (CSharp):
    1. --radius: 10px;
     
    SudoCat likes this.
  5. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,913
    I think my problem was using it in ':root'. It works if I use it in the main container, and add 'px' like you said. This is awesome!

    So, basically just put the variable in the main container, and all the children can pick it up.
     
  6. jonathanma_unity

    jonathanma_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    229
    Seems like the root selector is not applied.

    Could you report a bug so we can investigate? (Help -> Report a bug)

    Thanks!
     
  7. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,913
    It's probably because I'm making an inspector Editor using CreateInspectorGUI and not doing it properly, or its not supported. I'm only doing it to test a PropertyDrawer for when inspectors ditch IMGUI. It looks like this:
    Code (csharp):
    1.  
    2. [CustomEditor(typeof(Tester))]
    3. public class TesterEditor : Editor
    4. {
    5.     public override VisualElement CreateInspectorGUI()
    6.     {
    7.         var container = new VisualElement();
    8.         container.styleSheets.Add(Resources.Load<StyleSheet>("css"));
    9.  
    10.         return container;
    11.     }
    12. }
    I can report a bug if it's supposed to work here.
     
  8. jonathanma_unity

    jonathanma_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    229
    It should work in all cases in my opinion and it's hard to tell with snippets what is happening.

    That is where the bug reporter help since we get the full picture.
     
  9. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,913
    Ok it's Case 1213652 - UIElements uss variables do not work in root selector.
     
  10. jonathanma_unity

    jonathanma_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    229
    Thank you for the bug report I was able to investigate the issue and sadly this is a limitation of UIElements inside the inspector.

    What is happening is the ":root" pseudo class is only active on the root VisualElement of the window (inspector).
    Style sheets only apply to the subtree they are attached to which means that the css.uss does not apply to the root VisualElement because it is way higher in the tree. Therefore the :root selector never matches.

    This is a difference with html where all the style sheets are defined in the <head> section.
     
  11. tonycoculuzzi

    tonycoculuzzi

    Joined:
    Jun 2, 2011
    Posts:
    301
    so the :root selector is not the preferable way to do it?

    if not, which way would you recommend? would a wildcard selector (*) work better?
     
    StephanieRowlinson likes this.
  12. StephanieRowlinson

    StephanieRowlinson

    Joined:
    Jul 23, 2014
    Posts:
    137
    I'm wondering about this as well, because for me variables are most useful if they're global. Preferably across multiple .uss files as well.

    I think I've seen people do this from C#, but I really want a solution that works in USS as that's where they belong imo.
     
  13. jonathanma_unity

    jonathanma_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    229
    The :root selector is sadly not usable in the inspector as explained in my post above. What you can do instead is to add a specific class on the element returned by CreateInspectorGUI and in your USS you can define all variables needed for your inspector in there.

    The :root selector works well for editor window when the style sheets are added onto the root VisualElement.
     
  14. jonathanma_unity

    jonathanma_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    229
    This should also work but is not advisable from a performance standpoint because all elements would get a "copy" of the variables which will make the code handling variables inheritance slower...
     
  15. tonycoculuzzi

    tonycoculuzzi

    Joined:
    Jun 2, 2011
    Posts:
    301
    ah okay, good to know! I noticed it worked in editor windows, but knowing this for inspectors will be useful going forward. I'd recommend updating the docs to reflect this nuance