AgentSkillsCN

taffy-api

当您编写使用 taffy 进行 UI 布局——包括 Flexbox、CSS Grid 或块级布局算法——时,可选用此方案。无论是计算布局树、设置节点样式,还是将 taffy 与渲染系统集成,此方案都能派上用场。

SKILL.md
--- frontmatter
name: taffy-api
description: Use when writing Rust code that uses taffy for UI layout - Flexbox, CSS Grid, or Block layout algorithms. Use when computing layout trees, setting node styles, or integrating taffy with rendering systems.

Taffy API Reference

Taffy is a high-performance UI layout library implementing CSS Flexbox, Grid, and Block algorithms in Rust.

Quick Start

rust
use taffy::prelude::*;

let mut taffy: TaffyTree<()> = TaffyTree::new();

// Create nodes
let child = taffy.new_leaf(Style {
    size: Size { width: length(100.0), height: auto() },
    flex_grow: 1.0,
    ..Default::default()
})?;

let root = taffy.new_with_children(
    Style {
        display: Display::Flex,
        size: Size { width: length(800.0), height: length(600.0) },
        ..Default::default()
    },
    &[child],
)?;

// Compute and access layout
taffy.compute_layout(root, Size::MAX_CONTENT)?;
let layout = taffy.layout(root)?;
println!("Position: ({}, {})", layout.location.x, layout.location.y);
println!("Size: {}x{}", layout.size.width, layout.size.height);

Core Types

TaffyTree<NodeContext>

Main entry point. NodeContext is user data for measure functions (use () if not needed).

rust
// Creation
TaffyTree::new()                    // Default capacity (16)
TaffyTree::with_capacity(100)       // Pre-allocate

// Node creation
new_leaf(style) -> NodeId
new_leaf_with_context(style, ctx) -> NodeId
new_with_children(style, &[children]) -> NodeId

// Tree manipulation
add_child(parent, child)
set_children(parent, &[children])
remove_child(parent, child)
remove_child_at_index(parent, idx)
insert_child_at_index(parent, idx, child)
replace_child_at_index(parent, idx, new_child)

// Style access
set_style(node, style)
style(node) -> &Style

// Layout
compute_layout(node, available_space)
compute_layout_with_measure(node, available_space, measure_fn)
layout(node) -> &Layout
mark_dirty(node)                    // Invalidate cached layout
dirty(node) -> bool                 // Check if needs recompute

// Rounding
enable_rounding()                   // Default: enabled
disable_rounding()

// Debug
print_tree(root)                    // Print layout tree (std feature)

Layout (Output)

rust
pub struct Layout {
    pub location: Point<f32>,       // Top-left position relative to parent
    pub size: Size<f32>,            // Width and height
    pub content_size: Size<f32>,    // Content size (for scroll)
    pub padding: Rect<f32>,
    pub border: Rect<f32>,
    pub margin: Rect<f32>,
    pub scrollbar_size: Size<f32>,
    pub order: u32,                 // Render order (higher = on top)
}

// Convenience methods
layout.content_box_size()           // Size minus padding/border
layout.content_box_x()              // X offset to content box
layout.content_box_y()              // Y offset to content box
layout.scroll_width()               // Overflow width
layout.scroll_height()              // Overflow height

Geometry Types

rust
Size<T> { width: T, height: T }
Point<T> { x: T, y: T }
Rect<T> { left: T, right: T, top: T, bottom: T }
Line<T> { start: T, end: T }

// Constants
Size::ZERO, Size::MAX_CONTENT
Point::ZERO

Style Properties

Display Mode

rust
Display::Flex       // Flexbox (default)
Display::Grid       // CSS Grid
Display::Block      // Block layout
Display::None       // Hidden

Position

rust
Position::Relative  // Normal flow (default)
Position::Absolute  // Out of flow, relative to positioned ancestor

Sizing

rust
Style {
    size: Size { width: length(100.0), height: auto() },
    min_size: Size::auto(),
    max_size: Size::auto(),
    aspect_ratio: Some(16.0 / 9.0),  // Width / height
    box_sizing: BoxSizing::BorderBox, // or ContentBox
    ..Default::default()
}

Dimension Values

