This website requires JavaScript to deliver the best possible experience.

Re-imaging the Full Screen Experience with Focus

Full screen pages are always a great way to catch your audience attention. Do you want to make a presentation that sharpens your ideas and articulates your points? Do you want to design a portfolio page that showcases your awesome works? Focus, a full-screen scrolling website component offers just that. Learn how we built Focus, and the functionality behind it.

Here’s how we built Focus:

Focus mainly functions on the following variables:

  • Sections
  • CurrentSection
  • Slides
  • SlidesCount
  • ActiveSlide
  • CurrentSlides
  • IsSliding
  • ScrollingValues

Initiating methods

We start with the initializing functions to set some primitive values.

initDots( )

It's used to initialize the side navigation dots, that show a list of dots, one for each slide, with an indicator to the current active slide.

initDots() {
 this.fragment = document.createDocumentFragment();
 const focusNav = document.createElement('ul');

 focusNav.classList.add('focus-nav');
 focusNav.insertAdjacentHTML('afterbeing', '<li><a class="focus-dit"></a></li>'.repeat(this.sections.length));

 this.fragment.appendChild(focusNav);
 document.body.appendChild(this.fragment);

 this.dots = Array.from(document.querySelectorAll('.focus-dot'));
 this.dots.forEach((dot, index) => {
   dot.addEventListener('click', () => {
     this.goToSection(index);
   }, false);
 });
}

initKeyboard( )

A function that makes Focus keyboard-enabled, allowing the user to navigate through slides, both horizontally and vertically, using arrow buttons.

initKeyboard() {
 window.addEventListener('keydown', (event) => {
   if(event.defaultPrevented) {
     return;
   }

   switch(event.key) {
     case 'ArrowDown':
       this.nextSection();
       break;
     case 'ArrowUp':
       this.previousSection();
       break;
     case 'ArrowRight':
       this.slideRight();
       break;
     case 'ArrowLeft':
       this.slideLeft();
       break;
     default:
       return;
   }

   // Cancel the default action to avoid it being handled twice
   event.preventDefault();
 }, true)
}

initScroll ( )

This one handles the mouse wheel for scrolling through different slides.

initScroll() {
 function handler(e) {
   event.preventDefault();
   // get scrolling value
   const value = e.wheelDelta || -e.deltaY || -e.detail;

   //get scrolling direction
   const delta = Math.max(-1, Math.min(1, value));

   if(this.scrollingValues.length < 99) {
     this.scrollingValues.shift();
   }

   this.scrollingValues.push(Math.abs(value));
   const scrollingStart = getAverage(this.scrollingValues, 50);
   const scrollingEnd = getAverage(this.scrollingValues, 10);

   if(scrollingEnd < scrollingStart) return;
   if(delta === 1) {
     this.previousSection();
     return false;
   }
   if(delta === -1) {
     this.nextSection();
     // Cancel default browser behavior
     return false;
   }
 }

 window.addEventListener('mousewheel', handler.bind(this), false);
 // firefox
 window.addEventListener('DOMMouseScroll', handler.bind(this), false);

}

Helper methods

Those are two methods that return the array of slides, and their length. They come in handy in navigation methods.

getSlides( )

It returns an array of slides.

getSlides() {
 return this.sections.map((section) => {
   return Array.from(section.querySelectorAll('.slide'));
 });
}

getSlidesCount( )

It returns the length of the array of slides.

getSlidesCount() {
 return this.sections.map((section) => {
   return Array.from(section.querySelectorAll('.slide')).length;
 })
}

Navigating methods

Here we define the methods that are responsible for actually navigating through different slides and sections.

nextSection( )

takes us to the next section, vertically.

nextSection() {
 if(this.currentSection >= (this.sections.length - 1)) return;
 this.goToSection(this.currentSection + 1);
}

previousSection( )

It takes us to the previous section.

previousSection() {
 if(this.currentSection <= 0) return;
 this.goToSection(this.currentSection - 1);
}

goToSection(index)

This method takes an index as its argument, and navigates the user to the slide specified by that index.

goToSection(index) {
 if(this.isSliding) return;
 this.isSliding = true;

 this.el.style.transform = `translate3d(0, -${index * window.innerHeight}px, 0)`;
 this.sections[this.currentSection].classList.remove('is-active');
 this.dots[this.currentSection].classList.remove('is-active');
 this.currentSection = index;

 this.sections[this.currentSection].classList.add('is-active');
 this.dots[this.currentSection].classList.add('is-active');
 setTimeout(() => {
   this.isSliding = false;
 }, 500);
}

slideRight( )

It navigates to the next slide to the right.

slideRight() {
 const currentSlideCount = this.slidesCount[this.currentSection];
 const currentSlide = this.currentSlides[this.currentSection];

 if(currentSlide < currentSlideCount - 1) {
   this.goToSlide(currentSlide + 1)
 }
}

slideLeft( )

It navigates to the next slide to the left.

slideLeft() {
 const currentSlide = this.currentSlides[this.currentSection];

 if(currentSlide > 0) {
   this.goToSlide(currentSlide - 1);
 }
}

goToSlide(index)

It navigates to a certain horizontal slide, specified by its index argument.

goToSlide(index) {
 const currentSlideCount = this.slidesCount[this.currentSection];

 if(currentSlideCount === 0) return;
 if(this.activeSlide) this.activeSlide.classList.remove('is-acitve');

 this.activeSlide = this.slides[this.currentSection][index];
 this.activeSlide.classList.add('is-active');

 this.currentSlides[this.currentSection] = index;
 this.sections[this.currentSection].style.,marginLeft = `-${index * 100}%`
}

Utilities

You’ve probably noticed some methods that were not defined, those reusable methods were put in a different file, for better organization of code.

select( )

It's a simple method for selecting a DOM element.

export function select(element) {
 if(typeof element === 'string') {
   return document.querySelector(element);
 }

 return element;
}

getAverage(array, length)

It calculates and returns the mathematical average of an array of values.

export function getAverage(array, length) {
 let sum = 0;
 const elements = array.slice(Math.max(array.length - length, 1));
 elements.forEach((value) => sum = sum + value);

 return Math.ceil(sum / length);
}

getArray(length, value)

It's a method that returns an array with certain length and fills it with the value argument passed to it.

export function getArray(length, value) {
 return new Array(length).fill(value);
}

You can download Focus, and go through the whole repository on Github.

Feel free to contribute to the open source project!

More Articles