Primary APIs:
FlowDirection (LeftToRight, RightToLeft)Margin, Padding, BorderThickness, CornerRadius, Width, Height, MinWidth, MinHeightCanvas.Left, Canvas.Right, Canvas.Top, Canvas.BottomTextBlock.TextAlignmentReference docs:
00-html-css-layout-box-model-and-positioning.md01-html-css-flexbox-grid-and-responsive-layout-recipes.md16-html-css-accessibility-semantics-and-motion-preference-mapping.mdCSS 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:
FlowDirection source of truth (LeftToRight or RightToLeft),Thickness/position values from logical inputs,For application UI migration, this is the most predictable equivalent of web logical spacing.
| 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:
writing-mode-driven vertical inline/block axes are not a direct 1:1 Avalonia layout feature.FlowDirection is the practical migration target.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);
}
}
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>
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);
Thickness/CornerRadius.FlowDirection at root or feature-scope containers, not ad-hoc per control.FlowDirection and recompute bound logical thickness properties.TopLeft, TopRight, BottomRight, BottomLeft).Canvas.Left/Canvas.Right using one direction-aware function.