rust
// Helper functions (preferred)
length(100.0)       // Fixed pixels
percent(0.5)        // 50% of parent
auto()              // Automatic sizing
min_content()       // Shrink to minimum
max_content()       // Expand to maximum
fit_content(length(200.0))  // Clamp to argument

// Direct enum usage
Dimension::Length(100.0)
Dimension::Percent(0.5)
Dimension::Auto

Spacing

rust
Style {
    margin: Rect { left: length(10.0), right: length(10.0), top: auto(), bottom: auto() },
    padding: Rect::length(20.0),    // All sides same
    border: Rect::zero(),
    gap: Size { width: length(10.0), height: length(10.0) },  // Flex/Grid gap
    ..Default::default()
}

Overflow

rust
Style {
    overflow: Point { x: Overflow::Visible, y: Overflow::Scroll },
    scrollbar_width: 15.0,          // Reserve space for scrollbar
    ..Default::default()
}

Overflow::Visible   // Content can overflow (default)
Overflow::Clip      // Clip overflow, auto min-size based on content
Overflow::Hidden    // Clip overflow, auto min-size is 0
Overflow::Scroll    // Like Hidden + reserve scrollbar space

Flexbox

rust
Style {
    display: Display::Flex,
    flex_direction: FlexDirection::Row,     // Row, Column, RowReverse, ColumnReverse
    flex_wrap: FlexWrap::NoWrap,            // NoWrap, Wrap, WrapReverse

    // Container alignment
    justify_content: Some(JustifyContent::Center),
    align_items: Some(AlignItems::Stretch),
    align_content: Some(AlignContent::FlexStart),
    gap: Size { width: length(10.0), height: length(10.0) },

    ..Default::default()
}

// Item properties
Style {
    flex_grow: 1.0,                 // How much to grow (default: 0)
    flex_shrink: 1.0,               // How much to shrink (default: 1)
    flex_basis: auto(),             // Initial size before grow/shrink
    align_self: Some(AlignSelf::Center),
    ..Default::default()
}

Alignment Values

rust
// justify_content / align_content
JustifyContent::FlexStart | Start | Center | FlexEnd | End
JustifyContent::SpaceBetween | SpaceAround | SpaceEvenly | Stretch

// align_items / align_self
AlignItems::FlexStart | Start | Center | FlexEnd | End
AlignItems::Stretch | Baseline

CSS Grid

rust
Style {
    display: Display::Grid,

    // Track definitions
    grid_template_columns: vec![length(250.0), fr(1.0), length(250.0)],
    grid_template_rows: vec![length(100.0), fr(1.0), length(50.0)],

    // Implicit tracks (for auto-placed items)
    grid_auto_rows: vec![length(50.0)],
    grid_auto_columns: vec![fr(1.0)],
    grid_auto_flow: GridAutoFlow::Row,  // Row, Column, RowDense, ColumnDense

    // Alignment
    justify_items: Some(AlignItems::Stretch),
    align_items: Some(AlignItems::Stretch),
    gap: Size { width: length(10.0), height: length(10.0) },

    ..Default::default()
}

Track Sizing Functions

rust
length(100.0)                       // Fixed size
percent(0.25)                       // Percentage of container
fr(1.0)                             // Fractional unit (flex)
auto()                              // Size to content
min_content()                       // Minimum content size
max_content()                       // Maximum content size
minmax(length(100.0), fr(1.0))      // Min/max bounds
fit_content(length(200.0))          // Clamp max-content to argument
flex(1.0)                           // Shorthand for minmax(0, fr(1))

// Repetition
repeat(3, vec![fr(1.0)])            // Repeat 3 times
repeat("auto-fill", vec![length(100.0)])  // Fill container
repeat("auto-fit", vec![minmax(length(100.0), fr(1.0))])
evenly_sized_tracks(4)              // 4 equal columns: repeat(4, fr(1))

Grid Item Placement

rust
Style {
    // Place on specific lines (1-indexed, negative counts from end)
    grid_row: Line { start: line(1), end: line(3) },
    grid_column: Line { start: line(2), end: span(2) },

    // Item alignment
    justify_self: Some(AlignSelf::Center),
    align_self: Some(AlignSelf::Start),
    ..Default::default()
}

// Placement helpers
line(2)         // Grid line 2
line(-1)        // Last grid line
span(3)         // Span 3 tracks
auto()          // Auto placement

Holy Grail Layout Example

