Size.Auto computation does not take into account child positions

When using automatic sizes parents will size to the max width and height of their children.

The following creates a 400 tall panel that full contains a 400 tall rectangle:

<Panel Color="#f00">
    <Rectangle Width="100" Height="400" Color="#0f08" />
</Panel>

However if the children use an X or Y position this is not taken into account; The parent is still sized to the maximum child dimensions, but not such that all children are contained within it.

The following creates a 300 tall panel that only partially contains a 300 tall rectangle:

<Panel Color="#f00">
    <Rectangle Width="100" Y="100" Height="300" Color="#0f08" />
</Panel>

In both examples above I would have expected the Panel to be 400 point tall, in order to contain its children, with the second example simply having a space above the rectangle. It seems non-obvious to me that the parent elements should still be sized to the largest element, but not such that they are actually contained.

It might be that this is just a deliberate oddity in behaviour, and not a bug, but it seems to me that containing all children when using automatic sizes would be the more useful, intuitive behaviour.

Hi Luke,

TL;DR:
The suggestion to “expand parent to contain all children” is fundamentally flawed. Fuse already employs much more sophisticated ways to calculate (and handle) UX element sizes that handles almost any possible scenario. The reason why X and Y positions are “not taken into account” are because that’s just a visual translation, and not a layout change.

Ready? Let’s go.

The size of elements in Fuse is calculated (and sometimes enforced) based on a number of different things, not just the size of children. Several assumptions you’ve made also aren’t entirely true.

Let me take you on a journey through UX size calculations…

Let’s start with the concept of “available space”. As you might expect, when you have an empty application, the available space is the whole screen of the mobile device, including the area behind Status and Action bars:

<App>
</App>

Now, when you put any kind of *Panel inside of the app, it will by default try to be as big as possible and fill up all available space:

<App>
    <Panel>
    </Panel>
</App>

Which, if you think about it, is quite useful, because the possibility to draw behind Status and Action bars is a neat feature.

However, since that is not always desired, there are ways to constrain the available space, so let’s do that:

<App>
    <DockPanel>
        <StatusBarBackground Dock="Top" />
        <BottomBarBackground Dock="Bottom" />
        <Panel>
        </Panel>
    </DockPanel>
</App>

The DockPanel there fills up all available space, then inside of it a StatusBarBackground is docked to the top and takes up as much space as the status bar on device would. The BottomBarBackground is docked to the bottom and takes up as much space as the Action bar (and on-screen keyboard, when visible) would take up.

Want to guess what the remaining Panel does? No surprise there: it takes up the remaining available space, which now equals to the whole visible area of the screen, except Status and Action bars.

If we now put in another simple Panel inside of that Panel, it will again try to be as big as possible and extend to the dimensions of its parent:

<App>
    <DockPanel>
        <StatusBarBackground Dock="Top" />
        <BottomBarBackground Dock="Bottom" />
        <Panel>
            <Panel>
            </Panel>
        </Panel>
    </DockPanel>
</App>

With the available space concept settled firmly, I think we’re ready to move on. Let’s throw Alignment in the mix!

<App>
    <DockPanel>
        <StatusBarBackground Dock="Top" />
        <BottomBarBackground Dock="Bottom" />
        <Panel>
            <Panel Alignment="Top">
            </Panel>
        </Panel>
    </DockPanel>
</App>

In this case, the nested child Panel (the one with Alignment) will take up full width of the available space and zero height, and be aligned to the top of its parent. When you assign an Alignment to an element, it tries to stick to the particular side and take up as little space in the respective direction as possible. If we were to say Alignment="TopLeft" (or any other corner-direction), then both width and height would be zero.

However, if we were to add some child elements with non-zero height inside of such top-aligned Panel, the children would push the parent dimensions to accommodate the tallest child:

<App>
    <DockPanel>
        <StatusBarBackground Dock="Top" />
        <BottomBarBackground Dock="Bottom" />
        <Panel>
            <Panel Alignment="Top">
                <Panel Height="20">
                </Panel>
                <Panel Height="200">
                </Panel>
            </Panel>
        </Panel>
    </DockPanel>
</App>

Note that the children inside of a regular Panel overlap each other, so the parent in this case would be pushed to be 200 points high, not 220.

A slightly different picture is painted when we use different kinds of Panels. Let’s look at what a StackPanel does:

<App>
    <DockPanel>
        <StatusBarBackground Dock="Top" />
        <BottomBarBackground Dock="Bottom" />
        <Panel>
            <StackPanel>
            </StackPanel>
        </Panel>
    </DockPanel>
</App>

By just looking at that code, it would make sense to think that the StackPanel would take up all of the available space inside its parent, right? Wrong.

StackPanel does what its name suggests, it stacks items. Since there are zero child elements for it to stack, it is aligned to the vertical center inside its parent and the height of the StackPanel is, you guessed it, zero. We can now push it larger by adding some child elements inside of it, just like before with the regular Panel:

<App>
    <DockPanel>
        <StatusBarBackground Dock="Top" />
        <BottomBarBackground Dock="Bottom" />
        <Panel>
            <StackPanel Alignment="Top">
                <Panel Height="20">
                </Panel>
                <Panel Height="200">
                </Panel>
            </StackPanel>
        </Panel>
    </DockPanel>
</App>

And now the StackPanel is 220 points high and aligned to the top of its parent.

It doesn’t stop at this. There’s a WrapPanel and a Grid too, and a huge list of other interesting UX beasts, all of which are extremely useful and come with their properties that affect the available space calculation. And I didn’t even mention Padding and Margin, which you could apply to both parent and child elements. And then the translations in X and Y direction, as you mentioned. And just when you thought you’ve got it all bright and clear, along comes ClipToBounds="true" which allows you to visually clip the children to the bounds of the parent (while they physically still expand beyond it).

There’s so much going on that you simply have to dive in and give it all a go. It’s fun! A good resource to see how all the different UX elements are used to achieve meaningful element placement on screen, are the ever-expanding Fuse examples.

To me, after spending a good while developing with Fuse, all this couldn’t get more intuitive than that. Hope this helps you clear up the UX sizing concepts in Fuse!