Fix popups anchored to body instead of viewport due to CSS filter containing block#4
Fix popups anchored to body instead of viewport due to CSS filter containing block#4Copilot wants to merge 2 commits into
Conversation
…f body The root cause was that `body` had `animation: backgroundPulse` which applied CSS `filter` at every keyframe. Per the CSS spec, any element with an active `filter` property creates a new containing block for all `position: fixed` descendants. As a result, the popup overlays (`.movie-popup-overlay`, `.schedule-popup-overlay`) were anchored to the top of the scrolling `body` instead of the viewport — they appeared correctly when at the top of the page but were hidden/unreachable after scrolling down. Fixes: 1. styles.css – remove `animation: backgroundPulse` from `body`; add a `body::before` pseudo-element (`position:fixed; inset:0; z-index:-1; pointer-events:none`) that carries the same animation. A pseudo-element is not an ancestor of the popup overlays, so it never affects their containing block. 2. schedule-list.component.html – move `movie-popup-overlay` outside the `.container` div (same level as the already-correct `schedule-popup-overlay`) and wire all open/close calls to the new component methods. 3. schedule-list.component.ts – add `openMoviePopup/closeMoviePopup` and `openSchedulePopup/closeSchedulePopup` methods that toggle `document.body.style.overflow = 'hidden'` so the background page does not scroll while a popup is visible. `ngOnDestroy` guarantees the overflow is restored if navigation occurs with a popup still open. Agent-Logs-Url: https://github.com/Programmercito/horarios-cine/sessions/3c0406f0-2704-4794-8f9a-7890bc3e6827 Co-authored-by: Programmercito <4504287+Programmercito@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Fixes popup overlays incorrectly anchoring to the page (scrolling away) by removing filter-driven animation from body (which creates a containing block for position: fixed) and restructuring popup placement/handlers to keep overlays viewport-fixed and prevent background scrolling while open.
Changes:
- Move
backgroundPulseanimation offbodyontobody::beforeto avoid creating a containing block for fixed-position overlays. - Relocate popup overlay markup outside the
.containerand route overlay clicks through dedicated close methods. - Add open/close popup methods plus
ngOnDestroycleanup to lock/unlock body scrolling viadocument.body.style.overflow.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
src/styles.css |
Moves filter animation off body to prevent fixed overlays being positioned relative to the body. |
src/app/schedule-list/schedule-list.component.html |
Moves popup overlays to the component root and wires overlay clicks to close handlers. |
src/app/schedule-list/schedule-list.component.ts |
Adds popup open/close methods with body scroll locking and ensures cleanup on destroy. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| body::before { | ||
| content: ''; | ||
| position: fixed; | ||
| inset: 0; | ||
| z-index: -1; | ||
| pointer-events: none; | ||
| animation: backgroundPulse 18s ease-in-out infinite; | ||
| } |
There was a problem hiding this comment.
body::before only sets content/positioning and animates filter, but it has no background (and no rendered content), so the backgroundPulse animation will have no visible effect. If you want to keep the ambient pulse, move the body background (gradient + radial background-image) onto the pseudo-element (or set an explicit background on body::before) and make the body background transparent, so the filter animation affects visible pixels without impacting position: fixed descendants.
| closeMoviePopup() { | ||
| this.showMoviePopup = false; | ||
| document.body.style.overflow = ''; | ||
| } | ||
|
|
||
| // Schedule popup method | ||
| showScheduleDetails(schedule: any, movieTitle: string) { | ||
| this.currentSchedule = schedule; | ||
| this.currentMovieTitle = movieTitle; | ||
| this.openSchedulePopup(); | ||
| } | ||
|
|
||
| openSchedulePopup() { | ||
| this.showSchedulePopup = true; | ||
| document.body.style.overflow = 'hidden'; | ||
| } | ||
|
|
||
| closeSchedulePopup() { | ||
| this.showSchedulePopup = false; | ||
| document.body.style.overflow = ''; | ||
| } |
There was a problem hiding this comment.
closeMoviePopup() and closeSchedulePopup() unconditionally clear document.body.style.overflow. Since showMoviePopup and showSchedulePopup are independent flags, it’s possible for both popups to be open (or to become open in the future); closing one would re-enable background scrolling while the other overlay is still displayed. Consider centralizing the scroll-lock logic (e.g., a helper that sets overflow based on showMoviePopup || showSchedulePopup, or a reference-counted lock) so scroll remains disabled as long as any popup is open.
| openMoviePopup() { | ||
| this.showMoviePopup = true; | ||
| document.body.style.overflow = 'hidden'; | ||
| } |
There was a problem hiding this comment.
Directly touching document.body makes this component harder to test and incompatible with non-DOM runtimes (e.g., SSR) if introduced later. Prefer injecting DOCUMENT (from @angular/common) and/or using Renderer2 to toggle a CSS class on the body for scroll locking, instead of setting inline styles via the global document reference.
Popups always rendered at the top of the page and scrolled away with the content instead of staying fixed to the viewport. Opening a popup while scrolled down made it unreachable.
Root cause
bodyhadanimation: backgroundPulsewhose keyframes appliedfilter: saturate() brightness(). Per CSS spec, any element with an activefiltercreates a new containing block forposition: fixeddescendants — overridingposition: fixed !importanton the overlay divs and anchoring them to the body's coordinate space instead of the viewport.Changes
src/styles.css— Stripanimationfrombody; move it to abody::beforepseudo-element (position: fixed; inset: 0; z-index: -1; pointer-events: none). Pseudo-elements are not DOM ancestors of the popup nodes, so theirfiltercannot affect the popups' containing block.schedule-list.component.html— Movemovie-popup-overlayoutside.containerso both popups sit at the component root, away from any element that could inadvertently become a containing block. Wire(click)handlers to dedicated methods.schedule-list.component.ts— AddopenMoviePopup/closeMoviePopupandopenSchedulePopup/closeSchedulePopupmethods that toggledocument.body.style.overflow = 'hidden'to block background scroll while a popup is open. AddngOnDestroyto guarantee overflow is restored on navigation/component teardown.Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
fonts.googleapis.com/home/REDACTED/work/_temp/ghcca-node/node/bin/node node node_modules/.bin/ng build(dns block)If you need me to access, download, or install something from one of these locations, you can either: