Repository navigation
Conversation
|
Could I see the difference of before and after? |
Yes! Sorry I am still preparing the recordings. (Didn't expect you to be so fast 😂) Edit: Updated PR with recordings. |
|
I updated the PR to also fix similar jitter when sidebar is on the right side. |
|
@mr-cheffy The before/after recordings are in the PR description now. I added them after my earlier reply, so you may not have been notified. Since then I also fixed the same jitter for the right-side sidebar. Ready for another look when you have time. |
Extend the compact-mode toolbar transition to sidebars on the right. The right header changes width when it moves into the navbar, so measure its destination and animate it along the path between the two layouts. The tab list no longer jumps when the sidebar reopens.
Animate the navbar inset and release header or collapsed-sidebar space with the sidebar. Keep the menu before the sidebar button so the controls do not cross. Measure control destinations after applying the final margins and cancel temporary animations before restoring styles. Regression checks reproduce the previous 5 px navigation snap and 30 px URL-bar edge jump. The toolbar suite passes 1,327 checks in both headless and headed runs; related width and URL-bar suites pass 136 checks. UI build and implementation ESLint pass. CSS lint has the same existing line 262 error on the baseline.
Remove the CSS override that moved the sidebar toggle after the menu in compact mode. Keep the toolbar margin animations and restore the original button positions in each layout. Replace the test that enforced the new order with checks for the original expanded and compact orders. The new order checks fail with the override. After removal, 1,331 headless toolbar checks and 1,467 headed toolbar, width and URL-bar checks pass. The incremental UI build passes.
Keep four short explanations for layout constraints and remove comments that repeat the code. Preserve existing comments and the test copyright notice. JavaScript token comparison and CSS comparison confirm no executable changes. Implementation ESLint, incremental UI build and 1,331 compact-mode checks pass.
|
Noticed another small visual issue with the URL bar "snapping" during right side bar animation, addressed this too. I feel now the animations across URL and left/right sidebar is much cleaner. |
|
This looks like a very complicated fix to such a minor issue... I'll clone it and check it out tomorrow |
|
Hi @mr-cheffy, have you had a chance to try it out? On the complexity: I agree it looks heavy for the size of the issue, so here is what the code is actually doing. When compact mode toggles, I tried a smaller version that dropped the nav-bar inset animation. It passed the existing tests but brought back a URL-bar jump in narrow windows, so I kept it. |
|
Hi @yosofbadr, great work on stabilizing the toolbar controls in the "Sidebar and top toolbar" layout! I tested your PR across different configurations and noticed that in "Single toolbar" (URL bar inside the sidebar) and on other platforms, the transition was still feeling jerky. I put together a small patch to make it completely smooth and progressive across all setups without altering your toolbar compensation logic:
Click to view smooth-compact-mode.patchFrom 6d089d81877261c944f51d8f79870bc06e024aab Mon Sep 17 00:00:00 2001
From: Wety14 <sacha.darleg@gmail.com>
Date: Sat, 31 Oct 2026 14:12:34 +0100
Subject: [PATCH] feat(compact-mode): smooth sidebar transition and progressive
viewport resize
---
src/zen/compact-mode/ZenCompactMode.mjs | 71 +++++++++++++------------
1 file changed, 38 insertions(+), 33 deletions(-)
diff --git a/src/zen/compact-mode/ZenCompactMode.mjs b/src/zen/compact-mode/ZenCompactMode.mjs
index 66e194b79..b9b5e0f4b 100644
--- a/src/zen/compact-mode/ZenCompactMode.mjs
+++ b/src/zen/compact-mode/ZenCompactMode.mjs
@@ -633,28 +633,21 @@ window.gZenCompactModeManager = {
animateCompactMode(isCompactMode, toolbarTransition = null) {
return new Promise(resolve => {
- document.documentElement.setAttribute("zen-compact-animating", "true");
const canHideSidebar = this.canHideSidebar;
const canAnimate = this._canAnimateSidebar;
delete this._preventAnimateCollapse;
delete this._wasInCompactMode;
- // Do this so we can get the correct width ONCE compact mode styled have been applied
- if (canAnimate) {
- this.sidebar.setAttribute("animate", "true");
- } else {
- this.sidebar.style.transition = "none";
- }
+
if (this._ignoreNextHover) {
this._setElementExpandAttribute(this.sidebar, false);
}
- this.sidebar.style.removeProperty("margin-right");
- this.sidebar.style.removeProperty("margin-left");
- this.sidebar.style.removeProperty("transform");
+
// Reparenting controls invalidates layout; compensation needs fresh bounds.
let sidebarWidth = toolbarTransition
? this.sidebar.getBoundingClientRect().width
: window.windowUtils.getBoundsWithoutFlushing(this.sidebar).width;
const elementSeparation = ZenThemeModifier.elementSeparation;
+
if (!canAnimate) {
this.sidebar.removeAttribute("animate");
document.documentElement.removeAttribute("zen-compact-animating");
@@ -667,14 +660,37 @@ window.gZenCompactModeManager = {
resolve();
return;
}
- sidebarWidth -=
- elementSeparation * (toolbarTransition || isCompactMode ? 1 : 3);
+
+ sidebarWidth -= elementSeparation;
+
+ const browser = document.getElementById("browser");
+ if (canHideSidebar) {
+ browser?.style.setProperty("overflow", "clip");
+ }
+
+ // To avoid layout flicker when showing the sidebar, apply the initial negative
+ // margin before toggling animating classes / losing fixed positioning styles.
+ if (!isCompactMode && canHideSidebar) {
+ delete this._ignoreNextHover;
+ if (this.sidebarIsOnRight) {
+ this.sidebar.style.marginRight = `-${sidebarWidth}px`;
+ } else {
+ this.sidebar.style.marginLeft = `-${sidebarWidth}px`;
+ }
+ } else {
+ this.sidebar.style.removeProperty("margin-right");
+ this.sidebar.style.removeProperty("margin-left");
+ }
+ this.sidebar.style.removeProperty("transform");
+
+ document.documentElement.setAttribute("zen-compact-animating", "true");
+ this.sidebar.setAttribute("animate", "true");
+
const animationOptions = {
- ease: isCompactMode ? "easeIn" : "easeOut",
- type: "spring",
- bounce: 0,
- duration: 0.1,
+ ease: "easeOut",
+ duration: 0.22,
};
+
if (canHideSidebar && isCompactMode) {
toolbarTransition?.start(sidebarWidth, animationOptions);
this._setElementExpandAttribute(this.sidebar, false);
@@ -692,8 +708,9 @@ window.gZenCompactModeManager = {
)
.then(() => {
this.sidebar.style.transition = "none";
- this.sidebar.style.pointEvents = "none";
+ this.sidebar.style.pointerEvents = "none";
this.sidebar.removeAttribute("animate");
+ browser?.style.removeProperty("overflow");
if (this._ignoreNextHover) {
setTimeout(() => {
@@ -705,7 +722,7 @@ window.gZenCompactModeManager = {
this.sidebar.style.removeProperty("margin-right");
this.sidebar.style.removeProperty("margin-left");
this.sidebar.style.removeProperty("transform");
- this.sidebar.style.removeProperty("point-events");
+ this.sidebar.style.removeProperty("pointer-events");
requestAnimationFrame(() => {
this.sidebar.style.removeProperty("transition");
@@ -714,31 +731,18 @@ window.gZenCompactModeManager = {
resolve();
});
} else if (canHideSidebar && !isCompactMode) {
- // Shouldn't be ever true, but just in case
- delete this._ignoreNextHover;
- document.getElementById("browser").style.overflow = "clip";
- if (this.sidebarIsOnRight) {
- this.sidebar.style.marginRight = `-${sidebarWidth}px`;
- } else {
- this.sidebar.style.marginLeft = `-${sidebarWidth}px`;
- }
toolbarTransition?.start(sidebarWidth, animationOptions);
gZenUIManager.motion
.animate(
this.sidebar,
this.sidebarIsOnRight
- ? {
- marginRight: [`-${sidebarWidth}px`, 0],
- ...(!toolbarTransition && {
- transform: ["translateX(100%)", "translateX(0)"],
- }),
- }
+ ? { marginRight: [`-${sidebarWidth}px`, 0] }
: { marginLeft: [`-${sidebarWidth}px`, 0] },
animationOptions
)
.then(() => {
this.sidebar.removeAttribute("animate");
- document.getElementById("browser").style.removeProperty("overflow");
+ browser?.style.removeProperty("overflow");
this.sidebar.style.transition = "none";
this.sidebar.style.removeProperty("margin-right");
this.sidebar.style.removeProperty("margin-left");
@@ -750,6 +754,7 @@ window.gZenCompactModeManager = {
resolve();
});
} else {
+ browser?.style.removeProperty("overflow");
this.sidebar.removeAttribute("animate"); // remove the attribute if we are not animating
document.documentElement.removeAttribute("zen-compact-animating");
delete this._ignoreNextHover;
--
2.54.0 (Apple Git-157)
|
|
@Wety14 thanks for the patch. I tested it on macOS against this PR's compact-mode code, ported to a slightly older nightly base. I ran the compact-mode tests and logged the sidebar and content positions on each animation frame. The patch as posted causes a regression. It measures the sidebar width before setting the
On the individual points:
The patch also removes |
Fixes #15916.
Summary
I recently switched from Arc to Zen and noticed that, in the "Sidebar and top toolbar" layout, toggling the sidebar with Cmd+S makes its contents jump vertically. Back, forward and reload also slide too far into the sidebar, and the compact-mode button shifts sideways.
It is a small visual issue, but I use this shortcut a lot and the movement makes the browser feel less polished.
This fix keeps the sidebar header controls steady while the sidebar slides. It reserves the header's space so the tab list does not jump, and keeps the navigation buttons within their intended path. The controls stay in normal layout so toolbar sizing and overflow still work. Temporary styles are restored after the transition.
Before and after
Side-by-side comparison of the "Sidebar and top toolbar" layout at half speed, before on the left and after on the right.
sidebar-comparison.mp4
Before, normal speed:
sidebar-before.mp4
After, normal speed:
sidebar-after.mp4
Both recordings use the same runtime, settings and fresh temporary profiles.
The issue occurs in "Sidebar and top toolbar". The "Only sidebar" layout already behaves as intended and is unchanged by this fix.
The fix is limited to macOS, a left sidebar, left-to-right layout and "Sidebar and top toolbar", with only the sidebar hidden in compact mode. macOS reparents its left-hand window controls when compact mode changes. Windows and most Linux configurations place their caption controls differently, so this compensation is deliberately scoped to the layout I reproduced. Other layouts keep their existing animation path.
Right sidebar follow-up
These recordings show the right-sidebar extension prepared locally, which has not been pushed yet. Both use the same existing Firefox 157 runtime, settings and fresh temporary profiles. The animations are slowed to 25% speed for clarity.
Before, the tab list jumps 42 pixels and the header shifts during reopening. After, the tab list stays level and the header reaches its final position before the temporary styles are removed.
Side-by-side comparison, before on the left and after on the right:
right-sidebar-comparison.mp4
Before:
right-sidebar-before.mp4
After:
right-sidebar-after.mp4
The local extension passed 915 compact-mode checks, including a check for the header's position immediately before animation cleanup. JavaScript lint and the incremental UI build passed.
Top-bar follow-up
Comparison of the top-bar follow-up, before on top and after below. Both use the same runtime, settings and fresh temporary profiles, first at normal speed and then with the animation slowed to 25% speed. The before build already includes the right-sidebar fix.
top-bar-comparison-original-order.mp4
Updated recording of the top-bar fix with a right sidebar, first at normal speed and then with the animation slowed to 25% speed.
top-bar-after-original-order.mp4
Testing
The reviewed implementation passed 436 browser checks across compact mode and the existing URL-bar suites. The new tests sample the animation itself and cover expanded and collapsed sidebars, custom spacing, disabled animations, style cleanup and the RTL fallback. JavaScript lint and the incremental UI build passed.
I also tested it in my daily-use profile. Windows and Linux have not been tested. These results are from the existing local Firefox 157 runtime, rather than a fresh full build of the latest upstream base.