Page Layout

Headroom

Add the [data-headroom-nav] attribute to the sds-pageLayout__header element

Use the [data-reacts-to-headroom-nav] attribute to have elements change their top value to match the visible part of the navigation when sticky.

If header is used as module inside <main/>

Add the [data-nav-module] attribute to the sds-pageLayout__header element.
This will take care of telling the page layout to add padding top equal to the nav height and set the header's position to fixed so its sticky behaviour can still work as intended no matter how deeply it is nested within the page's content. This works through the CSS :has() selector on the page layout itself. If the selector isn't supported the default behaviour is applied as a fallback and the nav isn't sticky

<a href="#main" class="sds-skipNavigation sds-box -insetMd sds-scaleInteraction text-underline">
    Skip navigation
</a>
<div class="sds-pageLayout">

    <div class="sds-pageLayout__header" data-headroom-nav>

    </div>

    <main class="sds-pageLayout__main" id="main">

        <div class="sds-pageLayout__mainTop">

        </div>
        <div class="sds-pageLayout__mainCenter">

        </div>
        <div class="sds-pageLayout__mainBottom">

        </div>
    </main>

    <footer class="sds-pageLayout__footer">

    </footer>
</div>
{% render "@skip-navigation" %}
<div class="{{ namespace }}pageLayout{% for mod in pageLayoutModifiers %} {{ mod }}{% endfor %}{% for mod in classes %} {{ mod }}{% endfor %}">
	{% if not navUsedAsModule %}
		<div class="{{ namespace }}pageLayout__header"{% if navUsedAsModule %} data-nav-module{% else %} data-headroom-nav{% endif %}>
	{% endif %}
		{% block header %}
		{% endblock %}
	{% if not navUsedAsModule %}
		</div>
	{% endif %}
	<main class="{{ namespace }}pageLayout__main" id="main">
		{% block breadcrumbs %}
		{% endblock %}
		<div class="{{ namespace }}pageLayout__mainTop">
		{% if navUsedAsModule %}
			<div class="{{ namespace }}pageLayout__header"{% if navUsedAsModule %} data-nav-module{% else %} data-headroom-nav{% endif %}>
		{% endif %}
			{% block headerAsModule %}
			{% endblock %}
		{% if navUsedAsModule %}
			</div>
		{% endif %}
		{% block mainTop %}
		{% endblock %}
		</div>
		<div class="{{ namespace }}pageLayout__mainCenter">
		{% block main %}
		{% endblock %}
		</div>
		<div class="{{ namespace }}pageLayout__mainBottom">
		{% block mainBottom %}
		{% endblock %}
		</div>
	</main>
	{% block contactFooter %}
	{% endblock %}
	<footer class="{{ namespace }}pageLayout__footer">
		{% block footer %}
		{% endblock %}
	</footer>
