How To Build a Portfolio Image Carousel with Synchronized Sliders on a Web Page

Published on December 12, 2019

Luis Manuel

How To Build a Portfolio Image Carousel with Synchronized Sliders on a Web Page

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.


When creating a professional website, using an image carousel to showcase your portfolio will display your experience with front-end development in a fun and creative way. This tutorial will walk you through the essential steps of creating and styling this web page component. You will write the HTML, style it with CSS, and use JavaScript to make the page dynamic. You will also use the MomentumSlider library to create your slider effect.

An example of the type of carousel effect we are looking for is as follows:

Portfolio Carousel Example

Note: This original design belongs to Francesco Zagami, and is published in Dribbble.


Before launching ourselves into developing the design, we must think about how we are going to carry it out, taking into account the technology that we have available.

In this case, carefully observing the design, we can see that the Portfolio Carousel is composed of four independent sliders (images, numbers, titles, and links) that are all synchronized.

With this in mind, we can use the MomentumSlider library without problems, since it allows synchronizing one or several sliders to a main slider. The images could be taken as the main slider, allowing you to synchronize the others (numbers, titles, and links).

Step 1 — Making the HTML Structure

Our HTML code will be minimal, because all the sliders will be generated from JavaScript with the help of the MomentumSlider library. Therefore, our markup will be as follows:

<!-- Container for all sliders and pagination -->
<main class="sliders-container">
    <!-- Here sliders will be injected for images, numbers, titles, and links -->

Please note that we have not included the rest of the decorative elements that you will see in the final demo, in order to focus on the Portfolio code. In the same way, we will not include the CSS code corresponding to these decorative elements, which undoubtedly will make this tutorial more understandable and easier to follow.

In any case, you can always check the complete code in the Github repository.

Step 2 — Adding Styles Using the MomentumSlider Mixin

Even before we have our sliders in the HTML (because they will be generated dynamically with JavaScript), we can already define some styles for them. To do this, we’ll use the new SCSS mixin offered by the MomentumSlider library.

The SCSS mixin to generate the basic CSS styles of any slider created with MomentumSlider can be found in the path scss/_ms-mixin.scss, and can receive the following parameters:

  • $cssClass: CSS class to match the slider container.
  • $slider-length: Length (width or height) of slider container.
  • $slider-center: If slider should be centered.
  • $slide-width: Fixed width for each slide.
  • $slide-height: Fixed height for each slide.
  • $vertical: If slider should be vertical (true), or horizontal (false).
  • $reverse: If slider should have reversed slides (first items at the end).
  • $debug: Show helpful background colors to help debugging.

An example, using the default values, would be the following:

@import "ms-mixin";

