From 5012603e03f380defac510df970d6b2cc635131a Mon Sep 17 00:00:00 2001 From: rustbasic <127506429+rustbasic@users.noreply.github.com> Date: Wed, 10 Jun 2026 16:57:44 +0900 Subject: [PATCH] Fix: ScrollArea layout jitter with floating bars and zoom levels (#7944) Fix: ScrollArea layout jitter with floating bars and zoom levels * Closes #7937 * Closes #7942 This PR improves the stability of `ScrollArea` by addressing two layout issues: 1. **Discrete Layout for Floating Bars:** Fixed content "shaking" in `floating` mode when a non-zero `allocated_width` is used. By using discrete visibility (`show_bars`) instead of the animated factor for space allocation, we ensure the layout remains stable during scrollbar animations. 2. **Zoom-level Stability:** Introduced a small epsilon (0.1) when checking if content exceeds the viewport. This prevents scrollbars from flickering on and off due to floating-point rounding errors at specific zoom factors (e.g., 1.01 or 0.95). --- crates/egui/src/containers/scroll_area.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/crates/egui/src/containers/scroll_area.rs b/crates/egui/src/containers/scroll_area.rs index 5e0c69936..0fa4bba0c 100644 --- a/crates/egui/src/containers/scroll_area.rs +++ b/crates/egui/src/containers/scroll_area.rs @@ -753,7 +753,12 @@ impl ScrollArea { ctx.animate_bool_responsive(id.with("v"), show_bars[1]), ); - let current_bar_use = show_bars_factor.yx() * ui.spacing().scroll.allocated_width(); + let scroll_style = ui.spacing().scroll; + let current_bar_use = if scroll_style.floating { + show_bars.to_vec2().yx() * scroll_style.allocated_width() + } else { + show_bars_factor.yx() * scroll_style.allocated_width() + }; let available_outer = ui.available_rect_before_wrap(); @@ -1187,9 +1192,15 @@ impl Prepared { let outer_rect = Rect::from_min_size(inner_rect.min, inner_rect.size() + current_bar_use); + let limit_rect = if ui.spacing().scroll.floating { + outer_rect + } else { + inner_rect + }; + let content_is_too_large = Vec2b::new( - direction_enabled[0] && inner_rect.width() < content_size.x, - direction_enabled[1] && inner_rect.height() < content_size.y, + direction_enabled[0] && (limit_rect.width().ceil() < content_size.x), + direction_enabled[1] && (limit_rect.height().ceil() < content_size.y), ); let max_offset = content_size - inner_rect.size();