Skip to content

JCU/fix(root): resolve the admin-sidebar gutter in CSS, not in an animation - #1496

Merged
milanmajchrak merged 1 commit into
customer/jcufrom
JCU/fix-admin-sidebar-gutter
Sep 9, 2026
Merged

JCU/fix(root): resolve the admin-sidebar gutter in CSS, not in an animation#1496
milanmajchrak merged 1 commit into
customer/jcufrom
JCU/fix-admin-sidebar-gutter

Conversation

@milanmajchrak

Copy link
Copy Markdown
Collaborator

References

Description

Logged in as an administrator, a reload moved the whole page sideways. @slideSidebarPadding takes the gutter width from the browser-only CSS-variable store, so the server has nothing to substitute and renders style="padding-left: *", which is not valid CSS. The browser then resolves the real width and everything shifts right by the sidebar. The gutter is now resolved in CSS from the sidebar's own custom properties, which the server and the browser read the same way.

Instructions for Reviewers

List of changes in this PR:

  • root.component.html: the @slideSidebarPadding binding is replaced by ds-admin-sidebar-{hidden,unpinned,pinned} classes, driven by a new sidebarPaddingState$.
  • root.component.scss: those classes resolve padding-left from --ds-admin-sidebar-fixed-element-width and --ds-admin-sidebar-total-width, the same custom properties the animation used to read. No width is hardcoded and the theme keeps control of it.
  • The pin/unpin slide survives as transition: padding-left, behind ds-admin-sidebar-animate, which ngAfterViewInit adds after the first paint so the initial resolution never animates.
  • themes/custom/app/root/root.component.ts drops the animation as well.

Written for this branch rather than cherry-picked, since #1333 landed on 7.x. The changed blocks match customer/mendelu's line for line apart from comment wording.

#1493 made this worth fixing now rather than later: the anti-flicker overlay holds the server's paint on screen for a second or two, so the shift that used to be lost in the white rebuild is now a clean jump the eye follows.

How to test:

  1. Log in as an administrator, open any page and reload it. The content does not move sideways, and the sidebar no longer sits on top of the first 55px of the page.
  2. view-source: on a page served to a logged-in session: .outer-wrapper carries ds-admin-sidebar-unpinned and no inline style attribute. It used to read style="padding-left: *".
  3. Pin and unpin the sidebar: the gutter still slides over 300ms.
  4. Logged out, .outer-wrapper carries ds-admin-sidebar-hidden and the gutter is 0.

Measured on a DSpace 9.3 stack in Docker (docker-compose-rest.yml + db.entities.yml, 494 items) with this branch's production build under PM2, logged in as an administrator, reloading /home at 4x CPU throttle:

before after
.outer-wrapper inline style padding-left: * none
computed padding-left 0px 55px
#main-content x 0, with the 55px sidebar over the content 55
horizontal movement during the reload the width of the sidebar none, the SSR snapshot and the live app agree from the first frame

--ds-admin-sidebar-fixed-element-width resolves to 55px and --ds-admin-sidebar-total-width to 305px in the browser, so pinned keeps the width the animation used. Anonymous pages are unchanged: ds-admin-sidebar-hidden, gutter 0, and the white-frame numbers from #1493 still hold (89-104ms document-swap gap with the overlay, 407-842ms extra flash without it).

Checklist

  • My PR is created against the main branch of code (unless it is a backport or is fixing an issue specific to an older branch). Customer branch fix, base is customer/jcu.
  • My PR is small in size (e.g. less than 1,000 lines of code, not including comments & specs/tests), or I have provided reasons as to why that's not possible.
  • My PR passes ESLint validation using npm run lint
  • My PR doesn't introduce circular dependencies (verified via npm run check-circ-deps)
  • My PR includes TypeDoc comments for all new (or modified) public methods and classes. It also includes TypeDoc for large or complex private methods.
  • My PR passes all specs/tests and includes new/updated specs or tests based on the Code Testing Guide. root.component.spec.ts passes; the behaviour itself is CSS, verified on a running stack.
  • My PR aligns with Accessibility guidelines if it makes changes to the user interface. Same layout, no new controls.
  • My PR uses i18n (internationalization) keys instead of hardcoded English text, to allow for translations. No user-visible text.
  • My PR includes details on how to test it. I've provided clear instructions to reviewers on how to successfully test this fix or feature.
  • If my PR includes new libraries/dependencies (in package.json), I've made sure their licenses align with the DSpace BSD License. None added.
  • If my PR includes new features or configurations, I've provided basic technical documentation in the PR itself. No new configuration.
  • If my PR fixes an issue ticket, I've linked them together.

…mation

Backport of #1333, already on customer/TUL, customer/lindat and
customer/mendelu. Written for this branch rather than cherry-picked.

@slideSidebarPadding reads the gutter width from the browser-only CSS-variable store, so the server
has nothing to substitute and renders style="padding-left: *", which is not valid CSS. For a
logged-in user the browser then resolves the real width and the page moves right by the sidebar.
That is visible on every reload, and all the more so now that the anti-flicker overlay holds the
server's paint on screen while it happens.

The gutter now comes from a ds-admin-sidebar-{hidden,unpinned,pinned} class whose padding-left reads
--ds-admin-sidebar-fixed-element-width / --ds-admin-sidebar-total-width. CSS resolves those the same
on the server and in the browser, so there is nothing left to shift and no width is hardcoded. The
pin/unpin slide survives as transition: padding-left, gated behind ds-admin-sidebar-animate, which is
added only after the first paint so the initial resolution never animates.

Measured on the docker stack, logged in, reloading /home: outer-wrapper padding-left goes from
"padding-left: *" (computed 0px, sidebar overlapping the content) to 55px, identical in the SSR
snapshot and the live app, and the horizontal position of #main-content no longer moves at all.

Refs: dataquest-dev/dspace-customers#717

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@milanmajchrak
milanmajchrak merged commit c95706e into customer/jcu Sep 9, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant