tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 583HTML 275Markdown 8TOML 41586 Definiciones

Convert algorithms to traitified styles

7b6efafe42c49ebdf1d84a7afe8ff4e62fda94ed · por Nico Burns · (hace 2 años) · padre 82574827f · ver el árbol en este commit

Delta semántico · 93

src/compute/block.rs

src/compute/flexbox.rs

src/compute/grid/alignment.rs

src/compute/grid/explicit_grid.rs

src/compute/grid/implicit_grid.rs

src/compute/grid/mod.rs

src/compute/grid/placement.rs

src/compute/grid/types/grid_item.rs

src/compute/leaf.rs

src/compute/mod.rs

src/style/grid.rs

src/style/mod.rs

src/tree/taffy_tree.rs

src/tree/traits.rs

14 archivos · +596 −305

diff --git a/src/compute/block.rs b/src/compute/block.rs
index ea89f639c..edbbdaed8 100644
--- a/src/compute/block.rs
+++ b/src/compute/block.rs
@@ -1,6 +1,6 @@
 //! Computes the CSS block layout algorithm in the case that the block container being laid out contains only block-level boxes
 use crate::geometry::{Line, Point, Rect, Size};
-use crate::style::{AvailableSpace, Display, LengthPercentageAuto, Overflow, Position};
+use crate::style::{AvailableSpace, CoreStyle, LengthPercentageAuto, Overflow, Position};
 use crate::style_helpers::TaffyMaxContent;
 use crate::tree::{CollapsibleMarginSet, Layout, LayoutInput, LayoutOutput, RunMode, SizingMode};
 use crate::tree::{LayoutPartialTree, LayoutPartialTreeExt, NodeId};
@@ -9,6 +9,7 @@ use crate::util::sys::f32_max;
 use crate::util::sys::Vec;
 use crate::util::MaybeMath;
 use crate::util::{MaybeResolve, ResolveOrZero};
+use crate::{BoxGenerationMode, LayoutBlockContainer};
 
 #[cfg(feature = "content_size")]
 use super::common::content_size::compute_content_size_contribution;
@@ -56,25 +57,31 @@ struct BlockItem {
     can_be_collapsed_through: bool,
 }
 