rust
let root = taffy.new_with_children(
    Style {
        display: Display::Grid,
        size: Size { width: length(800.0), height: length(600.0) },
        grid_template_columns: vec![length(200.0), fr(1.0), length(200.0)],
        grid_template_rows: vec![length(100.0), fr(1.0), length(50.0)],
        ..Default::default()
    },
    &[header, left_sidebar, content, right_sidebar, footer],
)?;

// Header spans all 3 columns
let header = taffy.new_leaf(Style {
    grid_row: line(1),
    grid_column: Line { start: line(1), end: span(3) },
    ..Default::default()
})?;

Measure Functions

For leaf nodes with dynamic content (text, images):

rust
enum NodeContext {
    Text(String),
    Image { width: f32, height: f32 },
}

let text_node = taffy.new_leaf_with_context(
    Style::default(),
    NodeContext::Text("Hello".into()),
)?;

taffy.compute_layout_with_measure(
    root,
    Size::MAX_CONTENT,
    |known_dimensions, available_space, node_id, node_context, style| {
        match node_context {
            Some(NodeContext::Text(text)) => measure_text(text, available_space),
            Some(NodeContext::Image { width, height }) => Size { width: *width, height: *height },
            None => Size::ZERO,
        }
    },
)?;

Measure Function Signature

rust
fn measure(
    known_dimensions: Size<Option<f32>>,  // Fixed dimensions (if any)
    available_space: Size<AvailableSpace>, // Space constraints
    node_id: NodeId,
    node_context: Option<&mut NodeContext>,
    style: &Style,
) -> Size<f32>

AvailableSpace

rust
AvailableSpace::Definite(500.0)  // Exact available width/height
AvailableSpace::MinContent       // Return minimum size
AvailableSpace::MaxContent       // Return ideal size

// Common patterns
Size::MAX_CONTENT                // Both axes max-content
Size { width: AvailableSpace::Definite(100.0), height: AvailableSpace::MaxContent }

Feature Flags

toml
[dependencies]
taffy = { version = "0.7", default-features = false, features = ["flexbox", "grid"] }
FeatureDescription
flexboxFlexbox layout (default)
gridCSS Grid layout (default)
block_layoutBlock layout (default)
taffy_treeBuilt-in tree (default)
stdStandard library (default)
allocAlloc without std
serdeSerialization
content_sizeTrack content size (default)
detailed_layout_infoGrid track info

Common Patterns

Centered Content

rust
Style {
    display: Display::Flex,
    justify_content: Some(JustifyContent::Center),
    align_items: Some(AlignItems::Center),
    ..Default::default()
}

Scrollable Container

rust
Style {
    overflow: Point { x: Overflow::Hidden, y: Overflow::Scroll },
    scrollbar_width: 15.0,
    ..Default::default()
}

Absolute Positioning

rust
Style {
    position: Position::Absolute,
    inset: Rect {
        left: length(10.0),
        top: length(10.0),
        right: auto(),
        bottom: auto(),
    },
    ..Default::default()
}

Responsive Grid

rust
Style {
    display: Display::Grid,
    grid_template_columns: vec![
        repeat("auto-fill", vec![minmax(length(200.0), fr(1.0))])
    ],
    gap: Size::length(16.0),
    ..Default::default()
}

Low-Level API

For custom tree implementations, implement these traits:

rust
trait TraversePartialTree {
    fn child_ids(&self, node: NodeId) -> impl Iterator<Item = NodeId>;
    fn child_count(&self, node: NodeId) -> usize;
    fn get_child_id(&self, node: NodeId, index: usize) -> NodeId;
}

trait LayoutPartialTree: TraversePartialTree {
    fn get_core_container_style(&self, node: NodeId) -> impl CoreStyle;
    fn set_unrounded_layout(&mut self, node: NodeId, layout: &Layout);
    fn compute_child_layout(&mut self, node: NodeId, inputs: LayoutInput) -> LayoutOutput;
}

Then use the algorithm functions directly:

rust
compute_flexbox_layout(&mut tree, node_id, inputs)
compute_grid_layout(&mut tree, node_id, inputs)
compute_block_layout(&mut tree, node_id, inputs)
compute_leaf_layout(inputs, style, baseline_fn, measure_fn)
round_layout(&mut tree, node_id)