xaml-csharp-development-skill-for-avalonia

HTML/CSS Logical Properties to Avalonia Flow-Aware Spacing and Alignment

Table of Contents

  1. Scope and APIs
  2. Logical Property Support Model
  3. Mapping Table (Inline/Block to Avalonia)
  4. Flow-Aware Thickness and Corner Helpers
  5. Conversion Example: Logical Card Spacing
  6. C# Equivalent: Logical Card Spacing
  7. Practical Do/Don’t Guidance
  8. Troubleshooting

Scope and APIs

Primary APIs:

Reference docs:

Logical Property Support Model

CSS logical properties (margin-inline-start, padding-block-end, inset-inline-start, inline-size, etc.) are direction-aware by design.

Avalonia does not expose separate built-in logical thickness properties. The practical mapping is:

  1. keep one FlowDirection source of truth (LeftToRight or RightToLeft),
  2. compute physical Thickness/position values from logical inputs,
  3. bind computed values into XAML properties.

For application UI migration, this is the most predictable equivalent of web logical spacing.

Mapping Table (Inline/Block to Avalonia)

CSS logical idiom Avalonia mapping
margin-inline-start / margin-inline-end map to Margin.Left/Margin.Right based on FlowDirection
margin-block-start / margin-block-end map to Margin.Top/Margin.Bottom
padding-inline-* / padding-block-* map to Padding Thickness values
border-inline-start-width / border-inline-end-width map to BorderThickness.Left/BorderThickness.Right by flow
inset-inline-start / inset-inline-end map to Canvas.Left/Canvas.Right by flow
inset-block-start / inset-block-end map to Canvas.Top/Canvas.Bottom
inline-size / min-inline-size Width / MinWidth (horizontal writing mode apps)
block-size / min-block-size Height / MinHeight (horizontal writing mode apps)
text-align: start TextAlignment="Start" with appropriate FlowDirection

Notes:

Flow-Aware Thickness and Corner Helpers

using Avalonia;
using Avalonia.Media;

public static class LogicalLayout
{
    public static Thickness Thickness(
        double inlineStart,
        double blockStart,
        double inlineEnd,
        double blockEnd,
        FlowDirection flowDirection)
    {
        return flowDirection == FlowDirection.RightToLeft
            ? new Thickness(inlineEnd, blockStart, inlineStart, blockEnd)
            : new Thickness(inlineStart, blockStart, inlineEnd, blockEnd);
    }

    public static CornerRadius Corner(
        double startStart,
        double startEnd,
        double endEnd,
        double endStart,
        FlowDirection flowDirection)
    {
        // Avalonia corner order: TopLeft, TopRight, BottomRight, BottomLeft
        return flowDirection == FlowDirection.RightToLeft
            ? new CornerRadius(startEnd, startStart, endStart, endEnd)
            : new CornerRadius(startStart, startEnd, endEnd, endStart);
    }
}

Conversion Example: Logical Card Spacing

HTML/CSS:

<article class="card">
  <h3 class="title">Revenue</h3>
</article>
.card {
  margin-inline: 24px 12px;
  padding-inline: 20px 28px;
  padding-block: 12px 16px;
  border-inline-start-width: 6px;
  border-inline-end-width: 2px;
}

Avalonia pattern (computed once per direction and bound):

<Border Classes="metric-card"
        Margin="{CompiledBinding CardMargin}"
        Padding="{CompiledBinding CardPadding}"
        BorderThickness="{CompiledBinding CardBorderThickness}"
        CornerRadius="{CompiledBinding CardCornerRadius}">
  <TextBlock Text="{CompiledBinding Title}" TextAlignment="Start" />
</Border>

C# Equivalent: Logical Card Spacing

using Avalonia;
using Avalonia.Media;

public FlowDirection CurrentFlowDirection { get; set; } = FlowDirection.LeftToRight;

public Thickness CardMargin =>
    LogicalLayout.Thickness(inlineStart: 24, blockStart: 0, inlineEnd: 12, blockEnd: 0, CurrentFlowDirection);

public Thickness CardPadding =>
    LogicalLayout.Thickness(inlineStart: 20, blockStart: 12, inlineEnd: 28, blockEnd: 16, CurrentFlowDirection);

public Thickness CardBorderThickness =>
    LogicalLayout.Thickness(inlineStart: 6, blockStart: 1, inlineEnd: 2, blockEnd: 1, CurrentFlowDirection);

public CornerRadius CardCornerRadius =>
    LogicalLayout.Corner(startStart: 14, startEnd: 6, endEnd: 14, endStart: 6, CurrentFlowDirection);

Practical Do/Don’t Guidance

Troubleshooting

  1. RTL UI still shows LTR spacing.
    • Confirm the active container FlowDirection and recompute bound logical thickness properties.
  2. Borders/radii mirror incorrectly on RTL.
    • Centralize mapping helpers and verify corner order (TopLeft, TopRight, BottomRight, BottomLeft).
  3. Inline start/end positioned elements overlap.
    • For absolute layouts, map logical inset to Canvas.Left/Canvas.Right using one direction-aware function.