-/// Computes the layout of [`LayoutPartialTree`] according to the block layout algorithm
-pub fn compute_block_layout(tree: &mut impl LayoutPartialTree, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput {
+/// Computes the layout of [`LayoutBlockContainer`] according to the block layout algorithm
+pub fn compute_block_layout(
+    tree: &mut impl LayoutBlockContainer,
+    node_id: NodeId,
+    inputs: LayoutInput,
+) -> LayoutOutput {
     let LayoutInput { known_dimensions, parent_size, available_space, run_mode, .. } = inputs;
-    let style = tree.get_style(node_id);
+    let style = tree.get_block_container_style(node_id);
 
     // Pull these out earlier to avoid borrowing issues
-    let aspect_ratio = style.aspect_ratio;
-    let margin = style.margin.resolve_or_zero(parent_size.width);
-    let min_size = style.min_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
-    let max_size = style.max_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
-    let padding = style.padding.resolve_or_zero(parent_size.width);
-    let border = style.border.resolve_or_zero(parent_size.width);
+    let aspect_ratio = style.aspect_ratio();
+    let margin = style.margin().resolve_or_zero(parent_size.width);
+    let min_size = style.min_size().maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
+    let max_size = style.max_size().maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
+    let padding = style.padding().resolve_or_zero(parent_size.width);
+    let border = style.border().resolve_or_zero(parent_size.width);
     let padding_border_size = (padding + border).sum_axes();
     let clamped_style_size = if inputs.sizing_mode == SizingMode::InherentSize {
-        style.size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio).maybe_clamp(min_size, max_size)
+        style.size().maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio).maybe_clamp(min_size, max_size)
     } else {
         Size::NONE
     };
 
+    drop(style);
+
     // If both min and max in a given axis are set and max <= min then this determines the size in that axis
     let min_max_definite_size = min_size.zip_map(max_size, |min, max| match (min, max) {
         (Some(min), Some(max)) if max <= min => Some(min),
@@ -103,29 +110,29 @@ pub fn compute_block_layout(tree: &mut impl LayoutPartialTree, node_id: NodeId,
     compute_inner(tree, node_id, LayoutInput { known_dimensions: styled_based_known_dimensions, ..inputs })
 }
 
-/// Computes the layout of [`LayoutPartialTree`] according to the block layout algorithm
-fn compute_inner(tree: &mut impl LayoutPartialTree, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput {
+/// Computes the layout of [`LayoutBlockContainer`] according to the block layout algorithm
+fn compute_inner(tree: &mut impl LayoutBlockContainer, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput {
     let LayoutInput {
         known_dimensions, parent_size, available_space, run_mode, vertical_margins_are_collapsible, ..
     } = inputs;
 
-    let style = tree.get_style(node_id);
-    let raw_padding = style.padding;
-    let raw_border = style.border;
-    let raw_margin = style.margin;
-    let aspect_ratio = style.aspect_ratio;
-    let size = style.size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
-    let min_size = style.min_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
-    let max_size = style.max_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
-    let padding = style.padding.resolve_or_zero(parent_size.width);
-    let border = style.border.resolve_or_zero(parent_size.width);
+    let style = tree.get_block_container_style(node_id);
+    let raw_padding = style.padding();
+    let raw_border = style.border();
+    let raw_margin = style.margin();
+    let aspect_ratio = style.aspect_ratio();
+    let size = style.size().maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
+    let min_size = style.min_size().maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
+    let max_size = style.max_size().maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
+    let padding = style.padding().resolve_or_zero(parent_size.width);
+    let border = style.border().resolve_or_zero(parent_size.width);
 
     // Scrollbar gutters are reserved when the `overflow` property is set to `Overflow::Scroll`.
     // However, the axis are switched (transposed) because a node that scrolls vertically needs
     // *horizontal* space to be reserved for a scrollbar
     let scrollbar_gutter = {
-        let offsets = style.overflow.transpose().map(|overflow| match overflow {
-            Overflow::Scroll => style.scrollbar_width,
+        let offsets = style.overflow().transpose().map(|overflow| match overflow {
+            Overflow::Scroll => style.scrollbar_width(),
             _ => 0.0,
         });
         // TODO: make side configurable based on the `direction` property
@@ -139,28 +146,30 @@ fn compute_inner(tree: &mut impl LayoutPartialTree, node_id: NodeId, inputs: Lay
     // Determine margin collapsing behaviour
     let own_margins_collapse_with_children = Line {
         start: vertical_margins_are_collapsible.start
-            && !style.overflow.x.is_scroll_container()
-            && !style.overflow.y.is_scroll_container()
-            && style.position == Position::Relative
+            && !style.overflow().x.is_scroll_container()
+            && !style.overflow().y.is_scroll_container()
+            && style.position() == Position::Relative
             && padding.top == 0.0
             && border.top == 0.0,
         end: vertical_margins_are_collapsible.end
-            && !style.overflow.x.is_scroll_container()
-            && !style.overflow.y.is_scroll_container()
-            && style.position == Position::Relative
+            && !style.overflow().x.is_scroll_container()
+            && !style.overflow().y.is_scroll_container()
+            && style.position() == Position::Relative
             && padding.bottom == 0.0
             && border.bottom == 0.0
             && size.height.is_none(),
     };
-    let has_styles_preventing_being_collapsed_through = style.display != Display::Block
-        || style.overflow.x.is_scroll_container()
-        || style.overflow.y.is_scroll_container()
-        || style.position == Position::Absolute
+    let has_styles_preventing_being_collapsed_through = false//style.display != Display::Block
+        || style.overflow().x.is_scroll_container()
+        || style.overflow().y.is_scroll_container()
+        || style.position() == Position::Absolute
         || padding.top > 0.0
         || padding.bottom > 0.0
         || border.top > 0.0
         || border.bottom > 0.0;
 
+    drop(style);
+
     // 1. Generate items
     let mut items = generate_item_list(tree, node_id, container_content_box_size);
 
@@ -212,7 +221,7 @@ fn compute_inner(tree: &mut impl LayoutPartialTree, node_id: NodeId, inputs: Lay
     let len = tree.child_count(node_id);
     for order in 0..len {
         let child = tree.get_child_id(node_id, order);
-        if tree.get_style(child).display == Display::None {
+        if tree.get_block_child_style(child).box_generation_mode() == BoxGenerationMode::None {
             tree.set_unrounded_layout(child, &Layout::with_order(order as u32));
             tree.perform_child_layout(
                 child,
@@ -258,30 +267,30 @@ fn compute_inner(tree: &mut impl LayoutPartialTree, node_id: NodeId, inputs: Lay
 /// Create a `Vec` of `BlockItem` structs where each item in the `Vec` represents a child of the current node
 #[inline]
 fn generate_item_list(
-    tree: &impl LayoutPartialTree,
+    tree: &impl LayoutBlockContainer,
     node: NodeId,
     node_inner_size: Size<Option<f32>>,
 ) -> Vec<BlockItem> {
     tree.child_ids(node)
-        .map(|child_node_id| (child_node_id, tree.get_style(child_node_id)))
-        .filter(|(_, style)| style.display != Display::None)
+        .map(|child_node_id| (child_node_id, tree.get_block_child_style(child_node_id)))
+        .filter(|(_, style)| style.box_generation_mode() != BoxGenerationMode::None)
         .enumerate()
         .map(|(order, (child_node_id, child_style))| {
-            let aspect_ratio = child_style.aspect_ratio;
-            let padding = child_style.padding.resolve_or_zero(node_inner_size);
-            let border = child_style.border.resolve_or_zero(node_inner_size);
+            let aspect_ratio = child_style.aspect_ratio();
+            let padding = child_style.padding().resolve_or_zero(node_inner_size);
+            let border = child_style.border().resolve_or_zero(node_inner_size);
             BlockItem {
                 node_id: child_node_id,
                 order: order as u32,
 
-                size: child_style.size.maybe_resolve(node_inner_size).maybe_apply_aspect_ratio(aspect_ratio),
-                min_size: child_style.min_size.maybe_resolve(node_inner_size).maybe_apply_aspect_ratio(aspect_ratio),
-                max_size: child_style.max_size.maybe_resolve(node_inner_size).maybe_apply_aspect_ratio(aspect_ratio),
-                overflow: child_style.overflow,
-                scrollbar_width: child_style.scrollbar_width,
-                position: child_style.position,
-                inset: child_style.inset,
-                margin: child_style.margin,
+                size: child_style.size().maybe_resolve(node_inner_size).maybe_apply_aspect_ratio(aspect_ratio),
+                min_size: child_style.min_size().maybe_resolve(node_inner_size).maybe_apply_aspect_ratio(aspect_ratio),
+                max_size: child_style.max_size().maybe_resolve(node_inner_size).maybe_apply_aspect_ratio(aspect_ratio),
+                overflow: child_style.overflow(),
+                scrollbar_width: child_style.scrollbar_width(),
+                position: child_style.position(),
+                inset: child_style.inset(),
+                margin: child_style.margin(),
                 padding,
                 border,
                 padding_border_sum: (padding + border).sum_axes(),
@@ -492,7 +501,7 @@ fn perform_final_layout_on_in_flow_children(
 /// Perform absolute layout on all absolutely positioned children.
 #[inline]
 fn perform_absolute_layout_on_absolute_children(
-    tree: &mut impl LayoutPartialTree,
+    tree: &mut impl LayoutBlockContainer,
     items: &[BlockItem],
     area_size: Size<f32>,
     area_offset: Point<f32>,
@@ -504,36 +513,39 @@ fn perform_absolute_layout_on_absolute_children(
     let mut absolute_content_size = Size::ZERO;
 
     for item in items.iter().filter(|item| item.position == Position::Absolute) {
-        let child_style = tree.get_style(item.node_id);
+        let child_style = tree.get_block_child_style(item.node_id);
 
         // Skip items that are display:none or are not position:absolute
-        if child_style.display == Display::None || child_style.position != Position::Absolute {
+        if child_style.box_generation_mode() == BoxGenerationMode::None || child_style.position() != Position::Absolute
+        {
             continue;
         }
 
-        let aspect_ratio = child_style.aspect_ratio;
-        let margin = child_style.margin.map(|margin| margin.resolve_to_option(area_width));
-        let padding = child_style.padding.resolve_or_zero(Some(area_width));
-        let border = child_style.border.resolve_or_zero(Some(area_width));
+        let aspect_ratio = child_style.aspect_ratio();
+        let margin = child_style.margin().map(|margin| margin.resolve_to_option(area_width));
+        let padding = child_style.padding().resolve_or_zero(Some(area_width));
+        let border = child_style.border().resolve_or_zero(Some(area_width));
         let padding_border_sum = (padding + border).sum_axes();
 
         // Resolve inset
-        let left = child_style.inset.left.maybe_resolve(area_width);
-        let right = child_style.inset.right.maybe_resolve(area_width);
-        let top = child_style.inset.top.maybe_resolve(area_height);
-        let bottom = child_style.inset.bottom.maybe_resolve(area_height);
+        let left = child_style.inset().left.maybe_resolve(area_width);
+        let right = child_style.inset().right.maybe_resolve(area_width);
+        let top = child_style.inset().top.maybe_resolve(area_height);
+        let bottom = child_style.inset().bottom.maybe_resolve(area_height);
 
         // Compute known dimensions from min/max/inherent size styles
-        let style_size = child_style.size.maybe_resolve(area_size).maybe_apply_aspect_ratio(aspect_ratio);
+        let style_size = child_style.size().maybe_resolve(area_size).maybe_apply_aspect_ratio(aspect_ratio);
         let min_size = child_style
-            .min_size
+            .min_size()
             .maybe_resolve(area_size)
             .maybe_apply_aspect_ratio(aspect_ratio)
             .or(padding_border_sum.map(Some))
             .maybe_max(padding_border_sum);
-        let max_size = child_style.max_size.maybe_resolve(area_size).maybe_apply_aspect_ratio(aspect_ratio);
+        let max_size = child_style.max_size().maybe_resolve(area_size).maybe_apply_aspect_ratio(aspect_ratio);
         let mut known_dimensions = style_size.maybe_clamp(min_size, max_size);
 
+        drop(child_style);
+
         // Fill in width from left/right and reapply aspect ratio if:
         //   - Width is not already known
         //   - Item has both left and right inset properties set
diff --git a/src/compute/flexbox.rs b/src/compute/flexbox.rs
index 67b094dfb..3812c82bb 100644
--- a/src/compute/flexbox.rs
+++ b/src/compute/flexbox.rs
@@ -2,17 +2,18 @@
 use crate::compute::common::alignment::compute_alignment_offset;
 use crate::geometry::{Line, Point, Rect, Size};
 use crate::style::{
-    AlignContent, AlignItems, AlignSelf, AvailableSpace, Dimension, Display, FlexWrap, JustifyContent,
-    LengthPercentageAuto, Overflow, Position,
+    AlignContent, AlignItems, AlignSelf, AvailableSpace, Dimension, FlexWrap, JustifyContent, LengthPercentageAuto,
+    Overflow, Position,
 };
-use crate::style::{FlexDirection, Style};
+use crate::style::{CoreStyle, FlexDirection, FlexboxContainerStyle, FlexboxItemStyle};
 use crate::style_helpers::{TaffyMaxContent, TaffyMinContent};
 use crate::tree::{Layout, LayoutInput, LayoutOutput, RunMode, SizingMode};
-use crate::tree::{LayoutPartialTree, LayoutPartialTreeExt, NodeId};
+use crate::tree::{LayoutFlexboxContainer, LayoutPartialTreeExt, NodeId};
 use crate::util::debug::debug_log;
 use crate::util::sys::{f32_max, new_vec_with_capacity, Vec};
 use crate::util::MaybeMath;
 use crate::util::{MaybeResolve, ResolveOrZero};
+use crate::BoxGenerationMode;
 
 use super::common::alignment::apply_alignment_fallback;
 #[cfg(feature = "content_size")]
@@ -153,23 +154,29 @@ struct AlgoConstants {
 }
 
 /// Computes the layout of [`LayoutPartialTree`] according to the flexbox algorithm
-pub fn compute_flexbox_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inputs: LayoutInput) -> LayoutOutput {
+pub fn compute_flexbox_layout(
+    tree: &mut impl LayoutFlexboxContainer,
+    node: NodeId,
+    inputs: LayoutInput,
+) -> LayoutOutput {
     let LayoutInput { known_dimensions, parent_size, run_mode, .. } = inputs;
-    let style = tree.get_style(node);
+    let style = tree.get_flexbox_container_style(node);
 
     // Pull these out earlier to avoid borrowing issues
-    let aspect_ratio = style.aspect_ratio;
-    let min_size = style.min_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
-    let max_size = style.max_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
-    let padding = style.padding.resolve_or_zero(parent_size.width);
-    let border = style.border.resolve_or_zero(parent_size.width);
+    let aspect_ratio = style.aspect_ratio();
+    let min_size = style.min_size().maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
+    let max_size = style.max_size().maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
+    let padding = style.padding().resolve_or_zero(parent_size.width);
+    let border = style.border().resolve_or_zero(parent_size.width);
     let padding_border_sum = padding.sum_axes() + border.sum_axes();
     let clamped_style_size = if inputs.sizing_mode == SizingMode::InherentSize {
-        style.size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio).maybe_clamp(min_size, max_size)
+        style.size().maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio).maybe_clamp(min_size, max_size)
     } else {
         Size::NONE
     };
 
+    drop(style);
+
     // If both min and max in a given axis are set and max <= min then this determines the size in that axis
     let min_max_definite_size = min_size.zip_map(max_size, |min, max| match (min, max) {
         (Some(min), Some(max)) if max <= min => Some(min),
@@ -193,11 +200,11 @@ pub fn compute_flexbox_layout(tree: &mut impl LayoutPartialTree, node: NodeId, i
 }
 
 /// Compute a preliminary size for an item
-fn compute_preliminary(tree: &mut impl LayoutPartialTree, node: NodeId, inputs: LayoutInput) -> LayoutOutput {
+fn compute_preliminary(tree: &mut impl LayoutFlexboxContainer, node: NodeId, inputs: LayoutInput) -> LayoutOutput {
     let LayoutInput { known_dimensions, parent_size, available_space, run_mode, .. } = inputs;
 
     // Define some general constants we will need for the remainder of the algorithm.
-    let mut constants = compute_constants(tree.get_style(node), known_dimensions, parent_size);
+    let mut constants = compute_constants(tree.get_flexbox_container_style(node), known_dimensions, parent_size);
 
     // 9. Flex Layout Algorithm
 
@@ -253,9 +260,9 @@ fn compute_preliminary(tree: &mut impl LayoutPartialTree, node: NodeId, inputs:
         debug_log!("constants.node_inner_size", dbg:constants.node_inner_size);
 
         // Re-resolve percentage gaps
-        let style = tree.get_style(node);
+        let style = tree.get_flexbox_container_style(node);
         let inner_container_size = constants.inner_container_size.main(constants.dir);
-        let new_gap = style.gap.main(constants.dir).maybe_resolve(inner_container_size).unwrap_or(0.0);
+        let new_gap = style.gap().main(constants.dir).maybe_resolve(inner_container_size).unwrap_or(0.0);
         constants.gap.set_main(constants.dir, new_gap);
     }
 
@@ -343,7 +350,7 @@ fn compute_preliminary(tree: &mut impl LayoutPartialTree, node: NodeId, inputs:
     let len = tree.child_count(node);
     for order in 0..len {
         let child = tree.get_child_id(node, order);
-        if tree.get_style(child).display == Display::None {
+        if tree.get_flexbox_child_style(child).box_generation_mode() == BoxGenerationMode::None {
             tree.set_unrounded_layout(child, &Layout::with_order(order as u32));
             tree.perform_child_layout(
                 child,
@@ -382,29 +389,29 @@ fn compute_preliminary(tree: &mut impl LayoutPartialTree, node: NodeId, inputs:
 /// Compute constants that can be reused during the flexbox algorithm.
 #[inline]
 fn compute_constants(
-    style: &Style,
+    style: impl FlexboxContainerStyle,
     known_dimensions: Size<Option<f32>>,
     parent_size: Size<Option<f32>>,
 ) -> AlgoConstants {
-    let dir = style.flex_direction;
+    let dir = style.flex_direction();
     let is_row = dir.is_row();
     let is_column = dir.is_column();
-    let is_wrap = matches!(style.flex_wrap, FlexWrap::Wrap | FlexWrap::WrapReverse);
-    let is_wrap_reverse = style.flex_wrap == FlexWrap::WrapReverse;
+    let is_wrap = matches!(style.flex_wrap(), FlexWrap::Wrap | FlexWrap::WrapReverse);
+    let is_wrap_reverse = style.flex_wrap() == FlexWrap::WrapReverse;
 
-    let aspect_ratio = style.aspect_ratio;
-    let margin = style.margin.resolve_or_zero(parent_size.width);
-    let padding = style.padding.resolve_or_zero(parent_size.width);
-    let border = style.border.resolve_or_zero(parent_size.width);
-    let align_items = style.align_items.unwrap_or(AlignItems::Stretch);
-    let align_content = style.align_content.unwrap_or(AlignContent::Stretch);
-    let justify_content = style.justify_content;
+    let aspect_ratio = style.aspect_ratio();
+    let margin = style.margin().resolve_or_zero(parent_size.width);
+    let padding = style.padding().resolve_or_zero(parent_size.width);
+    let border = style.border().resolve_or_zero(parent_size.width);
+    let align_items = style.align_items().unwrap_or(AlignItems::Stretch);
+    let align_content = style.align_content().unwrap_or(AlignContent::Stretch);
+    let justify_content = style.justify_content();
 
     // Scrollbar gutters are reserved when the `overflow` property is set to `Overflow::Scroll`.
     // However, the axis are switched (transposed) because a node that scrolls vertically needs
     // *horizontal* space to be reserved for a scrollbar
-    let scrollbar_gutter = style.overflow.transpose().map(|overflow| match overflow {
-        Overflow::Scroll => style.scrollbar_width,
+    let scrollbar_gutter = style.overflow().transpose().map(|overflow| match overflow {
+        Overflow::Scroll => style.scrollbar_width(),
         _ => 0.0,
     });
     // TODO: make side configurable based on the `direction` property
@@ -414,7 +421,7 @@ fn compute_constants(
 
     let node_outer_size = known_dimensions;
     let node_inner_size = node_outer_size.maybe_sub(content_box_inset.sum_axes());
-    let gap = style.gap.resolve_or_zero(node_inner_size.or(Size::zero()));
+    let gap = style.gap().resolve_or_zero(node_inner_size.or(Size::zero()));
 
     let container_size = Size::zero();
     let inner_container_size = Size::zero();
@@ -425,8 +432,8 @@ fn compute_constants(
         is_column,
         is_wrap,
         is_wrap_reverse,
-        min_size: style.min_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio),
-        max_size: style.max_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio),
+        min_size: style.min_size().maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio),
+        max_size: style.max_size().maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio),
         margin,
         border,
         gap,
@@ -449,40 +456,43 @@ fn compute_constants(
 /// - [**Generate anonymous flex items**](https://www.w3.org/TR/css-flexbox-1/#algo-anon-box) as described in [§4 Flex Items](https://www.w3.org/TR/css-flexbox-1/#flex-items).
 #[inline]
 fn generate_anonymous_flex_items(
-    tree: &impl LayoutPartialTree,
+    tree: &impl LayoutFlexboxContainer,
     node: NodeId,
     constants: &AlgoConstants,
 ) -> Vec<FlexItem> {
     tree.child_ids(node)
         .enumerate()
-        .map(|(index, child)| (index, child, tree.get_style(child)))
-        .filter(|(_, _, style)| style.position != Position::Absolute)
-        .filter(|(_, _, style)| style.display != Display::None)
+        .map(|(index, child)| (index, child, tree.get_flexbox_child_style(child)))
+        .filter(|(_, _, style)| style.position() != Position::Absolute)
+        .filter(|(_, _, style)| style.box_generation_mode() != BoxGenerationMode::None)
         .map(|(index, child, child_style)| {
-            let aspect_ratio = child_style.aspect_ratio;
+            let aspect_ratio = child_style.aspect_ratio();
             FlexItem {
                 node: child,
                 order: index as u32,
-                size: child_style.size.maybe_resolve(constants.node_inner_size).maybe_apply_aspect_ratio(aspect_ratio),
+                size: child_style
+                    .size()
+                    .maybe_resolve(constants.node_inner_size)
+                    .maybe_apply_aspect_ratio(aspect_ratio),
                 min_size: child_style
-                    .min_size
+                    .min_size()
                     .maybe_resolve(constants.node_inner_size)
                     .maybe_apply_aspect_ratio(aspect_ratio),
                 max_size: child_style
-                    .max_size
+                    .max_size()
                     .maybe_resolve(constants.node_inner_size)
                     .maybe_apply_aspect_ratio(aspect_ratio),
 
-                inset: child_style.inset.zip_size(constants.node_inner_size, |p, s| p.maybe_resolve(s)),
-                margin: child_style.margin.resolve_or_zero(constants.node_inner_size.width),
-                margin_is_auto: child_style.margin.map(|m| m == LengthPercentageAuto::Auto),
-                padding: child_style.padding.resolve_or_zero(constants.node_inner_size.width),
-                border: child_style.border.resolve_or_zero(constants.node_inner_size.width),
-                align_self: child_style.align_self.unwrap_or(constants.align_items),
-                overflow: child_style.overflow,
-                scrollbar_width: child_style.scrollbar_width,
-                flex_grow: child_style.flex_grow,
-                flex_shrink: child_style.flex_shrink,
+                inset: child_style.inset().zip_size(constants.node_inner_size, |p, s| p.maybe_resolve(s)),
+                margin: child_style.margin().resolve_or_zero(constants.node_inner_size.width),
+                margin_is_auto: child_style.margin().map(|m| m == LengthPercentageAuto::Auto),
+                padding: child_style.padding().resolve_or_zero(constants.node_inner_size.width),
+                border: child_style.border().resolve_or_zero(constants.node_inner_size.width),
+                align_self: child_style.align_self().unwrap_or(constants.align_items),
+                overflow: child_style.overflow(),
+                scrollbar_width: child_style.scrollbar_width(),
+                flex_grow: child_style.flex_grow(),
+                flex_shrink: child_style.flex_shrink(),
                 flex_basis: 0.0,
                 inner_flex_basis: 0.0,
                 violation: 0.0,
@@ -570,7 +580,7 @@ fn determine_available_space(
 ///     (For example, an item with a specified size of zero, positive padding, and box-sizing: border-box will have an outer flex base size of zero—and hence a negative inner flex base size.)
 #[inline]
 fn determine_flex_base_size(
-    tree: &mut impl LayoutPartialTree,
+    tree: &mut impl LayoutFlexboxContainer,
     constants: &AlgoConstants,
     available_space: Size<AvailableSpace>,
     flex_items: &mut [FlexItem],
@@ -578,7 +588,8 @@ fn determine_flex_base_size(
     let dir = constants.dir;
 
     for child in flex_items.iter_mut() {
-        let child_style = tree.get_style(child.node);
+        let child_style = tree.get_flexbox_child_style(child.node);
+        let flex_basis = child_style.flex_basis().maybe_resolve(constants.node_inner_size.main(dir));
 
         // Parent size for child sizing
         let cross_axis_parent_size = constants.node_inner_size.cross(dir);
@@ -605,6 +616,8 @@ fn determine_flex_base_size(
             ckd
         };
 
+        drop(child_style);
+
         child.flex_basis = 'flex_basis: {
             // A. If the item has a definite used flex basis, that’s the flex base size.
 
@@ -616,7 +629,6 @@ fn determine_flex_base_size(
             // Note: `child.size` has already been resolved against aspect_ratio in generate_anonymous_flex_items
             // So B will just work here by using main_size without special handling for aspect_ratio
 
-            let flex_basis = child_style.flex_basis.maybe_resolve(constants.node_inner_size.main(dir));
             let main_size = child.size.main(dir);
             if let Some(flex_basis) = flex_basis.or(main_size) {
                 break 'flex_basis flex_basis;
@@ -810,7 +822,7 @@ fn collect_flex_lines<'a>(
 
 /// Determine the container's main size (if not already known)
 fn determine_container_main_size(
-    tree: &mut impl LayoutPartialTree,
+    tree: &mut impl LayoutFlexboxContainer,
     available_space: Size<AvailableSpace>,
     lines: &mut [FlexLine<'_>],
     constants: &mut AlgoConstants,
@@ -1216,7 +1228,7 @@ fn resolve_flexible_lengths(line: &mut FlexLine, constants: &AlgoConstants, orig
 ///     by performing layout with the used main size and the available space, treating auto as fit-content.
 #[inline]
 fn determine_hypothetical_cross_size(
-    tree: &mut impl LayoutPartialTree,
+    tree: &mut impl LayoutFlexboxContainer,
     line: &mut FlexLine,
     constants: &AlgoConstants,
     available_space: Size<AvailableSpace>,
@@ -1266,7 +1278,7 @@ fn determine_hypothetical_cross_size(
 /// Calculate the base lines of the children.
 #[inline]
 fn calculate_children_base_lines(
-    tree: &mut impl LayoutPartialTree,
+    tree: &mut impl LayoutFlexboxContainer,
     node_size: Size<Option<f32>>,
     available_space: Size<AvailableSpace>,
     flex_lines: &mut [FlexLine],
@@ -1461,23 +1473,28 @@ fn handle_align_content_stretch(flex_lines: &mut [FlexLine], node_size: Size<Opt
 ///
 ///     **Note that this step does not affect the main size of the flex item, even if it has an intrinsic aspect ratio**.
 #[inline]
-fn determine_used_cross_size(tree: &impl LayoutPartialTree, flex_lines: &mut [FlexLine], constants: &AlgoConstants) {
+fn determine_used_cross_size(
+    tree: &impl LayoutFlexboxContainer,
+    flex_lines: &mut [FlexLine],
+    constants: &AlgoConstants,
+) {
     for line in flex_lines {
         let line_cross_size = line.cross_size;
 
         for child in line.items.iter_mut() {
-            let child_style = tree.get_style(child.node);
+            let child_style = tree.get_flexbox_child_style(child.node);
             child.target_size.set_cross(
                 constants.dir,
                 if child.align_self == AlignSelf::Stretch
                     && !child.margin_is_auto.cross_start(constants.dir)
                     && !child.margin_is_auto.cross_end(constants.dir)
-                    && child_style.size.cross(constants.dir) == Dimension::Auto
+                    && child_style.size().cross(constants.dir) == Dimension::Auto
                 {
                     // For some reason this particular usage of max_width is an exception to the rule that max_width's transfer
                     // using the aspect_ratio (if set). Both Chrome and Firefox agree on this. And reading the spec, it seems like
                     // a reasonable interpretation. Although it seems to me that the spec *should* apply aspect_ratio here.
-                    let max_size_ignoring_aspect_ratio = child_style.max_size.maybe_resolve(constants.node_inner_size);
+                    let max_size_ignoring_aspect_ratio =
+                        child_style.max_size().maybe_resolve(constants.node_inner_size);
 
                     (line_cross_size - child.margin.cross_axis_sum(constants.dir)).maybe_clamp(
                         child.min_size.cross(constants.dir),
@@ -1735,7 +1752,7 @@ fn align_flex_lines_per_align_content(flex_lines: &mut [FlexLine], constants: &A
 /// Calculates the layout for a flex-item
 #[allow(clippy::too_many_arguments)]
 fn calculate_flex_item(
-    tree: &mut impl LayoutPartialTree,
+    tree: &mut impl LayoutFlexboxContainer,
     item: &mut FlexItem,
     total_offset_main: &mut f32,
     total_offset_cross: f32,
@@ -1816,7 +1833,7 @@ fn calculate_flex_item(
 /// Calculates the layout line
 #[allow(clippy::too_many_arguments)]
 fn calculate_layout_line(
-    tree: &mut impl LayoutPartialTree,
+    tree: &mut impl LayoutFlexboxContainer,
     line: &mut FlexLine,
     total_offset_cross: &mut f32,
     #[cfg(feature = "content_size")] content_size: &mut Size<f32>,
@@ -1866,7 +1883,7 @@ fn calculate_layout_line(
 /// Do a final layout pass and collect the resulting layouts.
 #[inline]
 fn final_layout_pass(
-    tree: &mut impl LayoutPartialTree,
+    tree: &mut impl LayoutFlexboxContainer,
     flex_lines: &mut [FlexLine],
     constants: &AlgoConstants,
 ) -> Size<f32> {
@@ -1911,7 +1928,7 @@ fn final_layout_pass(
 /// Perform absolute layout on all absolutely positioned children.
 #[inline]
 fn perform_absolute_layout_on_absolute_children(
-    tree: &mut impl LayoutPartialTree,
+    tree: &mut impl LayoutFlexboxContainer,
     node: NodeId,
     constants: &AlgoConstants,
 ) -> Size<f32> {
@@ -1923,41 +1940,44 @@ fn perform_absolute_layout_on_absolute_children(
 
     for order in 0..tree.child_count(node) {
         let child = tree.get_child_id(node, order);
-        let child_style = tree.get_style(child);
+        let child_style = tree.get_flexbox_child_style(child);
 
         // Skip items that are display:none or are not position:absolute
-        if child_style.display == Display::None || child_style.position != Position::Absolute {
+        if child_style.box_generation_mode() == BoxGenerationMode::None || child_style.position() != Position::Absolute
+        {
             continue;
         }
 
-        let overflow = child_style.overflow;
-        let scrollbar_width = child_style.scrollbar_width;
-        let aspect_ratio = child_style.aspect_ratio;
-        let align_self = child_style.align_self.unwrap_or(constants.align_items);
-        let margin = child_style.margin.map(|margin| margin.resolve_to_option(container_width));
-        let padding = child_style.padding.resolve_or_zero(Some(container_width));
-        let border = child_style.border.resolve_or_zero(Some(container_width));
+        let overflow = child_style.overflow();
+        let scrollbar_width = child_style.scrollbar_width();
+        let aspect_ratio = child_style.aspect_ratio();
+        let align_self = child_style.align_self().unwrap_or(constants.align_items);
+        let margin = child_style.margin().map(|margin| margin.resolve_to_option(container_width));
+        let padding = child_style.padding().resolve_or_zero(Some(container_width));
+        let border = child_style.border().resolve_or_zero(Some(container_width));
         let padding_border_sum = (padding + border).sum_axes();
 
         // Resolve inset
-        let left = child_style.inset.left.maybe_resolve(container_width);
-        let right = child_style.inset.right.maybe_resolve(container_width);
-        let top = child_style.inset.top.maybe_resolve(container_height);
-        let bottom = child_style.inset.bottom.maybe_resolve(container_height);
+        let left = child_style.inset().left.maybe_resolve(container_width);
+        let right = child_style.inset().right.maybe_resolve(container_width);
+        let top = child_style.inset().top.maybe_resolve(container_height);
+        let bottom = child_style.inset().bottom.maybe_resolve(container_height);
 
         // Compute known dimensions from min/max/inherent size styles
         let style_size =
-            child_style.size.maybe_resolve(constants.container_size).maybe_apply_aspect_ratio(aspect_ratio);
+            child_style.size().maybe_resolve(constants.container_size).maybe_apply_aspect_ratio(aspect_ratio);
         let min_size = child_style
-            .min_size
+            .min_size()
             .maybe_resolve(constants.container_size)
             .maybe_apply_aspect_ratio(aspect_ratio)
             .or(padding_border_sum.map(Some))
             .maybe_max(padding_border_sum);
         let max_size =
-            child_style.max_size.maybe_resolve(constants.container_size).maybe_apply_aspect_ratio(aspect_ratio);
+            child_style.max_size().maybe_resolve(constants.container_size).maybe_apply_aspect_ratio(aspect_ratio);
         let mut known_dimensions = style_size.maybe_clamp(min_size, max_size);
 
+        drop(child_style);
+
         // Fill in width from left/right and reapply aspect ratio if:
         //   - Width is not already known
         //   - Item has both left and right inset properties set
@@ -1975,7 +1995,6 @@ fn perform_absolute_layout_on_absolute_children(
             known_dimensions.height = Some(f32_max(new_height_raw, 0.0));
             known_dimensions = known_dimensions.maybe_apply_aspect_ratio(aspect_ratio).maybe_clamp(min_size, max_size);
         }
-
         let layout_output = tree.perform_child_layout(
             child,
             known_dimensions,
diff --git a/src/compute/grid/alignment.rs b/src/compute/grid/alignment.rs
index 04a0e3b40..ad2bbf48b 100644
--- a/src/compute/grid/alignment.rs
+++ b/src/compute/grid/alignment.rs
@@ -2,13 +2,14 @@
 use super::types::GridTrack;
 use crate::compute::common::alignment::{apply_alignment_fallback, compute_alignment_offset};
 use crate::geometry::{InBothAbsAxis, Line, Point, Rect, Size};
-use crate::style::{AlignContent, AlignItems, AlignSelf, AvailableSpace, Overflow, Position};
-use crate::tree::{Layout, LayoutPartialTree, LayoutPartialTreeExt, NodeId, SizingMode};
+use crate::style::{AlignContent, AlignItems, AlignSelf, AvailableSpace, CoreStyle, GridItemStyle, Overflow, Position};
+use crate::tree::{Layout, LayoutPartialTreeExt, NodeId, SizingMode};
 use crate::util::sys::f32_max;
 use crate::util::{MaybeMath, MaybeResolve, ResolveOrZero};
 
 #[cfg(feature = "content_size")]
 use crate::compute::common::content_size::compute_content_size_contribution;
+use crate::LayoutGridContainer;
 
 /// Align the grid tracks within the grid according to the align-content (rows) or
 /// justify-content (columns) property. This only does anything if the size of the
@@ -56,7 +57,7 @@ pub(super) fn align_tracks(
 
 /// Align and size a grid item into it's final position
 pub(super) fn align_and_position_item(
-    tree: &mut impl LayoutPartialTree,
+    tree: &mut impl LayoutGridContainer,
     node: NodeId,
     order: u32,
     grid_area: Rect<f32>,
@@ -65,28 +66,29 @@ pub(super) fn align_and_position_item(
 ) -> (Size<f32>, f32, f32) {
     let grid_area_size = Size { width: grid_area.right - grid_area.left, height: grid_area.bottom - grid_area.top };
 
-    let style = tree.get_style(node);
+    let style = tree.get_grid_child_style(node);
 
-    let overflow = style.overflow;
-    let scrollbar_width = style.scrollbar_width;
-    let aspect_ratio = style.aspect_ratio;
-    let justify_self = style.justify_self;
-    let align_self = style.align_self;
+    let overflow = style.overflow();
+    let scrollbar_width = style.scrollbar_width();
+    let aspect_ratio = style.aspect_ratio();
+    let justify_self = style.justify_self();
+    let align_self = style.align_self();
 
-    let position = style.position;
-    let inset_horizontal = style.inset.horizontal_components().map(|size| size.resolve_to_option(grid_area_size.width));
-    let inset_vertical = style.inset.vertical_components().map(|size| size.resolve_to_option(grid_area_size.height));
-    let padding = style.padding.map(|p| p.resolve_or_zero(Some(grid_area_size.width)));
-    let border = style.border.map(|p| p.resolve_or_zero(Some(grid_area_size.width)));
+    let position = style.position();
+    let inset_horizontal =
+        style.inset().horizontal_components().map(|size| size.resolve_to_option(grid_area_size.width));
+    let inset_vertical = style.inset().vertical_components().map(|size| size.resolve_to_option(grid_area_size.height));
+    let padding = style.padding().map(|p| p.resolve_or_zero(Some(grid_area_size.width)));
+    let border = style.border().map(|p| p.resolve_or_zero(Some(grid_area_size.width)));
     let padding_border_size = (padding + border).sum_axes();
-    let inherent_size = style.size.maybe_resolve(grid_area_size).maybe_apply_aspect_ratio(aspect_ratio);
+    let inherent_size = style.size().maybe_resolve(grid_area_size).maybe_apply_aspect_ratio(aspect_ratio);
     let min_size = style
-        .min_size
+        .min_size()
         .maybe_resolve(grid_area_size)
         .or(padding_border_size.map(Some))
         .maybe_max(padding_border_size)
         .maybe_apply_aspect_ratio(aspect_ratio);
-    let max_size = style.max_size.maybe_resolve(grid_area_size).maybe_apply_aspect_ratio(aspect_ratio);
+    let max_size = style.max_size().maybe_resolve(grid_area_size).maybe_apply_aspect_ratio(aspect_ratio);
 
     // Resolve default alignment styles if they are set on neither the parent or the node itself
     // Note: if the child has a preferred aspect ratio but neither width or height are set, then the width is stretched
@@ -111,7 +113,7 @@ pub(super) fn align_and_position_item(
 
     // Note: This is not a bug. It is part of the CSS spec that both horizontal and vertical margins
     // resolve against the WIDTH of the grid area.
-    let margin = style.margin.map(|margin| margin.resolve_to_option(grid_area_size.width));
+    let margin = style.margin().map(|margin| margin.resolve_to_option(grid_area_size.width));
 
     let grid_area_minus_item_margins_size = Size {
         width: grid_area_size.width.maybe_sub(margin.left).maybe_sub(margin.right),
@@ -175,6 +177,7 @@ pub(super) fn align_and_position_item(
     let Size { width, height } = Size { width, height }.maybe_clamp(min_size, max_size);
 
     // Layout node
+    drop(style);
     let layout_output = tree.perform_child_layout(
         node,
         Size { width, height },
diff --git a/src/compute/grid/explicit_grid.rs b/src/compute/grid/explicit_grid.rs
index 76ff737bf..fb05dbadf 100644
--- a/src/compute/grid/explicit_grid.rs
+++ b/src/compute/grid/explicit_grid.rs
@@ -2,18 +2,19 @@
 //! This mainly consists of evaluating GridAutoTracks
 use super::types::{GridTrack, TrackCounts};
 use crate::geometry::{AbsoluteAxis, Size};
-use crate::style::{GridTrackRepetition, LengthPercentage, NonRepeatedTrackSizingFunction, Style, TrackSizingFunction};
+use crate::style::{GridTrackRepetition, LengthPercentage, NonRepeatedTrackSizingFunction, TrackSizingFunction};
 use crate::style_helpers::TaffyAuto;
-use crate::util::sys::{GridTrackVec, Vec};
+use crate::util::sys::Vec;
 use crate::util::MaybeMath;
 use crate::util::ResolveOrZero;
+use crate::GridContainerStyle;
 
 #[cfg(not(feature = "std"))]
 use num_traits::float::FloatCore;
 
 /// Compute the number of rows and columns in the explicit grid
 pub(crate) fn compute_explicit_grid_size_in_axis(
-    style: &Style,
+    style: &impl GridContainerStyle,
     preferred_size: Size<Option<f32>>,
     axis: AbsoluteAxis,
 ) -> u16 {
@@ -93,13 +94,13 @@ pub(crate) fn compute_explicit_grid_size_in_axis(
     //   - then the number of repetitions is the smallest possible positive integer that fulfills that minimum requirement
     // Otherwise, the specified track list repeats only once.
     let style_size = preferred_size.get_abs(axis);
-    let style_min_size = style.min_size.get_abs(axis).into_option();
-    let style_max_size = style.max_size.get_abs(axis).into_option();
+    let style_min_size = style.min_size().get_abs(axis).into_option();
+    let style_max_size = style.max_size().get_abs(axis).into_option();
 
     let outer_container_size = style_size.maybe_min(style_max_size).or(style_max_size).or(style_min_size);
     let inner_container_size = outer_container_size.map(|size| {
-        let padding_sum = style.padding.resolve_or_zero(outer_container_size).grid_axis_sum(axis);
-        let border_sum = style.border.resolve_or_zero(outer_container_size).grid_axis_sum(axis);
+        let padding_sum = style.padding().resolve_or_zero(outer_container_size).grid_axis_sum(axis);
+        let border_sum = style.border().resolve_or_zero(outer_container_size).grid_axis_sum(axis);
         size - padding_sum - border_sum
     });
     let size_is_maximum = style_size.is_some() || style_max_size.is_some();
@@ -137,7 +138,7 @@ pub(crate) fn compute_explicit_grid_size_in_axis(
                     }
                 })
                 .sum();
-            let gap_size = style.gap.get_abs(axis).resolve_or_zero(Some(inner_container_size));
+            let gap_size = style.gap().get_abs(axis).resolve_or_zero(Some(inner_container_size));
 
             // Compute the amount of space that a single repetition of the repeated track list takes
             let per_repetition_track_used_space: f32 = repetition_definition
@@ -185,7 +186,7 @@ pub(crate) fn compute_explicit_grid_size_in_axis(
 pub(super) fn initialize_grid_tracks(
     tracks: &mut Vec<GridTrack>,
     counts: TrackCounts,
-    track_template: &GridTrackVec<TrackSizingFunction>,
+    track_template: &[TrackSizingFunction],
     auto_tracks: &[NonRepeatedTrackSizingFunction],
     gap: LengthPercentage,
     track_has_items: impl Fn(usize) -> bool,
diff --git a/src/compute/grid/implicit_grid.rs b/src/compute/grid/implicit_grid.rs
index 1836cbb5b..d1651218b 100644
--- a/src/compute/grid/implicit_grid.rs
+++ b/src/compute/grid/implicit_grid.rs
@@ -1,7 +1,8 @@
 //! This module is not required for spec compliance, but is used as a performance optimisation
 //! to reduce the number of allocations required when creating a grid.
 use crate::geometry::Line;
-use crate::style::{GenericGridPlacement, GridPlacement, Style};
+use crate::style::{GenericGridPlacement, GridPlacement};
+use crate::GridItemStyle;
 use core::cmp::{max, min};
 
 use super::types::TrackCounts;
@@ -15,10 +16,10 @@ use super::OriginZeroLine;
 ///     in ways which are impossible to predict until the auto-placement algorithm is run.
 ///
 /// Note that this function internally mixes use of grid track numbers and grid line numbers
-pub(crate) fn compute_grid_size_estimate<'a>(
+pub(crate) fn compute_grid_size_estimate<'a, S: GridItemStyle + 'a>(
     explicit_col_count: u16,
     explicit_row_count: u16,
-    child_styles_iter: impl Iterator<Item = &'a Style>,
+    child_styles_iter: impl Iterator<Item = S>,
 ) -> (TrackCounts, TrackCounts) {
     // Iterate over children, producing an estimate of the min and max grid lines (in origin-zero coordinates where)
     // along with the span of each item
@@ -60,20 +61,20 @@ pub(crate) fn compute_grid_size_estimate<'a>(
 ///
 /// Min and max grid lines are returned in origin-zero coordinates)
 /// The span is measured in tracks spanned
-fn get_known_child_positions<'a>(
-    children_iter: impl Iterator<Item = &'a Style>,
+fn get_known_child_positions<'a, S: GridItemStyle + 'a>(
+    children_iter: impl Iterator<Item = S>,
     explicit_col_count: u16,
     explicit_row_count: u16,
 ) -> (OriginZeroLine, OriginZeroLine, u16, OriginZeroLine, OriginZeroLine, u16) {
     let (mut col_min, mut col_max, mut col_max_span) = (OriginZeroLine(0), OriginZeroLine(0), 0);
     let (mut row_min, mut row_max, mut row_max_span) = (OriginZeroLine(0), OriginZeroLine(0), 0);
-    children_iter.for_each(|child_style: &Style| {
+    children_iter.for_each(|child_style| {
         // Note: that the children reference the lines in between (and around) the tracks not tracks themselves,
         // and thus we must subtract 1 to get an accurate estimate of the number of tracks
         let (child_col_min, child_col_max, child_col_span) =
-            child_min_line_max_line_span(child_style.grid_column, explicit_col_count);
+            child_min_line_max_line_span(child_style.grid_column(), explicit_col_count);
         let (child_row_min, child_row_max, child_row_span) =
-            child_min_line_max_line_span(child_style.grid_row, explicit_row_count);
+            child_min_line_max_line_span(child_style.grid_row(), explicit_row_count);
         col_min = min(col_min, child_col_min);
         col_max = max(col_max, child_col_max);
         col_max_span = max(col_max_span, child_col_span);
diff --git a/src/compute/grid/mod.rs b/src/compute/grid/mod.rs
index cc755769e..eec788bab 100644
--- a/src/compute/grid/mod.rs
+++ b/src/compute/grid/mod.rs
@@ -2,14 +2,14 @@
 //! <https://www.w3.org/TR/css-grid-1>
 use crate::geometry::{AbsoluteAxis, AbstractAxis, InBothAbsAxis};
 use crate::geometry::{Line, Point, Rect, Size};
-use crate::style::{AlignContent, AlignItems, AlignSelf, AvailableSpace, Display, Overflow, Position};
-use crate::style_helpers::*;
-use crate::tree::{Layout, LayoutInput, LayoutOutput, RunMode, SizingMode};
-use crate::tree::{LayoutPartialTree, LayoutPartialTreeExt, NodeId};
+use crate::style::{AlignContent, AlignItems, AlignSelf, AvailableSpace, Overflow, Position};
+use crate::tree::{Layout, LayoutPartialTreeExt, NodeId};
+use crate::tree::{LayoutInput, LayoutOutput, RunMode, SizingMode};
 use crate::util::debug::debug_log;
 use crate::util::sys::{f32_max, GridTrackVec, Vec};
 use crate::util::MaybeMath;
 use crate::util::{MaybeResolve, ResolveOrZero};
+use crate::{style_helpers::*, BoxGenerationMode, CoreStyle, GridContainerStyle, GridItemStyle, LayoutGridContainer};
 use alignment::{align_and_position_item, align_tracks};
 use explicit_grid::{compute_explicit_grid_size_in_axis, initialize_grid_tracks};
 use implicit_grid::compute_grid_size_estimate;
@@ -35,15 +35,16 @@ mod util;
 ///   - Placing items (which also resolves the implicit grid)
 ///   - Track (row/column) sizing
 ///   - Alignment & Final item placement
-pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inputs: LayoutInput) -> LayoutOutput {
+pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, inputs: LayoutInput) -> LayoutOutput {
     let LayoutInput { known_dimensions, parent_size, available_space, run_mode, .. } = inputs;
 
-    let get_child_styles_iter = |node| tree.child_ids(node).map(|child_node: NodeId| tree.get_style(child_node));
-    let style = tree.get_style(node).clone();
+    let get_child_styles_iter =
+        |node| tree.child_ids(node).map(|child_node: NodeId| tree.get_grid_child_style(child_node));
+    let style = tree.get_grid_container_style(node).clone();
     let child_styles_iter = get_child_styles_iter(node);
 
     let preferred_size = if inputs.sizing_mode == SizingMode::InherentSize {
-        style.size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(style.aspect_ratio)
+        style.size().maybe_resolve(parent_size).maybe_apply_aspect_ratio(style.aspect_ratio())
     } else {
         Size::NONE
     };
@@ -66,16 +67,18 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu
     let in_flow_children_iter = || {
         tree.child_ids(node)
             .enumerate()
-            .map(|(index, child_node)| (index, child_node, tree.get_style(child_node)))
-            .filter(|(_, _, style)| style.display != Display::None && style.position != Position::Absolute)
+            .map(|(index, child_node)| (index, child_node, tree.get_grid_child_style(child_node)))
+            .filter(|(_, _, style)| {
+                style.box_generation_mode() != BoxGenerationMode::None && style.position() != Position::Absolute
+            })
     };
     place_grid_items(
         &mut cell_occupancy_matrix,
         &mut items,
         in_flow_children_iter,
-        style.grid_auto_flow,
-        style.align_items.unwrap_or(AlignItems::Stretch),
-        style.justify_items.unwrap_or(AlignItems::Stretch),
+        style.grid_auto_flow(),
+        style.align_items().unwrap_or(AlignItems::Stretch),
+        style.justify_items().unwrap_or(AlignItems::Stretch),
     );
 
     // Extract track counts from previous step (auto-placement can expand the number of tracks)
@@ -90,36 +93,36 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu
     initialize_grid_tracks(
         &mut columns,
         final_col_counts,
-        &style.grid_template_columns,
-        &style.grid_auto_columns,
-        style.gap.width,
+        style.grid_template_columns(),
+        style.grid_auto_columns(),
+        style.gap().width,
         |column_index| cell_occupancy_matrix.column_is_occupied(column_index),
     );
     initialize_grid_tracks(
         &mut rows,
         final_row_counts,
-        &style.grid_template_rows,
-        &style.grid_auto_rows,
-        style.gap.height,
+        style.grid_template_rows(),
+        style.grid_auto_rows(),
+        style.gap().height,
         |row_index| cell_occupancy_matrix.row_is_occupied(row_index),
     );
 
     // 4. Compute "available grid space"
     // https://www.w3.org/TR/css-grid-1/#available-grid-space
-    let padding = style.padding.resolve_or_zero(parent_size.width);
-    let border = style.border.resolve_or_zero(parent_size.width);
+    let padding = style.padding().resolve_or_zero(parent_size.width);
+    let border = style.border().resolve_or_zero(parent_size.width);
     let padding_border = padding + border;
     let padding_border_size = padding_border.sum_axes();
-    let aspect_ratio = style.aspect_ratio;
-    let min_size = style.min_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
-    let max_size = style.max_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
+    let aspect_ratio = style.aspect_ratio();
+    let min_size = style.min_size().maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
+    let max_size = style.max_size().maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
     let size = preferred_size;
 
     // Scrollbar gutters are reserved when the `overflow` property is set to `Overflow::Scroll`.
     // However, the axis are switched (transposed) because a node that scrolls vertically needs
     // *horizontal* space to be reserved for a scrollbar
-    let scrollbar_gutter = style.overflow.transpose().map(|overflow| match overflow {
-        Overflow::Scroll => style.scrollbar_width,
+    let scrollbar_gutter = style.overflow().transpose().map(|overflow| match overflow {
+        Overflow::Scroll => style.scrollbar_width(),
         _ => 0.0,
     });
     // TODO: make side configurable based on the `direction` property
@@ -388,7 +391,7 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu
         Line { start: padding.left, end: padding.right },
         Line { start: border.left, end: border.right },
         &mut columns,
-        style.justify_content.unwrap_or(AlignContent::Stretch),
+        style.justify_content().unwrap_or(AlignContent::Stretch),
     );
     // Align rows
     align_tracks(
@@ -396,7 +399,7 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu
         Line { start: padding.top, end: padding.bottom },
         Line { start: border.top, end: border.bottom },
         &mut rows,
-        style.align_content.unwrap_or(AlignContent::Stretch),
+        style.align_content().unwrap_or(AlignContent::Stretch),
     );
 
     // 9. Size, Align, and Position Grid Items
@@ -407,7 +410,8 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu
     // Sort items back into original order to allow them to be matched up with styles
     items.sort_by_key(|item| item.source_order);
 
-    let container_alignment_styles = InBothAbsAxis { horizontal: style.justify_items, vertical: style.align_items };
+    let container_alignment_styles = InBothAbsAxis { horizontal: style.justify_items(), vertical: style.align_items() };
+    drop(style);
 
     // Position in-flow children (stored in items vector)
     for (index, item) in items.iter_mut().enumerate() {
@@ -439,10 +443,11 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu
     let mut order = items.len() as u32;
     (0..tree.child_count(node)).for_each(|index| {
         let child = tree.get_child_id(node, index);
-        let child_style = tree.get_style(child);
+        let child_style = tree.get_grid_child_style(child);
 
         // Position hidden child
-        if child_style.display == Display::None {
+        if child_style.box_generation_mode() == BoxGenerationMode::None {
+            drop(child_style);
             tree.set_unrounded_layout(child, &Layout::with_order(order));
             tree.perform_child_layout(
                 child,
@@ -457,11 +462,11 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu
         }
 
         // Position absolutely positioned child
-        if child_style.position == Position::Absolute {
+        if child_style.position() == Position::Absolute {
             // Convert grid-col-{start/end} into Option's of indexes into the columns vector
             // The Option is None if the style property is Auto and an unresolvable Span
             let maybe_col_indexes = child_style
-                .grid_column
+                .grid_column()
                 .into_origin_zero(final_col_counts.explicit)
                 .resolve_absolutely_positioned_grid_tracks()
                 .map(|maybe_grid_line| {
@@ -470,7 +475,7 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu
             // Convert grid-row-{start/end} into Option's of indexes into the row vector
             // The Option is None if the style property is Auto and an unresolvable Span
             let maybe_row_indexes = child_style
-                .grid_row
+                .grid_row()
                 .into_origin_zero(final_row_counts.explicit)
                 .resolve_absolutely_positioned_grid_tracks()
                 .map(|maybe_grid_line| {
@@ -489,6 +494,8 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu
                     .map(|index| columns[index].offset)
                     .unwrap_or(container_border_box.width - border.right),
             };
+            drop(child_style);
+
             // TODO: Baseline alignment support for absolutely positioned items (should check if is actuallty specified)
             #[cfg_attr(not(feature = "content_size"), allow(unused_variables))]
             let (content_size_contribution, _, _) =
diff --git a/src/compute/grid/placement.rs b/src/compute/grid/placement.rs
index bd760accb..695ac0291 100644
--- a/src/compute/grid/placement.rs
+++ b/src/compute/grid/placement.rs
@@ -4,15 +4,16 @@ use super::types::{CellOccupancyMatrix, CellOccupancyState, GridItem};
 use super::OriginZeroLine;
 use crate::geometry::Line;
 use crate::geometry::{AbsoluteAxis, InBothAbsAxis};
-use crate::style::{AlignItems, GridAutoFlow, OriginZeroGridPlacement, Style};
+use crate::style::{AlignItems, GridAutoFlow, OriginZeroGridPlacement};
 use crate::tree::NodeId;
 use crate::util::sys::Vec;
+use crate::GridItemStyle;
 
 /// 8.5. Grid Item Placement Algorithm
 /// Place items into the grid, generating new rows/column into the implicit grid as required
 ///
 /// [Specification](https://www.w3.org/TR/css-grid-2/#auto-placement-algo)
-pub(super) fn place_grid_items<'a, ChildIter>(
+pub(super) fn place_grid_items<'a, S, ChildIter>(
     cell_occupancy_matrix: &mut CellOccupancyMatrix,
     items: &mut Vec<GridItem>,
     children_iter: impl Fn() -> ChildIter,
@@ -20,7 +21,8 @@ pub(super) fn place_grid_items<'a, ChildIter>(
     align_items: AlignItems,
     justify_items: AlignItems,
 ) where
-    ChildIter: Iterator<Item = (usize, NodeId, &'a Style)>,
+    S: GridItemStyle + 'a,
+    ChildIter: Iterator<Item = (usize, NodeId, S)>,
 {
     let primary_axis = grid_auto_flow.primary_axis();
     let secondary_axis = primary_axis.other_axis();
@@ -28,10 +30,12 @@ pub(super) fn place_grid_items<'a, ChildIter>(
     let map_child_style_to_origin_zero_placement = {
         let explicit_col_count = cell_occupancy_matrix.track_counts(AbsoluteAxis::Horizontal).explicit;
         let explicit_row_count = cell_occupancy_matrix.track_counts(AbsoluteAxis::Vertical).explicit;
-        move |(index, node, style): (usize, NodeId, &'a Style)| -> (_, _, _, &'a Style) {
+        move |(index, node, style): (usize, NodeId, S)| -> (_, _, _, S) {
             let origin_zero_placement = InBothAbsAxis {
-                horizontal: style.grid_column.map(|placement| placement.into_origin_zero_placement(explicit_col_count)),
-                vertical: style.grid_row.map(|placement| placement.into_origin_zero_placement(explicit_row_count)),
+                horizontal: style
+                    .grid_column()
+                    .map(|placement| placement.into_origin_zero_placement(explicit_col_count)),
+                vertical: style.grid_row().map(|placement| placement.into_origin_zero_placement(explicit_row_count)),
             };
             (index, node, origin_zero_placement, style)
         }
@@ -40,7 +44,7 @@ pub(super) fn place_grid_items<'a, ChildIter>(
     // 1. Place children with definite positions
     let mut idx = 0;
     children_iter()
-        .filter(|(_, _, child_style)| child_style.grid_row.is_definite() && child_style.grid_column.is_definite())
+        .filter(|(_, _, child_style)| child_style.grid_row().is_definite() && child_style.grid_column().is_definite())
         .map(map_child_style_to_origin_zero_placement)
         .for_each(|(index, child_node, child_placement, style)| {
             idx += 1;
@@ -296,12 +300,12 @@ fn place_indefinitely_positioned_item(
 /// Record the grid item in both CellOccupancyMatric and the GridItems list
 /// once a definite placement has been determined
 #[allow(clippy::too_many_arguments)]
-fn record_grid_placement(
+fn record_grid_placement<S: GridItemStyle>(
     cell_occupancy_matrix: &mut CellOccupancyMatrix,
     items: &mut Vec<GridItem>,
     node: NodeId,
     index: usize,
-    style: &Style,
+    style: S,
     parent_align_items: AlignItems,
     parent_justify_items: AlignItems,
     primary_axis: AbsoluteAxis,
diff --git a/src/compute/grid/types/grid_item.rs b/src/compute/grid/types/grid_item.rs
index 8c33798a6..acdc16a01 100644
--- a/src/compute/grid/types/grid_item.rs
+++ b/src/compute/grid/types/grid_item.rs
@@ -5,10 +5,11 @@ use crate::geometry::AbstractAxis;
 use crate::geometry::{Line, Point, Rect, Size};
 use crate::style::{
     AlignItems, AlignSelf, AvailableSpace, Dimension, LengthPercentageAuto, MaxTrackSizingFunction,
-    MinTrackSizingFunction, Overflow, Style,
+    MinTrackSizingFunction, Overflow,
 };
 use crate::tree::{LayoutPartialTree, LayoutPartialTreeExt, NodeId, SizingMode};
 use crate::util::{MaybeMath, MaybeResolve, ResolveOrZero};
+use crate::GridItemStyle;
 use core::ops::Range;
 
 /// Represents a single grid item
@@ -86,11 +87,11 @@ pub(in super::super) struct GridItem {
 
 impl GridItem {
     /// Create a new item given a concrete placement in both axes
-    pub fn new_with_placement_style_and_order(
+    pub fn new_with_placement_style_and_order<S: GridItemStyle>(
         node: NodeId,
         col_span: Line<OriginZeroLine>,
         row_span: Line<OriginZeroLine>,
-        style: &Style,
+        style: S,
         parent_align_items: AlignItems,
         parent_justify_items: AlignItems,
         source_order: u16,
@@ -100,14 +101,14 @@ impl GridItem {
             source_order,
             row: row_span,
             column: col_span,
-            overflow: style.overflow,
-            size: style.size,
-            min_size: style.min_size,
-            max_size: style.max_size,
-            aspect_ratio: style.aspect_ratio,
-            margin: style.margin,
-            align_self: style.align_self.unwrap_or(parent_align_items),
-            justify_self: style.justify_self.unwrap_or(parent_justify_items),
+            overflow: style.overflow(),
+            size: style.size(),
+            min_size: style.min_size(),
+            max_size: style.max_size(),
+            aspect_ratio: style.aspect_ratio(),
+            margin: style.margin(),
+            align_self: style.align_self().unwrap_or(parent_align_items),
+            justify_self: style.justify_self().unwrap_or(parent_justify_items),
             baseline: None,
             baseline_shim: 0.0,
             row_indexes: Line { start: 0, end: 0 }, // Properly initialised later
diff --git a/src/compute/leaf.rs b/src/compute/leaf.rs
index c6bc177b7..ebcaecfaf 100644
--- a/src/compute/leaf.rs
+++ b/src/compute/leaf.rs
@@ -1,19 +1,20 @@
 //! Computes size using styles and measure functions
 
 use crate::geometry::{Point, Size};
-use crate::style::{AvailableSpace, Display, Overflow, Position, Style};
+use crate::style::{AvailableSpace, Overflow, Position};
 use crate::tree::{CollapsibleMarginSet, RunMode};
 use crate::tree::{LayoutInput, LayoutOutput, SizingMode};
 use crate::util::debug::debug_log;
 use crate::util::sys::f32_max;
 use crate::util::MaybeMath;
 use crate::util::{MaybeResolve, ResolveOrZero};
+use crate::CoreStyle;
 use core::unreachable;
 
 /// Compute the size of a leaf node (node with no children)
 pub fn compute_leaf_layout<MeasureFunction>(
     inputs: LayoutInput,
-    style: &Style,
+    style: &impl CoreStyle,
     measure_function: MeasureFunction,
 ) -> LayoutOutput
 where
@@ -31,10 +32,10 @@ where
             (node_size, node_min_size, node_max_size, None)
         }
         SizingMode::InherentSize => {
-            let aspect_ratio = style.aspect_ratio;
-            let style_size = style.size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
-            let style_min_size = style.min_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
-            let style_max_size = style.max_size.maybe_resolve(parent_size);
+            let aspect_ratio = style.aspect_ratio();
+            let style_size = style.size().maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
+            let style_min_size = style.min_size().maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
+            let style_max_size = style.max_size().maybe_resolve(parent_size);
 
             let node_size = known_dimensions.or(style_size);
             (node_size, style_min_size, style_max_size, aspect_ratio)
@@ -43,16 +44,16 @@ where
 
     // Note: both horizontal and vertical percentage padding/borders are resolved against the container's inline size (i.e. width).
     // This is not a bug, but is how CSS is specified (see: https://developer.mozilla.org/en-US/docs/Web/CSS/padding#values)
-    let margin = style.margin.resolve_or_zero(parent_size.width);
-    let padding = style.padding.resolve_or_zero(parent_size.width);
-    let border = style.border.resolve_or_zero(parent_size.width);
+    let margin = style.margin().resolve_or_zero(parent_size.width);
+    let padding = style.padding().resolve_or_zero(parent_size.width);
+    let border = style.border().resolve_or_zero(parent_size.width);
     let padding_border = padding + border;
 
     // Scrollbar gutters are reserved when the `overflow` property is set to `Overflow::Scroll`.
     // However, the axis are switched (transposed) because a node that scrolls vertically needs
     // *horizontal* space to be reserved for a scrollbar
-    let scrollbar_gutter = style.overflow.transpose().map(|overflow| match overflow {
-        Overflow::Scroll => style.scrollbar_width,
+    let scrollbar_gutter = style.overflow().transpose().map(|overflow| match overflow {
+        Overflow::Scroll => style.scrollbar_width(),
         _ => 0.0,
     });
     // TODO: make side configurable based on the `direction` property
@@ -60,15 +61,10 @@ where
     content_box_inset.right += scrollbar_gutter.x;
     content_box_inset.bottom += scrollbar_gutter.y;
 
-    #[cfg(feature = "block_layout")]
-    let is_block = style.display == Display::Block;
-    #[cfg(not(feature = "block_layout"))]
-    let is_block = false;
-
-    let has_styles_preventing_being_collapsed_through = !is_block
-        || style.overflow.x.is_scroll_container()
-        || style.overflow.y.is_scroll_container()
-        || style.position == Position::Absolute
+    let has_styles_preventing_being_collapsed_through = !style.is_block()
+        || style.overflow().x.is_scroll_container()
+        || style.overflow().y.is_scroll_container()
+        || style.position() == Position::Absolute
         || padding.top > 0.0
         || padding.bottom > 0.0
         || border.top > 0.0
diff --git a/src/compute/mod.rs b/src/compute/mod.rs
index 746997af4..5af70e8fb 100644
--- a/src/compute/mod.rs
+++ b/src/compute/mod.rs
@@ -45,7 +45,7 @@ pub use self::flexbox::compute_flexbox_layout;
 pub use self::grid::compute_grid_layout;
 
 use crate::geometry::{Line, Point, Size};
-use crate::style::{AvailableSpace, Overflow};
+use crate::style::{AvailableSpace, CoreStyle, Overflow};
 use crate::tree::{
     Layout, LayoutInput, LayoutOutput, LayoutPartialTree, LayoutPartialTreeExt, NodeId, RoundTree, SizingMode,
 };
@@ -65,13 +65,14 @@ pub fn compute_root_layout(tree: &mut impl LayoutPartialTree, root: NodeId, avai
         Line::FALSE,
     );
 
-    let style = tree.get_style(root);
-    let padding = style.padding.resolve_or_zero(available_space.width.into_option());
-    let border = style.border.resolve_or_zero(available_space.width.into_option());
+    let style = tree.get_core_container_style(root);
+    let padding = style.padding().resolve_or_zero(available_space.width.into_option());
+    let border = style.border().resolve_or_zero(available_space.width.into_option());
     let scrollbar_size = Size {
-        width: if style.overflow.y == Overflow::Scroll { style.scrollbar_width } else { 0.0 },
-        height: if style.overflow.x == Overflow::Scroll { style.scrollbar_width } else { 0.0 },
+        width: if style.overflow().y == Overflow::Scroll { style.scrollbar_width() } else { 0.0 },
+        height: if style.overflow().x == Overflow::Scroll { style.scrollbar_width() } else { 0.0 },
     };
+    drop(style);
 
     tree.set_unrounded_layout(
         root,
diff --git a/src/style/grid.rs b/src/style/grid.rs
index 0394b763d..d2597e69c 100644
--- a/src/style/grid.rs
+++ b/src/style/grid.rs
@@ -63,6 +63,24 @@ pub trait GridContainerStyle: CoreStyle {
     fn justify_items(&self) -> Option<AlignItems> {
         Style::DEFAULT.justify_items
     }
+
+    /// Get a grid item's row or column placement depending on the axis passed
+    #[inline(always)]
+    fn grid_template_tracks(&self, axis: AbsoluteAxis) -> &[TrackSizingFunction] {
+        match axis {
+            AbsoluteAxis::Horizontal => self.grid_template_columns(),
+            AbsoluteAxis::Vertical => self.grid_template_rows(),
+        }
+    }
+
+    /// Get a grid container's align-content or justify-content alignment depending on the axis passed
+    #[inline(always)]
+    fn grid_align_content(&self, axis: AbstractAxis) -> AlignContent {
+        match axis {
+            AbstractAxis::Inline => self.justify_content().unwrap_or(AlignContent::Stretch),
+            AbstractAxis::Block => self.align_content().unwrap_or(AlignContent::Stretch),
+        }
+    }
 }
 
 /// The set of styles required for a CSS Grid item (child of a CSS Grid container)
@@ -90,6 +108,15 @@ pub trait GridItemStyle: CoreStyle {
     fn justify_self(&self) -> Option<AlignSelf> {
         Style::DEFAULT.justify_self
     }
+
+    /// Get a grid item's row or column placement depending on the axis passed
+    #[inline(always)]
+    fn grid_placement(&self, axis: AbsoluteAxis) -> Line<GridPlacement> {
+        match axis {
+            AbsoluteAxis::Horizontal => self.grid_column(),
+            AbsoluteAxis::Vertical => self.grid_row(),
+        }
+    }
 }
 
 /// Controls whether grid items are placed row-wise or column-wise. And whether the sparse or dense packing algorithm is used.
@@ -684,30 +711,3 @@ impl From<MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>> for TrackSizin
         Self::Single(input)
     }
 }
-
-// Grid extensions to the Style struct
-impl Style {
-    /// Get a grid item's row or column placement depending on the axis passed
-    pub(crate) fn grid_template_tracks(&self, axis: AbsoluteAxis) -> &GridTrackVec<TrackSizingFunction> {
-        match axis {
-            AbsoluteAxis::Horizontal => &self.grid_template_columns,
-            AbsoluteAxis::Vertical => &self.grid_template_rows,
-        }
-    }
-
-    /// Get a grid item's row or column placement depending on the axis passed
-    pub(crate) fn grid_placement(&self, axis: AbsoluteAxis) -> Line<GridPlacement> {
-        match axis {
-            AbsoluteAxis::Horizontal => self.grid_column,
-            AbsoluteAxis::Vertical => self.grid_row,
-        }
-    }
-
-    /// Get a grid container's align-content or justify-content alignment depending on the axis passed
-    pub(crate) fn grid_align_content(&self, axis: AbstractAxis) -> AlignContent {
-        match axis {
-            AbstractAxis::Inline => self.justify_content.unwrap_or(AlignContent::Stretch),
-            AbstractAxis::Block => self.align_content.unwrap_or(AlignContent::Stretch),
-        }
-    }
-}
diff --git a/src/style/mod.rs b/src/style/mod.rs
index bcc4a436e..dded20527 100644
--- a/src/style/mod.rs
+++ b/src/style/mod.rs
@@ -40,6 +40,11 @@ pub trait CoreStyle {
     fn box_generation_mode(&self) -> BoxGenerationMode {
         BoxGenerationMode::DEFAULT
     }
+    /// Is block layout?
+    #[inline(always)]
+    fn is_block(&self) -> bool {
+        false
+    }
 
     // Overflow properties
     /// How children overflowing their container should affect layout
@@ -106,6 +111,12 @@ pub trait CoreStyle {
     }
 }
 
+// trait BlockChildStyle : CoreStyle {
+//     fn is_block_node() -> bool {
+//         false
+//     }
+// }
+
 /// Sets the layout used for the children of this node
 ///
 /// The default values depends on on which feature flags are enabled. The order of precedence is: Flex, Grid, Block, None.
@@ -475,6 +486,11 @@ impl CoreStyle for Style {
         }
     }
     #[inline(always)]
+    #[cfg(feature = "block_layout")]
+    fn is_block(&self) -> bool {
+        matches!(self.display, Display::Block)
+    }
+    #[inline(always)]
     fn overflow(&self) -> Point<Overflow> {
         self.overflow
     }
@@ -520,8 +536,62 @@ impl CoreStyle for Style {
     }
 }
 
+impl<T: CoreStyle> CoreStyle for &'_ T {
+    #[inline(always)]
+    fn box_generation_mode(&self) -> BoxGenerationMode {
+        (*self).box_generation_mode()
+    }
+    fn is_block(&self) -> bool {
+        (*self).is_block()
+    }
+    #[inline(always)]
+    fn overflow(&self) -> Point<Overflow> {
+        (*self).overflow()
+    }
+    #[inline(always)]
+    fn scrollbar_width(&self) -> f32 {
+        (*self).scrollbar_width()
+    }
+    #[inline(always)]
+    fn position(&self) -> Position {
+        (*self).position()
+    }
+    #[inline(always)]
+    fn inset(&self) -> Rect<LengthPercentageAuto> {
+        (*self).inset()
+    }
+    #[inline(always)]
+    fn size(&self) -> Size<Dimension> {
+        (*self).size()
+    }
+    #[inline(always)]
+    fn min_size(&self) -> Size<Dimension> {
+        (*self).min_size()
+    }
+    #[inline(always)]
+    fn max_size(&self) -> Size<Dimension> {
+        (*self).max_size()
+    }
+    #[inline(always)]
+    fn aspect_ratio(&self) -> Option<f32> {
+        (*self).aspect_ratio()
+    }
+    #[inline(always)]
+    fn margin(&self) -> Rect<LengthPercentageAuto> {
+        (*self).margin()
+    }
+    #[inline(always)]
+    fn padding(&self) -> Rect<LengthPercentage> {
+        (*self).padding()
+    }
+    #[inline(always)]
+    fn border(&self) -> Rect<LengthPercentage> {
+        (*self).border()
+    }
+}
+
 #[cfg(feature = "flexbox")]
-impl FlexboxContainerStyle for Style {
+impl FlexboxContainerStyle for &Style {
     #[inline(always)]
     fn flex_direction(&self) -> FlexDirection {
         self.flex_direction
@@ -547,6 +617,35 @@ impl FlexboxContainerStyle for Style {
         self.justify_content
     }
 }
+
+#[cfg(feature = "flexbox")]
+impl<T: FlexboxContainerStyle> FlexboxContainerStyle for &'_ T {
+    #[inline(always)]
+    fn flex_direction(&self) -> FlexDirection {
+        (*self).flex_direction()
+    }
+    #[inline(always)]
+    fn flex_wrap(&self) -> FlexWrap {
+        (*self).flex_wrap()
+    }
+    #[inline(always)]
+    fn gap(&self) -> Size<LengthPercentage> {
+        (*self).gap()
+    }
+    #[inline(always)]
+    fn align_content(&self) -> Option<AlignContent> {
+        (*self).align_content()
+    }
+    #[inline(always)]
+    fn align_items(&self) -> Option<AlignItems> {
+        (*self).align_items()
+    }
+    #[inline(always)]
+    fn justify_content(&self) -> Option<JustifyContent> {
+        (*self).justify_content()
+    }
+}
+
 #[cfg(feature = "flexbox")]
 impl FlexboxItemStyle for Style {
     #[inline(always)]
@@ -567,6 +666,26 @@ impl FlexboxItemStyle for Style {
     }
 }
 
+#[cfg(feature = "flexbox")]
+impl<T: FlexboxItemStyle> FlexboxItemStyle for &'_ T {
+    #[inline(always)]
+    fn flex_basis(&self) -> Dimension {
+        (*self).flex_basis()
+    }
+    #[inline(always)]
+    fn flex_grow(&self) -> f32 {
+        (*self).flex_grow()
+    }
+    #[inline(always)]
+    fn flex_shrink(&self) -> f32 {
+        (*self).flex_shrink()
+    }
+    #[inline(always)]
+    fn align_self(&self) -> Option<AlignSelf> {
+        (*self).align_self()
+    }
+}
+
 #[cfg(feature = "grid")]
 impl GridContainerStyle for Style {
     #[inline(always)]
@@ -610,8 +729,53 @@ impl GridContainerStyle for Style {
         self.justify_items
     }
 }
+
 #[cfg(feature = "grid")]
-impl GridItemStyle for Style {
+impl<T: GridContainerStyle> GridContainerStyle for &'_ T {
+    #[inline(always)]
+    fn grid_template_rows(&self) -> &[TrackSizingFunction] {
+        &(*self).grid_template_rows()
+    }
+    #[inline(always)]
+    fn grid_template_columns(&self) -> &[TrackSizingFunction] {
+        &(*self).grid_template_columns()
+    }
+    #[inline(always)]
+    fn grid_auto_rows(&self) -> &[NonRepeatedTrackSizingFunction] {
+        &(*self).grid_auto_rows()
+    }
+    #[inline(always)]
+    fn grid_auto_columns(&self) -> &[NonRepeatedTrackSizingFunction] {
+        &(*self).grid_auto_columns()
+    }
+    #[inline(always)]
+    fn grid_auto_flow(&self) -> GridAutoFlow {
+        (*self).grid_auto_flow()
+    }
+    #[inline(always)]
+    fn gap(&self) -> Size<LengthPercentage> {
+        (*self).gap()
+    }
+    #[inline(always)]
+    fn align_content(&self) -> Option<AlignContent> {
+        (*self).align_content()
+    }
+    #[inline(always)]
+    fn justify_content(&self) -> Option<JustifyContent> {
+        (*self).justify_content()
+    }
+    #[inline(always)]
+    fn align_items(&self) -> Option<AlignItems> {
+        (*self).align_items()
+    }
+    #[inline(always)]
+    fn justify_items(&self) -> Option<AlignItems> {
+        (*self).justify_items()
+    }
+}
+
+#[cfg(feature = "grid")]
+impl GridItemStyle for &'_ Style {
     #[inline(always)]
     fn grid_row(&self) -> Line<GridPlacement> {
         self.grid_row
@@ -630,6 +794,26 @@ impl GridItemStyle for Style {
     }
 }
 
+#[cfg(feature = "grid")]
+impl<T: GridItemStyle> GridItemStyle for &'_ T {
+    #[inline(always)]
+    fn grid_row(&self) -> Line<GridPlacement> {
+        (*self).grid_row()
+    }
+    #[inline(always)]
+    fn grid_column(&self) -> Line<GridPlacement> {
+        (*self).grid_column()
+    }
+    #[inline(always)]
+    fn align_self(&self) -> Option<AlignSelf> {
+        (*self).align_self()
+    }
+    #[inline(always)]
+    fn justify_self(&self) -> Option<AlignSelf> {
+        (*self).justify_self()
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::Style;
diff --git a/src/tree/taffy_tree.rs b/src/tree/taffy_tree.rs
index 664dc71cd..72898bf09 100644
--- a/src/tree/taffy_tree.rs
+++ b/src/tree/taffy_tree.rs
@@ -23,6 +23,7 @@ use crate::compute::compute_grid_layout;
 use crate::compute::{
     compute_cached_layout, compute_hidden_layout, compute_leaf_layout, compute_root_layout, round_layout,
 };
+use crate::{LayoutBlockContainer, LayoutFlexboxContainer, LayoutGridContainer};
 
 /// The error Taffy generates on invalid operations
 pub type TaffyResult<T> = Result<T, TaffyError>;
@@ -267,9 +268,11 @@ where
     MeasureFunction:
         FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>, &Style) -> Size<f32>,
 {
+    type CoreContainerStyle<'a> = &'a Style where Self : 'a;
+
     #[inline(always)]
-    fn get_style(&self, node: NodeId) -> &Style {
-        &self.taffy.nodes[node.into()].style
+    fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_> {
+        &self.taffy.nodes[node_id.into()].style
     }
 
     #[inline(always)]
@@ -297,7 +300,7 @@ where
         //
         // If there was no cache match and a new result needs to be computed then that result will be added to the cache
         compute_cached_layout(self, node, inputs, |tree, node, inputs| {
-            let display_mode = tree.get_style(node).display;
+            let display_mode = tree.taffy.nodes[node.into()].style.display;
             let has_children = tree.child_count(node) > 0;
 
             debug_log!(display_mode);
@@ -333,6 +336,60 @@ where
     }
 }
 
+impl<'t, NodeContext, MeasureFunction> LayoutBlockContainer for TaffyView<'t, NodeContext, MeasureFunction>
+where
+    MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
+{
+    type ContainerStyle<'a> = &'a Style where Self: 'a;
+    type ItemStyle<'a> = &'a Style where Self: 'a;
+
+    #[inline(always)]
+    fn get_block_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_> {
+        self.get_core_container_style(node_id)
+    }
+
+    #[inline(always)]
+    fn get_block_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> {
+        self.get_core_container_style(child_node_id)
+    }
+}
+
+impl<'t, NodeContext, MeasureFunction> LayoutFlexboxContainer for TaffyView<'t, NodeContext, MeasureFunction>
+where
+    MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
+{
+    type ContainerStyle<'a> = &'a Style where Self: 'a;
+    type ItemStyle<'a> = &'a Style where Self: 'a;
+
+    #[inline(always)]
+    fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_> {
+        &self.taffy.nodes[node_id.into()].style
+    }
+
+    #[inline(always)]
+    fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> {
+        &self.taffy.nodes[child_node_id.into()].style
+    }
+}
+
+impl<'t, NodeContext, MeasureFunction> LayoutGridContainer for TaffyView<'t, NodeContext, MeasureFunction>
+where
+    MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
+{
+    type ContainerStyle = Style;
+    type ItemStyle<'a> = &'a Style where Self: 'a;
+
+    #[inline(always)]
+    fn get_grid_container_style(&self, node_id: NodeId) -> &Self::ContainerStyle {
+        &self.taffy.nodes[node_id.into()].style
+    }
+
+    #[inline(always)]
+    fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> {
+        &self.taffy.nodes[child_node_id.into()].style
+    }
+}
+
 // RoundTree impl for TaffyView
 impl<'t, NodeContext, MeasureFunction> RoundTree for TaffyView<'t, NodeContext, MeasureFunction>
 where
diff --git a/src/tree/traits.rs b/src/tree/traits.rs
index 87a91baac..02324dbf9 100644
--- a/src/tree/traits.rs
+++ b/src/tree/traits.rs
@@ -128,7 +128,7 @@
 //!
 use super::{Cache, Layout, LayoutInput, LayoutOutput, NodeId, RequestedAxis, RunMode, SizingMode};
 use crate::geometry::{AbsoluteAxis, Line, Size};
-use crate::style::{AvailableSpace, CoreStyle, Style};
+use crate::style::{AvailableSpace, CoreStyle};
 #[cfg(feature = "flexbox")]
 use crate::style::{FlexboxContainerStyle, FlexboxItemStyle};
 #[cfg(feature = "grid")]
@@ -161,8 +161,14 @@ pub trait TraverseTree: TraversePartialTree {}
 /// Note that this trait extends [`TraversePartialTree`] (not [`TraverseTree`]). Taffy's algorithm implementations have been designed such that they can be used for a laying out a single
 /// node that only has access to it's immediate children.
 pub trait LayoutPartialTree: TraversePartialTree {
-    /// Get a reference to the [`Style`] for this node.
-    fn get_style(&self, node_id: NodeId) -> &Style;
+    /// The style type representing the core container styles that all containers should have
+    /// Used when laying out the root node of a tree
+    type CoreContainerStyle<'a>: CoreStyle
+    where
+        Self: 'a;
+
+    /// Get core style
+    fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_>;
 
     /// Set the node's unrounded layout
     fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout);
@@ -208,29 +214,28 @@ pub trait LayoutFlexboxContainer: LayoutPartialTree {
         Self: 'a;
 
     /// Get the container's styles
-    fn get_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_>;
+    fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_>;
 
     /// Get the child's styles
-    fn get_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_>;
+    fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_>;
 }
 
 #[cfg(feature = "grid")]
 /// Extends [`LayoutPartialTree`] with getters for the styles required for CSS Grid layout
 pub trait LayoutGridContainer: LayoutPartialTree {
     /// The style type representing the CSS Grid container's styles
-    type ContainerStyle<'a>: GridContainerStyle
-    where
-        Self: 'a;
+    type ContainerStyle: GridContainerStyle + Clone;
+
     /// The style type representing each CSS Grid item's styles
     type ItemStyle<'a>: GridItemStyle
     where
         Self: 'a;
 
     /// Get the container's styles
-    fn get_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_>;
+    fn get_grid_container_style(&self, node_id: NodeId) -> &Self::ContainerStyle;
 
     /// Get the child's styles
-    fn get_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_>;
+    fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_>;
 }
 
 #[cfg(feature = "block_layout")]
@@ -246,10 +251,10 @@ pub trait LayoutBlockContainer: LayoutPartialTree {
         Self: 'a;
 
     /// Get the container's styles
-    fn get_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_>;
+    fn get_block_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_>;
 
     /// Get the child's styles
-    fn get_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_>;
+    fn get_block_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_>;
 }
 
 // --- PRIVATE TRAITS