Skip to content

App Header

The fixed header bar of the LabXpert app. It is a layout component with three zones — it positions its zones and brings nothing else; everything inside is composed from existing components.

Why three zones

.l-container is a fixed 970px wide and centered, which leaves a margin on both sides. The two outer zones are pulled into that margin, so the navigation keeps the full container width:

   ┌── margin ──┬────────── .l-container (970px) ──────────┬── margin ──┐
   │  __start   │              __nav                       │   __end    │
   │ (absolute) │            (in flow)                     │ (absolute) │
   └────────────┴──────────────────────────────────────────┴────────────┘
        ↑ right: 100%                                    left: 100% ↑

Once the viewport is too narrow for those margins, both zones move into the normal flow and the bar becomes an ordinary three-column flex row.

Viewport__start / __end
>= 1380pxposition: absolute, in the page margin
< 1380pxin the normal flow (the default)

The rules are written mobile-first: the flow case is the default and needs no reset values, the absolute positioning is added in a min-width query.

The breakpoint is derived, not picked: $container-width (970px) + 2 × $app-header-zone-width (205px) = 1380px. Both live in _variables.scss.

Structure

div.l-app-header                          ← fixed bar, background, blur
└── div.l-container.-invisible.l-app-header__bar
    ├── div.l-app-header__start           ← app switcher + product logo
    ├── div.l-app-header__nav             ← LabXpert Navigation
    └── div.l-app-header__end             ← app actions + user account
ClassPurpose
.l-app-headerThe fixed bar: height, background, blur, shadow, z-index
.l-app-header__barGoes on the .l-container, provides the positioning context
.l-app-header__startPulled into the left margin
.l-app-header__navTakes the remaining space (flex: 1 1 100%)
.l-app-header__endPulled into the right margin, content aligned right
.l-app-header-offsetAdd to the first container below the header — clears the fixed bar

WARNING

__bar must sit on the container itself, not on a wrapper inside it. It supplies the position: relative that the two outer zones are positioned against.

Clearing the fixed bar

The header is position: fixed, so the content below needs to clear it. Add .l-app-header-offset to the first container:

html
<div class="l-container -invisible l-app-header-offset">
    ...
</div>

The offset is calculated from $app-header-height + $app-header-content-gap, so it stays in sync when the bar height changes.

Example

The demo below fakes a narrow container so both outer zones stay visible in the docs, and pins the bar in place instead of fixing it to the viewport.

Show Code
html
<!-- The demo wrapper fakes the page margin next to .l-container that the outer
     zones are pulled into, and keeps the fixed bar inside the docs page. -->
<div style="position: relative; height: 120px; overflow: hidden;">
    <div class="l-app-header" style="position: absolute;">
        <div class="l-container -invisible p-x-l l-app-header__bar" style="width: 600px; min-width: 0;">

            <div class="l-app-header__start">
                <div class="h-pos-relative">
                    <button type="button" class="c-btn -icon-btn -small -link h-bg-white" data-target="#app-header-apps" aria-label="Bereich wechseln">
                        <i class="fas fa-grid-round h-color-black" aria-hidden="true"></i>
                    </button>
                    <div class="c-panel -close-backdrop -is-dropdown -is-extra-small" id="app-header-apps" role="menu" aria-haspopup="true" style="width: 300px">
                        <div class="c-panel__inner">
                            <p class="h-type-uppercase h-type-bold h-type-small p-t-xs">Bereich wechseln</p>
                            <ul class="c-list -linklist -fullwidth -small">
                                <li class="c-list__item p-y-xs">
                                    <a class="c-link -secondary -tiny" href="#">LaborPlus</a>
                                </li>
                                <li class="c-list__item p-y-xs">
                                    <a class="c-link -secondary -tiny" href="#">MediCheck</a>
                                </li>
                            </ul>
                        </div>
                    </div>
                </div>

                <a href="#" class="h-flex">
                    <img src="/resources/images/logos/logo-labxpert.svg" width="130" alt="LabXpert" class="m-x-s"/>
                </a>
            </div>

            <div class="l-app-header__nav">
                <ul class="c-nav-labxpert">
                    <li class="c-nav-labxpert__item">
                        <a class="c-nav-labxpert__link c-link" href="#">Start</a>
                    </li>
                    <li class="c-nav-labxpert__item -is-current">
                        <a class="c-nav-labxpert__link c-link" href="#">Protokolle</a>
                    </li>
                </ul>
            </div>

            <div class="l-app-header__end">
                <a href="#" class="c-btn -icon-btn -small -link h-bg-white m-r-s" title="Updates">
                    <i class="far fa-bell h-color-black" aria-hidden="true"></i>
                </a>
                <a href="#" class="c-btn -icon-btn -small -link h-bg-white m-r-s" title="Einstellungen">
                    <i class="far fa-gear h-color-black" aria-hidden="true"></i>
                </a>
                <button type="button" class="c-btn -icon-btn -small -link h-bg-white" aria-label="Benutzerkonto">
                    <i class="fa-solid fa-user h-color-black" aria-hidden="true"></i>
                </button>
            </div>

        </div>
    </div>
</div>

Notes

  • The zone content is composition only: Button, Panel, List, Logo and the LabXpert Navigation.
  • z-index comes from the app-header key of the central z-index map (core/abstracts/_functions.scss), so it is not a loose number in the markup.