Angular 6 - CSS - STICKY Header
Solution 1
Before I answer your question, you may consider:
- Remove static styles from your HTML.
- Use reasonable z-index, so you won't end up with z-index of something like
z-index: 100000000
. - Use
!important
only when there's no other choice.
Since we can't write Angular code via StackOverflow's snippets, I wrote the code using Stackblitz - https://stackblitz.com/edit/angular-ii5tnn
To make a position sticky, well, you simply use position: sticky
, with additional top
or bottom
rule (in this case - top). For example:
mat-toolbar {
position: sticky;
top: 50px
}
This way, mat-toolbar
will remain at his position, until we pass it.
In my given example, I did:
- Initialized new Angular 6 and added Material Angular.
- Added
mat-toolbar
with[color="primary"]
and set it to fixed via CSS. - Added
#frugelmap
with custom height just to show it. - Added
mat-toolbar
with[color="warn"]
and set the sticky rules (watch below) - Added
#add-spacing
with lots of lorem ipsum just do demonstrate the sticky effect.
The following CSS rules:
mat-toolbar {
--default-height: 50px;
}
mat-toolbar[color="primary"] {
top: 0;
position: fixed;
height: var(--default-height);
}
mat-toolbar[color="warn"] {
position: sticky;
top: var(--default-height);
}
#frugalmap {
height: 300px;
background-color: #EEE;
}
Solution 2
To avoid the browser support concerns of position: sticky
, you can easily achieve this by using ngClass
to toggle sticky behaviour as:
component.html
<mat-toolbar color="primary" class="fixed-header" >
</mat-toolbar>
<div class="custom-popup" id="frugalmap" ></div>
<mat-toolbar
id="secondToolbar" color="warn"
[ngClass]="{'mat-elevation-z5' : true, 'sticky' : isSticky}">
</mat-toolbar>
usign HostListener
to track scroll position as you should not use JS event handler directly in Angular:
component.ts
isSticky: boolean = false;
@HostListener('window:scroll', ['$event'])
checkScroll() {
this.isSticky = window.pageYOffset >= 250;
}
finally adding style for our custom class sticky
.
component.css
.fixed-header {
position: fixed;
z-index:999;
height: 50px;
}
#frugalmap {
height: 300px;
width: 100%;
top: 50px;
position: relative;
}
.mat-elevation-z5 {
position: relative;
}
.sticky {
position: fixed;
top: 50px;
}
Solution 3
Since the other answer mostly rely on CSS that is not available in all browsers I'll allow myself to advertise my lib angular-sticky-things.
It has a feature that is called 'boundary element' and you can see it in action in the above link. What you do is basically you slice your page in sections (what you usually already have) and then you tell an element to be sticky within the boundaries of the parent element.
Here you can see it in action:
<div #boundary style="height:1000px;">
<div #spacer></div>
<div stickyThing [spacer]="spacer" [boundary]="boundary">
I am sticky but only inside #boundary!
</div>
</div>
Just install the lib, add my code and replace the div with stickyThing
with a mat-toolbar. That's basically it.
npm install @w11k/angular-sticky-things
Solution 4
I couldn't use the code of your question because I didn't have all of your code. So, I wrote you an example of what you want to do with you second toolbar.
My code is not in angular, but it has the same css styling and a Javascript event handler to add/remove a class to fix the second toolbar to the top. Just replace the elements with your own elements, classnames.
Notice
First of all, Take a look at this quesion CSS Sticky buttons div not working in IE 11.
In some use cases, your element might have a dynamic position and height and you have to get
element.clientHeight
to get the position of fixing your element. In this case, you have to use JS.
that you can use t
document.addEventListener("scroll", function(){
var secondToolbar = document.querySelector('.toolbar-2');
var map = document.querySelector('.map');
if ((window.pageYOffset + 50) > (map.offsetTop + map.clientHeight))
secondToolbar.classList.add('fixed');
else
secondToolbar.classList.remove('fixed');
});
body {
margin: 0;
}
*{
box-sizing: border-box;
}
.container {
width: 300px;
height: 1000px;
padding-top: 50px;
}
.toolbar-1,
.toolbar-2,
.map {
display: block;
width: 300px;
color: #aaa;
text-align: center;
padding: 15px;
border: 1px solid #242424;
}
.toolbar-1 {
position: fixed;
height: 50px;
top: 0;
left: 0;
background-color: #f8f8f8;
}
.toolbar-2 {
height: 50px;
}
.toolbar-2.fixed{
position: fixed;
top: 50px;
left: 0;
}
.map {
height: 250px;
background-color: #f8f8f8;
}
<div class="container">
<div class="toolbar-1">First Toolbar</div>
<div class="map">Map</div>
<div class="toolbar-2">Second Toolbar</div>
</div>
Comments
-
Newbiiiie almost 2 years
I have 3 elements : 1 toolbar, 1 map , an other toolbar. the elements are one below the other
I want that the second toolbar stay under the map element (at 400px of the top) but when i scroll down, my second toolbar will stop at 50px of the top and will fix under the first.
Thanks for your help
//Component.html
<mat-toolbar color="primary" [ngStyle]="{'height':'50px'}" class="fixed-header" > </mat-toolbar> <div class="custom-popup" id="frugalmap" ></div> <mat-toolbar color="warn" class="mat-elevation-z5"> </mat-toolbar>
//Component.css
.fixed-header { position: fixed; z-index:999; } #frugalmap { height: 300px; width: 100%; margin-top:50px; } .mat-elevation-z5 { position: relative; z-index: 2; }