Views & Offsets
View stacking
Views are the fixed frame of an application: BannerView, MainNavView, SideMenuView and PageHeaderView share the screen and must stack without overlapping or fighting over z-index. Instead of hard coded offsets, every view publishes its size as CSS custom properties, and a shared SCSS function adds them up, so each view and each sticky element knows exactly where to sit.
top: 0top: bannerleft: 0top: banner + main nav · left: side menutop: banner + main nav + page headerSee it in action
Scroll the page, show the banner and switch to phone width: the sticky bar always sits right below the page header.
File: view-stack-demo.tsx
"use client";import React from "react";import {Banner,Button,Container,IconDashboard,IconFileList,MainNavView,PageHeaderView,SideMenuItem,SideMenuSection,SideMenuView,StackLayout,Tile,TileContent,TileHeader,useBanner,} from "@brynlabs/fusion-ui";import styles from "./view-stack-demo.module.scss";const BannerToggle = () => {const {showBanner, hideBanner} = useBanner();return (<Buttonsize={"small"}onClick={() =>showBanner(<Banner bannerStyle={"warn"}>Maintenance tonight from 10 pm.{" "}<Button size={"extraSmall"} color={"currentColor"} onClick={hideBanner}>Hide</Button></Banner>,)}>Show banner</Button>);};export const ViewStackDemo = () => (<MainNavViewlogo={<span className={"heading-4-font"}>Shop</span>}menuItems={[{title: "Reports", href: "/preview/view-stack"},{title: "Orders", href: "#orders"},]}><SideMenuViewmenuItems={<SideMenuSection sectionTitle={"Reports"}><SideMenuItemmenuItem={{title: "Revenue", href: "/preview/view-stack", icon: <IconDashboard />}}/><SideMenuItemmenuItem={{title: "Customers", href: "#customers", icon: <IconFileList />}}/></SideMenuSection>}><PageHeaderView pageHeaderTitle={"Revenue"} buttons={<BannerToggle />}><Container direction={"both"}><StackLayout><div className={styles.sticky}>Sticky with get-view-offset("top"): always right below the page header</div>{Array.from({length: 10}, (_, index) => (<Tile key={index}><TileHeader>Section {index + 1}</TileHeader><TileContent>Scroll, show the banner and make the window narrow: every view keeps clear of theothers.</TileContent></Tile>))}</StackLayout></Container></PageHeaderView></SideMenuView></MainNavView>);
How it works
get-view-offset($direction) takes "top", "bottom", "left", "right" or "z-index" and returns a calc() that adds the offsets of all registered views for that direction. The registered views, in stacking order:
| View | Custom properties |
|---|---|
side-menu | --bryn-side-menu-view-offset--top / --left / … / --z-index |
menu-bar | --bryn-menu-bar-view-offset--top / --left / … / --z-index |
main-nav | --bryn-main-nav-view-offset--top / --left / … / --z-index |
loading-bar | --bryn-loading-bar-view-offset--top / --left / … / --z-index |
banner | --bryn-banner-view-offset--top / --left / … / --z-index |
page-header | --bryn-page-header-view-offset--top / --left / … / --z-index |
small-screen-notice | --bryn-small-screen-notice-view-offset--top / --left / … / --z-index |
Each view sets the offsets for the content inside it. When something calls top: get-view-offset("top"), the function produces:
calc(0px+ var(--bryn-side-menu-view-offset--top, 0px)+ var(--bryn-menu-bar-view-offset--top, 0px)+ var(--bryn-main-nav-view-offset--top, 0px)+ var(--bryn-loading-bar-view-offset--top, 0px)+ var(--bryn-banner-view-offset--top, 0px)+ var(--bryn-page-header-view-offset--top, 0px)+ var(--bryn-small-screen-notice-view-offset--top, 0px))
For "z-index" the same summing runs, but it starts at 100. Each view therefore layers naturally above the previous one — no magic numbers required.
Sticky content
Use the function for your own sticky or fixed elements, so they keep clear of all views — whichever are on the page. This is how the on-page menu of this documentation sticks below the page header.
Always transition the properties that use it with var(--transition--x-fast). The offsets change while the views animate, e.g. when the main nav slides away on scroll. With the same transition the element moves along with the views, without it the element jumps.
@use "@brynlabs/fusion-ui" as fusionui; // or "pkg:@brynlabs/fusion-ui".sticky {position: sticky;top: fusionui.get-view-offset("top");// Moves along with the views instead of jumpingtransition: top var(--transition--x-fast);}h2 {// Anchors are not hidden behind the views when jumped toscroll-margin-top: fusionui.get-view-offset("top");}
Example: a view
A view exposes its height as top offset on its content wrapper, so everything inside starts below it. The bar itself uses the function to sit below everything outside of it, such as a banner.
File: main-nav-view.module.scss
.content {--bryn-main-nav-view-offset--top: var(--bryn-main-nav--height);--bryn-main-nav-view-offset--z-index: -1;}.bar {position: fixed;top: get-view-offset("top");right: get-view-offset("right");left: get-view-offset("left");z-index: get-view-offset("z-index");transition:top var(--transition--x-fast),right var(--transition--x-fast),left var(--transition--x-fast);}

