Best way to "animate" visual changes without resizing visual element

Hey,

A bit of a vague title, but the situation I have is as following:

I have a menu of X amount of items going from top to bottom and on hover, I want to add a border to those items as an indication of what is currently highlighted. Now this is easily done with USS and I can customize it any way I want to. However, I am not entirely sure what the best practice is to not have all other elements move when doing this.

9495622--1337062--Unity_W0uc7J02x4.gif

As you can see in the image, when the border is added (exaggerated in width to make it more apparent), the size of the element increases and other elements will move accordingly to make room.

This is something I don’t want, but I am not entirely sure on what would be the best practice to do these kind of things? I can think of a couple of ways to prevent this, but I’d rather have a consistent best practice I can apply going forward.

Any advice on the topic?

If you’re not familiar with how padding and margins work, you may want to start studying that on the USS side this is called “Box Model” in CSS.

The idea you’re looking for is that your content sits nicely within content box, this includes anything added to it like a border, padding then won’t be needing to dynamically change.

If you’re using UI builder you should be able to hover the element and see how these boxes are arranging, subsequent element’s and flex on your USS will activate only if certain conditions are met.

The easiest test you can do right now is ensure that your boarder is the right size to allow the contents biggest state enough room. And of course the margin has some px between each other text/button/menu element.

There are make pixel rules too that you can choose to give you a standard to work with which can really help speed this process up to like 6:3:1 colour rule and 4-point grid for spacing.

Because unity doesn’t fully support all USS features ( like collapsible boxes) if you’re trying to optimise your pixel space just be aware that you may have to half or double a margin per element to fit the rule.
Hope that helps.

Thanks for the answer.

I am aware of padding and margin and this was what I initially tried without luck (the elements still grew, including the margin or padding). As I am not overly familiar with USS/CSS yet though, I might’ve done something wrong.

I will give it a go again and see how it goes.

Ah, I see. In that case, it might take some restructuring of your hierarchy or USS overrides.
Mostly it’s going to be down to how something is overriding.

My test case video shows that in your USS, you may have a different margin size on your item vs item:hover. ( hove can be left at 0 ( see note)

I’ve provided the video and unity package if you want to use it to study

To note, I’m just demonstrating that the USS selectors are different.
if you want to have the margin be the same between the two states you only need to set the parent state, the :hover state will take any existing setups.

Hope that helps

GIF of a working example:

9499321--1337839--2023-11-29_08-40-20.gif

9499321–1337842–2023-11-29_08-36-09.zip (2.31 MB)
9499321–1337845–MenuHoverSupport.unitypackage (1.22 KB)

If you want to see the box layout in Builder you can just over the elements
( you can also see this in UI debug view in the editor)

In this example mind, you’re not seeing the :hover ones, which is what i assume is going on in your situation.

GIF Showing Margins and Borders GIF Showing Margins and Borders

9499336--1337854--upload_2023-11-29_8-53-19.gif

This now being on my mind, another thought to where it could be is the border itself, with a border override you’ll have:

.selector

  • border colour
  • border width

.selector:hover

  • border colour
  • border width

overriding between the two to make a border appear in you would need the border to be present on both for example:

.selector

  • border colour: Alpha 0
  • border width: 1px

.selector:hover

  • border colour Alpha 255
  • border width: 1px

If your .selector doesn’t include a border width by default and with the alpha all the way down so that it’s invisible when you interpolate between normal and hover you would then be adding the border into the content space instead of it always being there, you’re just making it visible, this would be the alternative solution if it isn’t your margins and you’re still having issues.

Thanks for the very clear and elaborate answer, really appreciated!

Just to clarify, in the gif I posted I did not use any margin and/or padding. I had it set up before I posted, resulted in ‘jumping’ elements similar to the gif and thought: “Not gonna need any margin/padding so just going to remove them” and then after some toying around and not getting the results, I made this post.

Going to give it a try tomorrow, but I am confident I will get it to work now thanks to your posts!

Most welcome! And good luck tomorrow and let me know how it goes. I feel invested now.

Well, I found out where it went wrong. At least in comparison to your setup.

In my case, I wasn’t using buttons, but just visual elements as buttons. By default, buttons have a border width of 1px, so when you hover over and give the border a color (like your example) it works as expected.

In my case, the visual element by default doesn’t have a border width and I simply set the border width to 1px in the :hover state. This would add to the overall size of the element and other elements needs to “move” to make room.

What I initially thought you meant, is that margin/padding would provide additional room for that growth, which it doesn’t (not what is happening at least).

So now, when I give my menu items a border of 1px by default and simply make it show when hovering, it works as I would expect.

Thanks again for all the insight, much appreciated!

1 Like

Those sneaky 1px borders, I thought I’d follow up because that was on my mind. Well done for solving

1 Like

In addition to the obvious esthetical reasons to preserve the size of the items, there a under-the-hood advantages of trying to preserve the layout, as it is computationally intensive to change. If you are using uss transition, there is a few fast-pass on opacity, colors, and the transform( rotate, translate, scale) where we don’t need to re-layout and re-tessellate the element. If you are not using transition, you could look into setting the render hints on the element that you will change on hover to activate the optimizations. I really think the border color is optimized in some cases, but before doing this you can check in the profiler that you have a problem to begin with.

1 Like

ah yeah, I remember this from a dev environment, There are some hardware limits though right?
You can’t just mark an entire dynamic UI that’s is frequently jumping states with them for instance?

You can, but you will pay an extra cost performance wise: when using dynamic color, the color is stored separately from the vertex: changing it is way cheaper, but if you are not changing it the shader still need to do an extra lookup for no reason.

There is probably some hardware limit but you should not hit it in regular cases.

1 Like