How do I make an element scroll to the center of the scroll bar upon entering the page

Viewed 996

I am making an Angular project which has a "timeline" component, which has a overflow-x: scroll element:

.container {
    width: 30vw;
    height: 100vh;
    background-color: aquamarine;
    margin: 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
}

.timeline-box {
    width: 90%;
    position: relative;
}

.timeline-strip {
    background-color: yellow;
    height: 200px;
    display: flex;
    overflow-x: scroll; 
}

.timeline-box:before {
    content: '';
    position: absolute;
    top: 50%;
    border-top: 2px solid black;
    width: 100%;
    height: 0px;
}

.point {
    margin: 0 40px;
    align-self:center;
}
.point:before {
    content: '';
    position: relative;
    left: 50%;
    border-left: 2px solid black;
    top: 20px;
}
  <div class="container">
    <div class="timeline-box">
      <div class="timeline-strip">

        <div class="point">1</div>
        <div class="point">2</div>
        <div class="point">3</div>
        <div class="point">4</div>
        <div class="point">5</div>
        <div class="point">6</div>
        <div class="point">7</div>
        <div class="point">8</div>
        <div class="point">9</div>
        <div class="point">10</div>

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

I want the scroll bar of the .timeline-strip element (not the scrollbar of the page itself) to automatically be in the middle when the user enters the page. How can I achieve this? (I am Using Angular if that helps)

3 Answers

You can do this by by taking the scrollWidth property minus the clientWidth property and divide the result of this by 2. This will be the scroll position halfway so you can set this value to the scrollLeft property.

If your div contains images then you want to do this on the window load event. On the document DOMContentLoaded event the images are not loaded yet (unless cashed) and therefore the size of your div may change when the images will be loaded.

//Can be document.addEventListener('DOMContentLoaded', () => {}) when you don't care about images and stuff
window.addEventListener('load', () => {
  let scrollElement = document.querySelector('.timeline-strip');
  scrollElement.scrollLeft =  (scrollElement.scrollWidth - scrollElement.clientWidth ) / 2;
});
.container {
    width: 30vw;
    height: 100vh;
    background-color: aquamarine;
    margin: 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
}

.timeline-box {
    width: 90%;
    position: relative;
}

.timeline-strip {
    background-color: yellow;
    height: 200px;
    display: flex;
    overflow-x: scroll; 
}

.timeline-box:before {
    content: '';
    position: absolute;
    top: 50%;
    border-top: 2px solid black;
    width: 100%;
    height: 0px;
}

.point {
    margin: 0 40px;
    align-self:center;
}
.point:before {
    content: '';
    position: relative;
    left: 50%;
    border-left: 2px solid black;
    top: 20px;
}
<div class="container">
    <div class="timeline-box">
      <div class="timeline-strip">

        <div class="point">1</div>
        <div class="point">2</div>
        <div class="point">3</div>
        <div class="point">4</div>
        <div class="point">5</div>
        <div class="point">6</div>
        <div class="point">7</div>
        <div class="point">8</div>
        <div class="point">9</div>
        <div class="point">10</div>

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

personally I do not like to use addEventListener, so @ViewChild is better. This depends which angular is used

modify the answer from @ng-hobby:

add a id to the timeline strip div:

<div class="timeline-strip" #timelineStrip >

modify the viewChild and rename if you want:

@ViewChild('timelineStrip', {static: false}) timelineStripRef: ElementRef;

you can use scrollTo on the timelineStripRef element or timeline-strip:

const width = this.timelineStripRef.nativeElement.clientWidth;
this.timelineStripRef.nativeElement.scrollTo(width/2, 0);

I created a sample for you here on Stackblitz

So, Try something like this using @viewChild & ngAfterViewInit with window.scrollTo():

app.component.html

<hello name="{{ name }}"></hello>
<p class="img" #getHeight>
  Start editing to see some magic happen :)
</p>

app.component.ts

import { Component, VERSION, ElementRef, AfterViewInit, ViewChild } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements AfterViewInit {
  name = 'Angular ' + VERSION.major;
  @ViewChild('getHeight', {static: false}) getHeight: ElementRef;
  constructor(private el: ElementRef){}

  ngAfterViewInit() {
    let pageheight = this.getHeight.nativeElement.offsetHeight;
    console.log(pageheight/2)
    window.scrollTo(0, pageheight/2);
  }
}

Related