</div>
{% block misc %}
{% endblock %}
  • Content:
    import spacerTokens from "../../../../config/design-tokens-generated-config/js/spacer";
    export default class SpuerkeessSiteHeadroom {
    
    	constructor() {
    
    		this.fireSpkHeadroom();
    
    	}
    
    	fireSpkHeadroom() {
    
    		let nav = document.querySelector("[data-headroom-nav]");
    
    		if (CSS && CSS.supports && CSS.supports("position", "sticky")) {
    
    			let navHeight = nav.clientHeight;
    			let navTopBar = nav.querySelector(".sds-header__nav").clientHeight;
    
    			let hr = new Headroom(nav, {
    				// vertical offset in px before element is first unpinned
    				offset : navHeight,
    				// or you can specify offset individually for up/down scroll
    
    				// scroll tolerance in px before state changes
    				tolerance : 0,
    				// or you can specify tolerance individually for up/down scroll
    
    				// css classes to apply
    				classes : {
    					// when element is initialised
    					initial : "-headroom",
    					// when scrolling up
    					pinned : "-headroomPinned",
    					// when scrolling down
    					unpinned : "-headroomUnpinned",
    					// when above offset
    					top : "-headroomTop",
    					// when below offset
    					notTop : "-headroomNotTop",
    					// when at bottom of scroll area
    					bottom : "-headroomBottom",
    					// when not at bottom of scroll area
    					notBottom : "-headroomNotBottom",
    					// when frozen method has been called
    					frozen: "-headroomFrozen",
    
    				},
    
    				// callback when pinned, `this` is headroom object
    				onPin : function() {
    					nav.style.top = 0;
    					$('[data-reacts-to-headroom]')?.css("top", `${navTopBar + parseInt(spacerTokens.SpacerUnit8, 10)}px`);
    
    				},
    				// callback when unpinned, `this` is headroom object
    				onUnpin : function() {
    					nav.style.top = `-${navTopBar}px`;
    					$('[data-reacts-to-headroom]')?.css("top", `${spacerTokens.SpacerUnit8}`);
    				},
    				// callback when above offset, `this` is headroom object
    				onTop : function() {
    					$('[data-reacts-to-headroom]')?.css("top", `${navTopBar}px`);
    				},
    				// callback when below offset, `this` is headroom object
    				onNotTop : function() {},
    				// callback when at bottom of page, `this` is headroom object
    				onBottom : function() {},
    				// callback when moving away from bottom of page, `this` is headroom object
    				onNotBottom : function() {}
    			});
    			hr.init();
    		} else {
    			console.log("no position: sticky; support");
    		}
    
    	}
    
    }
  • URL: /components/raw/spk-page-layout/SpuerkeessSiteHeadroom.js
  • Filesystem Path: components/spuerkeess-site/frames/page-layout/SpuerkeessSiteHeadroom.js
  • Size: 2.3 KB
  • Content:
    /* variables specific to current element */
    
    $element-specific-variables: "";
    
    .#{$namespace}pageLayout {
    
    	/* Save root element context for easy access if nesting is needed */
    
    	$self: &;
    
    	/* properties of current element  + media queries */
    	display: flex;
    	flex-direction: column;
    	min-height: 100%;
    
    	/* Pseudo Elements */
    
    	&::before {
    	}
    
    	&::after {
    	}
    
    	/*
    	Include elements that are linked to the current element but have to reside at the root level of the stylesheet
    	(e.g: keyframes)
    	*/
    	@at-root {
    
    		//@keyframes lose-focus {
    		//	from {
    		//		outline-width: 2px;
    		//	}
    		//
    		//	to {
    		//		outline-width: 0;
    		//
    		//	}
    		//}
    
    
    	}
    
    	/* children - write selector in full in comments in order to facilitate search */
    
    	// pageLayout__header
    	&__header {
    
    		// follows same logic as parent
    		position: sticky;
    		z-index: z("fixed");
    		top: 0;
    		transition: top $snet-frame-main-header-transition-duration-global linear;
    
    		&[data-nav-module] {
    
    			position: fixed;
    			left: 0;
    			width: 100%;
    
    		}
    
    	}
    
    	&__main {
    
    		margin-bottom: map-deep-get($token-spacer-content-section-map, "sm");
    		flex-grow: 1;
    		//outline: 0 solid map-deep-get($design-tokens,"ui-interaction-active-border-color");
    		//outline-offset: -2px;
    
    		//&:target {
    		//
    		//	animation: lose-focus 2s linear forwards
    		//
    		//}
    
    
    		@include media-breakpoint-up("lg") {
    
    			margin-bottom: map-deep-get($token-spacer-content-section-map, "m");
    
    		}
    
    	}
    
    	&__footer {
    
    
    
    	}
    
    	&:has([data-nav-module]) {
    
    		padding-top: $nav-topbar-height-global;
    
    	}
    
    
    	/* modifiers */
    
    	// pageLayout -mainNoSpacing
    	&.-mainNoSpacing {
    
    		// follows same logic as base element
    
    		#{$self}__main {
    
    			margin-bottom: 0;
    
    		}
    		
    	}
    
    	/* random parent element */
    	/* 
    	*
    	*   Syntax : .randomParentElt & {}
    	*
    	*/
    
    	/* Pseudo Classes */
    
    	&:hover {
    		@media (hover: hover) {
    
    		}
    	}
    
    	&:focus {
    	}
    
    	&:active {
    	}
    
    	&:focus,
    	&:active {
    	}
    
    }
  • URL: /components/raw/spk-page-layout/_page-layout.scss
  • Filesystem Path: components/spuerkeess-site/frames/page-layout/_page-layout.scss
  • Size: 1.9 KB