We can have something like this, or we can have something like this. In my other video I've talked about UI elements and we have created the first result. In this video we are going to stylize that result while learning about the Basics of Style Sheets. Of course, if you don't want to watch my other video I'll have a link down below to get the starting code. StyleSheets are simply files that allow us to stylize our UI with a specific syntax. If you come from web development you are most likely familiar with CSS. What we are going to use will look much like it but it's named USS, short for Unity Style Sheets. In this video I'm going to talk about the following topics: Creating a Style Sheet. Loading a Style Sheet. Adding a Style Sheet to a Visual Element. What are and what type of Selectors you can use. What are Properties. Adding a Style to a Visual Element. And Creating and Using Style Sheets variables. I won't be going into detail how stuff like Flexbox and some more advanced stuff work, but if you do want to know about that you can search for CSS Tutorials as there are plenty of them out there and should work as fine. I don't think USS has everything CSS offers but it seems to have quite a bit of it. In their documentation page they say they use the Yoga Layout Engine, which seems to be an Open Source Layout Engine from Facebook. I'll leave a link in the description if you want to learn more about it. Starting off, in our previous video we have created the project and the files already, but if you haven't watched it, simply create a Project with the Unity version of 2019.1 or above and then create a Style Sheet by clicking in the Project Window,
going to Create > UI Toolkit and choose Style Sheet. I've named mine UIElementsStyles. Of course, don't forget to place the
Editor Window starting code here as well. Now, before going into Style Sheets I
first want to talk about the style variable. Every visual element comes with
a variable called style. This variable allows us to update certain styles through code
without needing to create a Style Sheet file. The disadvantages are that you will have quite a few lines of code on the same file as your UI as you need to update styles individually and you have a limited set of variables you can update. Of course let's just try it out so that you know that it exists and how can you use it. In our Editor Window, file go to your "title" Label and after that type in "title.style". And right here you see that this variable is get only, so you won't be able to set the whole style variable. Instead, like I previously said, you are going to need to set these class variables one by one. If we type a "." after the style variable, we can see that a bunch of variables show up. And that's really how you change it. You can change something like the text color and pass in a color. For example, "Color.red". If we save and go to Unity, we see that the Label is now red. I can think of two use cases for this: The first one is when you need to prototype something as you won't need to create anything extra. The second one would be to dynamically update a style like the background color depending on a condition. The other way of adding styles to your UI is with Style Sheets. Let's go ahead and open our Style Sheet file. It might come with some default code and if it does feel free to remove that. Now, the way Style Sheets work is by simply allowing us to specify "Who" we want to change the styles of and then specify "What" styles do we want to change. So for example, I could say "Change the background color and the text color of all Buttons", or i could say "Change the background color of all Visual
Elements that belong to a certain Group" To the "Who" we want to change, Unity calls a Selector. To the "What" we want to change, Unity calls Properties. There are several Selectors you can use. This means that there are several ways you can identify "Who" you want to change. The selectors are: The C# Type Selector. The Class Selector. The Name Selector. And the Wildcard Selector. Very much like in the name, in the C# Type Selector we simply say that a Type, like a Button, Label or Visual Element, will have certain Properties. When we do this, every Visual Element we create of that Type will have their styles changed to what we chose. We can do this by typing the name of a type. I'll start by updating our Label, so let's go ahead and type in Label. Then, we place curly brackets much like a C# scope. Inside of those curly brackets, we'll have our Properties. In our final result, the Label is seen as a bold and bigger text, and is also centered on the Window. To make our text bold we can use a
Unity built-in Property called "-unity-font-style". To give it a value, we type in column (":") instead of equals ("="), and then give it a value, which in this case, is "bold". And finish it by typing a semi-column (";"). Unity has some built-in Properties like the one we've used, but i couldn't really find a page that told me them all. To make our text centered, we use the "-unity-text-align" built-in
Property, and give it the "middle-center" value. To make the text bigger, we use the "font-size" property and I'll give it a value of 20 pixels. If we save and go back to Unity, we
can see that the Label stayed the same, that's simply because we haven't loaded our Style Sheet yet, nor added it to our EditorWindow. To do so, let's first place our Style Sheet file in a root folder named "Editor Default Resources". We'll be loading the Style Sheet using the "EditorGUIUtility.Load" method. If you want to know more about the Resources Folder and the Load method, feel free to check my video about the Resources Special Folder as I talk about loading Assets with it there, so I won't be explaining it here. Going to our Editor Window script, we create a variable of type "StyleSheet". I'll name it "styleSheet" and load it with the "EditorGUIUtility.Load" method I'll pass in the file name, extension included, so that will be "UIElementsStyles.uss". We have now loaded our StyleSheet assets, so all we need to do is to add it to a visual element. When we add a Style Sheet to a visual element, every visual element that's part of its hierarchy will be able to use that Style Sheet. That means that if we want to add a Style Sheet to our EditorWindow in a way that every Visual Element there can use the Style Sheet styles, we simply need to add it to the Editor Window root. And if you've watched my UI Elements video, you'll know that we can do that with the "rootVisualElement" variable. To add a Style Sheet, we simply use the "styleSheet" variable from the VisualElement base class and it's "Add" method. So we type in "rootVisualElement.stylesheets.Add" and pass in our "styleSheet" variable. Saving and going back to Unity, we see that our Label is now changed. One last thing that might be useful is that if you make a mistake in a value, let's say we've typed in "center" instead of "middle-center", Unity will throw a warning telling you the possible values you can give. Or, if you made a mistake on the name of the Property, it will
ask you if you meant to type something else. So don't be too afraid of typing in an error. It might even be a faster way than searching on google. And that's really it on the C# Type Selector. Every Label we create will have the same styles as our "title" Label. But sometimes we only want a certain group of specific Visual Elements to have a certain style. For example, we currently have 4 Buttons. They all show up with the same color, so we could simply add it with the Button C# Type Selector. However, if we were to add any other Button, they would have the same style. What we can do is to simply create a Group and make those Buttons part of that Group. Any Visual Element that's part of that Group will have its styles. And to that Group, we call, a Class Selector. Differently than the C# Type Selector, we can give it any name we'd like. So let's go ahead and type in "dark-button". We'll give this Class Selector to any Button we want to be dark. The most common naming methodology is probably to add a dash to separate the names. There are several methodologies you can use and Unity actually uses the BEM methodology, which I believe uses both dashes and underscores, but feel free to use any you'd like. As for the Properties, we see that it has a dark background, a white text, no default border and a certain height. So let's type in "background-color" and I'll give it an hex code (#1C2025). Feel free to copy it to have the same color. Then, I'll type in "color" to update its text color and give it an hex code (#E0E0E0) as well. For the border, we can do it in two different ways: The first is to make the border color transparent, this will keep whatever spacing the border has to your UI but won't show it. or, we could make the border width to be of 0 pixels. This means that the border won't add any extra spacing and of course, won't show up. I'll go with the border color one because of a Selector we are gonna use later. For the height, we could type in "height" and give it a value, but I'm actually gonna use the "min-height" Property to make sure it doesn't go under that height. I'll give it a value of 50 pixels. There is one last thing we need to do. You might have noticed that there isn't anything that tells Unity that this is a Class Selector. So right now, Unity might be trying to read it as a C# Type Selector. To tell Unity that this name is a Class Selector, we need to type in a "." before its name. Do note that this "." should only
be typed in the Style Sheet file and nowhere else. We now need to add this class to our Buttons, so let's head back to our Editor Window. Let's first add it to our "randomColorButton", so type in "randomColorButton" and the VisualElement base class has a method called "AddToClassList". This allows you to add classes to this Visual Element. That also means that you can have more than one class per Visual Element. To add a class simply type in its name without the "." at the beginning. If we save and go to Unity, we see that our "randomColorButton" now has styles. Let's do the same for all the other Buttons. Every button should now be looking the same. Now, this is a Button, and you might have noticed it doesn't really feel like one when we hover on them with our mouse. That's because we made the
background color the same for any state with that class. Thankfully, Style Sheets have something called "Pseudo-Classes", which allows you to apply styles of Visual Elements in certain states. The first thing we want to update is the style of the Button when it is hovered. To do so, simply type in the same class name but then type in ":hover". Now any property inside this will be applied when you hover on the Visual Elements with this class. Some elements however might not really have the hover mechanic. In our case, we want background color to be a bit darker, feel free to copy the hex code (#181B1F), and our text color to be yellow or golden (#FDD052). Something else we might want to update is when the Button is active, or pressed. To do so, we have the ":active" Pseudo-Class. We will update our border color to be of the same yellowish color (#FDD052). If we save and go to unity, we can see that our Buttons update their styles when hovering as well as when clicking on them. Remember that I've decided to go with the "border-color: transparent" property on our "dark-button" class
selector. If we'd gone with the border width instead we would need to make sure that on the ":active" Pseudo-Class it had a width of over 0px. Otherwise, our border wouldn't show up. Let's use our Class Selector to make an horizontal container as well. In our case, we are going to use it for our buttons. Let's type in "horizontal-container" and here
we'll use some Properties of the flex layout. I won't be going into detail on the flex
layout, but just give you some basic Properties. To make sure our elements go horizontally instead of vertically, we need to change its flex direction. so let's type in "flex-direction". The value here isn't horizontal nor vertical, but instead "column" or "row". In our case, we want it to be a row as that's horizontal. There's also "row-reversed" and "column-reversed" if you want the elements to swap their order. Next, to align our elements, we need to add two Properties. The first one is "justify-content". If the direction is "row", "justify-content" will align things horizontally. If the direction is "column", "justify-content" will align things vertically. So let's pass in the value of "center". Because we are on a row direction, it will align things horizontally. The second one is "align-content". It does the same as the "justify-content" but on the opposite directions. So "row" is vertical, and "column"
is horizontal. Let's also pass in "center". One last thing I'd like to do is to wrap the elements when the window size is changed to something small, so that they don't disappear. We can do that with the "flex-wrap" Property. We can simply pass in a value of "wrap". To make sure it is updated on our Editor Window, let's add this class to our "buttonsContainer". All Buttons should now be placed horizontally. Something about classes is that you
have a list. Therefore, if you want to get a class from a Visual Element, you can simply iterate through the classes list of that Visual Element. I could not find a link to every class Unity provides, so this is one way you could search for them in case you want to update them. Of course, you could simply create your own class with what you want to change and add it to your Visual Element. Now comes probably the weirdest one, which is the Name Selector. I say weird because in CSS this is called ID Selector. And I think it is most often not used or recommended. This is likely because this selector can only be used by one element per Panel. So in our Editor Window, only one Visual Element will be able to use this Name Selector. Meaning our ID's, or names, need to be unique through all of
the Editor Window. And I don't really see how this can do something that a Class Selector can't. But if you do know a good reason to use it please leave a comment below so that we all can know about it. I'll still talk about it though. Much like a Class Selector, we
can give it any name we'd like. I'm going to give it the name of "color-picker", as we'll be using it for our ColorField. To tell unity this is a Name Selector, we need to place an hashtag (#) before its name. We are only going to add one thing here and it's actually a margin, so let's go ahead and type in "margin: 8px;". If we save it, it will of course not yet be updated. That's because like the Class Selector, we need to tell which of our Visual Element will have this name. So let's go to our Editor Window and in our ColorField we can change its name through the name variable. This is a Visual Element variable that allows us to change the Visual Element name which will be used for our Style Sheets. You can give multiple Visual Elements the same name as Unity won't throw an error, but because they need to be unique, it might give you unexpected errors, so make sure the same name is only being used by one Visual Element. Give it the name of "color-picker". If we save, we can see that our color picker now has a small margin. In our final result, the Label and the horizontal container also have a margin, so let's give each one a margin of 8 pixels as well. And last but not least, we have our Wildcard Selector. This is a Selector that you can't really name and always looks the same: an asterisk (*). This selector means everything, so everything that uses this Style Sheet will have whatever style you define here. For example, we see that our Editor Window elements aren't vertically centered. Let's go ahead and center them by using the "justify-content" Property. We'll just pass in "center" as a value. Remember that this Property will act differently per flex direction, so for our horizontal container it will act horizontally, while for others it will act vertically. Of course, because of that, we can remove our "justify-content" from our horizontal container. Let's also make the default background color of everything a dark color (#282C34). This will also update the Editor Window background color. If we save, we can see that every Visual Element is now centered in our Editor Window. We could add our margin here as well, but then we would need to go to our Button and reset it to the margin that it had, which seems to be around 2 pixels or so, and delete the margin from our Editor Window as well. I'll just leave the margins as they are because they aren't really being used by every Selector. So really, if you know something is going to be equal for all elements, place that Property here. There is one thing we need to keep in
mind and that's when a Visual Element style is being updated in two different Selectors. For example, we've use the Wildcard Selector to add the "background-color " for every Visual Element. However, we also added a "background-color" to our Buttons through our "dark-button" Class Selector. When deciding which one to use, Unity uses something called Specificity. I'll leave a link in the description if you want to see who has more specificity. But in this case, our button color became darker instead of lighter, as our Class Selector has a higher specificity, or a higher priority, than the Wildcard Selector. If they were both the same Selectors type, then the one that appears last in the Style Sheet file will have the highest specificity. That's it for our styles, but there is one last thing we need to talk about. You might have noticed that two of
our values are used multiple times. This is alright but it is possible that you start typing a lot of
repeated values throughout your Style Sheet files. Thankfully, we can create variables
in Style Sheets as well. To declare one, we simply give it a name, much like built-in Properties, but with two dashes before their name. Then, we give it a value like we do to Properties. If we want this variable to be global and be usable on every selector of any Style Sheet, Unity tells us we can add it inside the ":root" Pseudo-Class Selector. I've tried placing it in several other Selectors and it all seemed to work, so I'm not entirely sure what the root is exactly, as it turned out to be global regardless. But I guess it's just safer for you to do so and like they say for CSS, a common practice. However, for Inspector UI, you need to use a Class Selector instead. But I'll leave a link down below for that. Do note that the variable won't be declared if it is outside a Selector. Here we can set anything we want as a variable. For example, let's set our yellow text color by typing in "--yellow-color: #FDD052;". Now to use this variable we use the "var" function to call it. So let's go to where we use our yellow color and replace it with "var(--yellow-color);". If we save and go to unity we can see that our color is still there. Let's also create one variable for our margin called "--margin-8". We'll replace this on every margin we use that has 8 pixels. If you wanted a whole project to use the same variables in case you had multiple Style Sheets, you could create a Style Sheet that contains all the variables and load it once, as other Style Sheet files can use the variables if they are loaded in the same root or panel. For example, if we add a file for the variables alone, we would need to load it in our Editor Window for our Visual Elements styles to be able to use them. If we didn't load it then the Style Sheet file will just ignore the variable. The var function apparently supports a default value in case Unity can't find the variable. But for some reason, when i try to use it, I get an error and it uses both colors. I might be doing something wrong but I'm not entirely sure what. And that's it for the basics of Style Sheets. We have the C# Type Selector to apply styles for a
whole C# Type, like Button or Label. We have the Class Selector to apply styles to whatever elements we want, and we can add more than one class to a Visual Element. We then have Pseudo-Classes that allows us to change styles in special states, like when a button is hovered or when the element is the first child. We also have the Name Selector to apply styles to an unique element per panel. And last but not least, we have the Wildcard Selector to apply global styles to all of the Visual
Elements. To update our styles we have Properties. We can update stuff like background color, text color or the width and height of our elements. When we have the same property being changed for the same Visual Element in different Selectors, we have to keep in mind their specificity. To make things easier for reusability, we can create our own variables. Creating them on the ":root" Pseudo-Class to make them global. If you have any question or just found something that I've said to be wrong please feel free to leave a comment down below so
that we all can know about it and learn from it. I hope you've enjoyed this tutorial
and see you in the next one.