If you’re using Unity’s UIToolkit you’ll sooner-or-later run into this nasty bug: two boxes side-by-side but the border in-between is twice as thick as it should be. In the image below we wanted the boxes on the right (‘a-aaa’ and ‘b-aaa’) with equal-width borders. But Unity will give you the boxes on the left, with the ugly fat border in the middle:

This is a well-known weakness in CSS3 … but when you try to use the standard workaround, you run into a series of multiple serious bugs in Unity which make your UI continue to look ugly. Here’s my final workaround that actually works.

NB: if you’re using the classic UnityUI, and my asset Flexbox4Unity, you will not run into this problem. This post is a tutorial for people using UIToolkit e.g. for Editor scripting. For most cases – especially for in-game UI – I recommend you ignore UIToolkit for now and use UnityUI instead.

CSS3 problem: Collapse-Borders

CSS3 will collapse margins to prevent this problem in most places, but they forgot to add this feature for borders – you simply cannot collapse margins in CSS3! Unity is correctly drawing a full-width border around each box, and not merging the lines between boxes.

Classic workarounds:

  1. Use half-borders on the boxes, and put a half-border round the parent element
  2. Only draw the top-left border for the parent, and only draw the bottom-right borders for the children

These are complex in code and depend on the parent. They fail in Unity because Unity’s CSS renderer isn’t good enough to handle half-width borders – e.g. it will often draw them negative (!) which is wrong in all ways and ruins your layout, or e.g. it will insert a 1-pixel gap between parent and child (again: incorrect, shouldn’t happen but does, presumably to make up for the rounding?)

Unity solution: first, middle, last

Instead we do this:

  1. All boxes get borders: top, bottom
  2. First box gets borders: left, right*0.5
  3. Middle boxes get borders: left*0.5, right*0.5
  4. Last box gets borders: left*0.5, right

This gives us the second pair of boxes in the screenshot:

Code example

public void SetBorders( VisualElement e, bool isFirst, bool isLast, float borderWidth )
{
e.style.borderWidthTop = e.style.borderWidthBottom = borderWidth;
e.style.borderWidthLeft = isFirst ? borderWidth : borderWidth / 2f;
e.style.borderWidthRight = isLast ? borderWidth : borderWidth / 2f;
}

public void ApplyBorderToElements( List<VisualElement> elements, float width )
{
int index = -1;
foreach( var element in elements )
{
index++;
SetBorders( element, index==0, index == (elements.Count-1), width );
}