5

I'm trying to achieve the following effect:
The first container, which has among others a class called .top-container, has a height of about one and a half pages. In the beginning, the user shall be able to scroll until the end of this container, but as soon as he reaches it, the container shall become fixed and the following elements are supposed to overlap it by scrolling.

My approach was to detect when the user reaches top-container's end, in order to then change its position to fixed. But how do I detect when the user has reached a certain scroll point?

Are there other approached to achieve the desired effect?

My code:

<div class="container-fluid px-0 top-container">

  <div class="container-fluid bg-test justify-content-center min-vh-100 d-flex">
    <h1 class="align-self-center">PURE</h1>
  </div>

  <div class="container-fluid justify-content-center d-flex collections" *ngIf="collections">
    <div class="row align-self-center justify-content-around">
      <div class="col-12 mb-5 text-center">
        <h1>ALL COLLECTIONS</h1>
      </div>
      <div class="col-3" *ngFor="let collection of collections">
        <div class="flex-row">
          <div class="col-12 text-center">
            <h4>{{collection.name}}</h4>
            <p>- {{collection.desc}} -</p>
          </div>
          <div class="col-12 d-flex justify-content-center">
            <img [src]="collection.image" [alt]="collection.name" class="w-75 align-self-center">
          </div>
        </div>
      </div>
    </div>
  </div>

</div>

<div class="padding-top">
  <app-slider></app-slider>
  <app-presentation></app-presentation>
</div>

CSS:

.top-container {
  background-color: #EDEDED;

  .collections {
    padding: 5%;
    background-color: white;
    h1 {
      font-family: "Zuric Light";
      text-transform: uppercase;
      color: #D3072A;
    }
    h4 {
      font-family: "Zuric Light";
      text-transform: uppercase;
    }
    p {
      font-family: "Zuric Light";
    }
  }

  .bg-test {
    background-image: url("/assets/images/products/pure/pure-upper-side-red.png");
    background-position: bottom left;
    background-size: contain;
    background-repeat: no-repeat;

    h1 {
      line-height: 1;
      margin: 0;
      font-family: "Zuric Bold";
      color: white;
      font-size: 200px;
      text-transform: uppercase;
      &::first-letter {
        margin-left: -0.05em;
      }
    }
    p {
      color: white;
      font-family: "Zuric Light";
      font-size: 30px;
    }
  }
}

3 Answers 3

3

try something like this to get scroll position, by creating an event observable using fromEvent and use sampleTime to prevent having thousands of values

import { fromEvent } from 'rxjs';
import { map, sampleTime } from 'rxjs/operators'; 
...
ngAfterViewInit(): void {
  const tracker = document.querySelector('.yourElement'); // get your element by css class
  const scroll$ = fromEvent(tracker, 'scroll').pipe(
   sampleTime(300), // to prevent getting multiple values in a milisecond
   map(() => tracker.scrollTop)
  );
  let scrollSubscription = windowYOffsetObservable.subscribe((scrollPos) => {
    console.log(scrollPos); // get scroll position
    // you can do your check here
  });
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. Sorry for the dumb question - but where do I put that code? Since simply adding it e.g. AfterViewInit or a HostListener won't log anything.
0

Try to listen to the scroll event with @HostListener until the end of your container. Then, call your function.

1 Comment

How do I listen to a @HostListener only until the end of a container?
0

This is a good job for Intersection Observer (IO). With it you can check how much an element intersects with another element or the screen. Listening to scroll events and calculating the position of an element can result in bad performance, so using IO is recommended approach for such problems.

First you have to define your options for your IO (you can have more than one IO)

let options = {
  rootMargin: '0px',
  threshold: 1.0
}

let observer = new IntersectionObserver(callback, options);

Second, you define which element(s) to watch:

let target = document.querySelector('#yourHeader');
observer.observe(target);

Final step is then to define the callback function and what should happen when the element comes into view/leaves the view:

let callback = (entries, observer) => { 
  entries.forEach(entry => {
    // Each entry describes an intersection change for one observed
    // target element
  });
};

You can also use this polyfill from w3c to support older browsers if needed.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.