@include ms(
  $cssClass: 'ms-container',
  $slider-length: 400px,
  $slider-center: false,
  $slide-width: 90px,
  $slide-height: 90px,
  $vertical: false,
  $reverse: false,
  $debug: false

All parameters are optional, using the previous values by default.

This mixin gives style to our sliders. Let’s see what the SCSS code for our main slider (images) would look like:

@import "ms-mixin";

// Images

$ms-images-slide-width: 700px;
$ms-images-slide-height: 400px;

// Using SCSS mixin to generate the final CSS code for the slider
@include ms(
  $cssClass: 'ms--images', // CSS class to match the slider container
  $slider-length: 100%,    // The slider container will have full width
  $slider-center: false,   // Don't need to center it, as it is full width
  $slide-width: $ms-images-slide-width,   // Fixed width for each slide
  $slide-height: $ms-images-slide-height, // Fixed height for each slide
  $vertical: false, // The slider should be horizontal
  $reverse: false,  // Normal order
  $debug: false     // No debug backgrounds in production

Maybe you have noticed that there are several unnecessary parameters, since they are equal to the default values. However, writing all parameters is recommended to avoid consulting the mixin code.

Also keep in mind that at the beginning, to define the position and dimensions of our slider, it is advisable to define the parameter $debug: true, because this will generate useful background colors for each element of our slider.

Step 3 — Initializing the Slider with JavaScript

With all the basic styles defined, we can initialize our main slider (for the images) as follows:

// Initializing the images slider
var msImages = new MomentumSlider({
    // Element to append the slider
    el: '.sliders-container',
    // CSS class to reference the slider
    cssClass: 'ms--images',
    // Generate the 4 slides required
    range: [0, 3],
    rangeContent: function () {
        return '<div class="ms-slide__image-container"><div class="ms-slide__image"></div></div>';
    // Synchronize the other sliders
    sync: [msNumbers, msTitles, msLinks],
    // Styles to interpolate as we move the slider
    style: {
        '.ms-slide__image': {
            transform: [{scale: [1.5, 1]}]

As shown in this code, the sync parameter receives an Array with instances of other sliders that we want to synchronize with the new slider we are creating. You must have previously initialized those sliders.

Step 4 — Customizing Styles

Having the images slider working properly, we can add the other styles needed to make our portfolio carousel look like the original design:

// Custom styles for images slider
.ms--images {
  left: calc(50% - #{$ms-images-slide-width / 2 - 70px});

  &.ms-container--horizontal .ms-track {
    left: -70px;

  // Slides images
  .ms-slide {
    &:nth-child(1) .ms-slide__image {
      background-image: url('../portfolio-carousel/img/harvey-gibson-498362-unsplash.jpg');
    &:nth-child(2) .ms-slide__image {
      background-image: url('../portfolio-carousel/img/andre-hunter-461305-unsplash.jpg');
    &:nth-child(3) .ms-slide__image {
      background-image: url('../portfolio-carousel/img/joanna-nix-389128-unsplash.jpg');
    &:nth-child(4) .ms-slide__image {
      background-image: url('../portfolio-carousel/img/jurica-koletic-321003-unsplash.jpg');

  .ms-slide__image-container {
    width: 80%;
    height: 80%;
    background-color: rgba(0, 0, 0, 0.3);
    overflow: hidden;

  .ms-slide__image {
    width: 100%;
    height: 100%;
    background-size: cover;

One of the main advantages of MomentumSlider is that it allows us to modify the CSS styles of our slider according to our needs without affecting its functionalities. We can add styles of all kinds, as long as we take care not to overwrite the dimensions of the slides.

Step 5 — Adding Pagination

The library offers several functionalities out of the box, but if we want a pagination component we must implement it ourselves.

This will be the HTML code that we will use, with one element for each slide:

<!-- Pagination for the slider -->
<ul class="pagination">
    <li class="pagination__item"><a class="pagination__button"></a></li>
    <li class="pagination__item"><a class="pagination__button"></a></li>
    <li class="pagination__item"><a class="pagination__button"></a></li>
    <li class="pagination__item"><a class="pagination__button"></a></li>

In this case we will not detail the CSS code needed to make our pagination component look like the design. Instead, let’s look at the JavaScript code to make it work properly:

// Get pagination items
var pagination = document.querySelector('.pagination');
var paginationItems = [].slice.call(pagination.children);

// Update initialization for images slider
var msImages = new MomentumSlider({

    // Update pagination if slider change
    change: function(newIndex, oldIndex) {
        if (typeof oldIndex !== 'undefined') {

// Select corresponding slider item when a pagination button is clicked
pagination.addEventListener('click', function(e) {
    if (e.target.matches('.pagination__button')) {
        var index = paginationItems.indexOf(e.target.parentNode);

Step 6 — Making It Responsive

To make our portfolio carousel look great on small screens, let’s fix some positions and solve some minor issues:

// Responsive styles

@media screen and (max-width: 860px) {
  .ms--numbers {
    left: calc(50% - #{$ms-numbers-slide-width / 2});

  .ms--titles {
    left: calc(50% - #{$ms-titles-slide-width / 2});
    top: calc(50% - #{$ms-titles-slide-height / 2 + 50px});
    text-align: center;

  .ms--links {
    left: calc(50% - #{$ms-links-slide-width / 2});
    top: calc(50% + #{$ms-links-slide-height / 2 + 50px});

  .pagination {
    left: 50%;
    top: calc(100% - 50px);
    transform: translateX(-50%);

@media screen and (max-width: 600px) {
  .ms--images {
    overflow: visible;

@media screen and (max-width: 400px) {
  .ms--titles {
    .ms-slide {
      transform: scale(0.8);

Now our portfolio carousel looks great on screens of any size.


During this tutorial, we have seen the essential elements to create an elegant portfolio carousel.

You can see the final result, as well as the CodePen demo.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us

About the authors
Default avatar
Luis Manuel


Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
Leave a comment

This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Featured on Community

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel