homepage >> The Simplest jQuery Slider Ever    
 

Yossef Benharosh is an apt web developer and the author of the eBook The essentials of object oriented PHP.

Yossef Benharosh web developer profile linkedin twitter github

The Simplest jQuery Slider Ever

Sliders are a staple of modern web design. They can display images, text, or other elements in an interactive, visually appealing way. However, most slider plugins are overkill for basic use cases, bloating your project with unnecessary features.

Enter The Simplest jQuery Slider Ever—a lightweight, functional slider that's easy to implement, customize, and understand. Here's how you can add this minimalist slider to your next project.

 

Demo

See the slider in action:

<
>
1
2
3
4
5

 

Download the demo and code for the simplest slider ever

 

HTML Structure

Here’s the bare bones HTML for the slider. It consists of:

  1. A wrapper for the slider.
  2. Navigation buttons (< and >).
  3. A container for the sliding elements.
<div class="simplest-slider-ever">
    <div class="handlers">
        <div class="handler direction before"><</div>
        <div class="handler direction after">></div>
    </div><!--handlers-->
    <div class="flex-wrapper">
        <div class="flex">
            <div class="flex-item">1</div>
            <div class="flex-item">2</div>
            <div class="flex-item">3</div>
            <div class="flex-item">4</div>
            <div class="flex-item">5</div>
        </div><!--flex-->
    </div><!--flex-wrapper-->
</div><!--simplest-slider-ever-->

 

Styling the Slider

A little CSS goes a long way! Here's how we style the slider for a clean, responsive look:

.simplest-slider-ever,
.simplest-slider-ever * {
    clear: both;
    margin: 0 0 0 0;
    padding: 0 0 0 0;
}
.simplest-slider-ever {
    min-height: 100px;
    width: 600px;
    max-width: 100%;
    margin-right: auto;
    margin-left: auto;
    position: relative;
    display: block;
    direction: ltr;
    text-align: left;
}
.simplest-slider-ever .handler.direction {
    direction: ltr;
    text-align: left;
    position: absolute;
    top: 50%;
    margin-top: -13px;
    color: rgba(71, 71, 71, 1);
    font-weight: bold;
    font-size: 24px;
    cursor: pointer;
}
.simplest-slider-ever .handler.before {
    left: 6px;
}
.simplest-slider-ever .handler.after {
    right: 6px;
}
.simplest-slider-ever .handler.direction.disabled {
    color: rgba(71, 71, 71, 0.3);
    cursor: not-allowed;
}
.simplest-slider-ever .flex-wrapper {
    width: calc(100% - 60px);
    margin-right: auto;
    margin-left: auto;
    overflow: hidden;
    border: 1px solid black;
}
.simplest-slider-ever .flex {
    display: flex;
    align-items: center;
    justify-content: center;
    margin-top: 0;
}
.simplest-slider-ever .flex > div {
    height: 180px;
    flex-basis: 180px;
    align-self: center;
    background-color: #efefef;
    color: black;
    text-align: center;
    line-height: 180px;
    margin: 10px 3px;
    border: 1px solid black;
    font-size: 48px;
    font-weight: bold;
    flex-shrink: 0;
}
#simplestSliderAlertProg {
    position: fixed;
    font-weight: 600;
    font-family: monospace;
    bottom: 0;
    right: 0; left: 0;
    height: 40px;
    line-height: 40px;
    background: black;
    color: green;
    font-size: 16px;
    text-align: center;
}

 

Adding Functionality with jQuery

Here’s the JavaScript that brings the slider to life. It not only enables smooth transitions and handles navigation button clicks but also supports intuitive drag and swipe interactions for both desktop and mobile users.

Explanation

  1. Movement Logic:
    The script calculates the current slider position using CSS transforms and moves the slider left or right based on user interactions. It differentiates between short clicks and long presses, applying varying movement distances to create a responsive feel.

  2. Boundaries:
    To ensure a smooth user experience, the slider includes built-in boundary checks that prevent it from moving too far in either direction. When these limits are reached, the corresponding navigation button is disabled, signaling to the user that no further movement is possible.

  3. Responsive Design:
    The slider dynamically recalculates its dimensions on window resize events. This ensures that movement calculations remain accurate across a range of screen sizes, keeping the interface consistent and fluid.

  4. Drag and Swipe Support:
    Enhancing the interaction further, the slider now supports both mouse dragging and touch-based swiping. The script tracks the pointer’s starting position and calculates movement deltas as the user drags or swipes. A small threshold is implemented to distinguish intentional drags from accidental clicks, ensuring that swipe gestures don’t inadvertently trigger click events.

  5. Click Handling on Slider Items:
    To further refine the user experience, additional logic prevents click events on slider items from firing if a drag or swipe is detected. This ensures that only deliberate clicks on an item will trigger associated actions.

  6. Debugging Utility (alertProg):
    For development purposes, the slider includes a utility function called alertProg that displays debugging messages on-screen. This helps developers monitor the slider’s behavior (such as drag events and state changes) in real time. Once the slider is ready for production, the alertProg function can be easily removed or hidden, ensuring that the end-user experience remains clean and unaffected.

var simplestSliderEver = function() {
    const $slider = $('.simplest-slider-ever');
    const $flex = $slider.find('.flex').css('transition', 'transform 0.5s');
    const $handleLeft = $slider.find('.before');
    const $handleRight = $slider.find('.after');
    const $flexItems = $flex.find(".flex-item");
    
    let flexWidth = 400;
    let shortMovement = 100;
    let longMovement = 200;
    let maxMovementRatio = 0.5;
    
    // Dynamically calculate flexWidth and movement values
    function setFlexWidth() {
        flexWidth = ($flex.innerWidth() > 100) ? $flex.innerWidth() : $(document).width() * 0.9; 
        shortMovement = flexWidth / 4;
        longMovement = flexWidth * 2 / 3;
        maxMovementRatio = $(window).width() < 1000 ? 1.5 : 0.5;
    }

    let timeout;

    // Helper function to get current translateX value
    function getTranslateX(element) {
        const transformMatrix = element.css('transform');
        if (transformMatrix === 'none') {
            return 0;
        }
        const matrixValues = transformMatrix
            .replace('matrix(', '')
            .replace(')', '')
            .split(', ');
        return parseFloat(matrixValues[4]) || 0;
    }

    // Move the .flex element by a specified movement
    function moveFlex(movement) {
        const currentLeft = getTranslateX($flex);
        let newLeft = currentLeft + movement;
        $handleLeft.removeClass("disabled");
        $handleRight.removeClass("disabled");

        // Boundaries check
        const maxMovement = flexWidth * maxMovementRatio;
        if (newLeft > maxMovement) {
            newLeft = maxMovement;
            $handleRight.addClass("disabled");
        } else if (newLeft < -maxMovement) {
            newLeft = -maxMovement;
            $handleLeft.addClass("disabled");
        }

        $flex.css('transform', `translateX(${newLeft}px)`);
    }

    // Handle short and long clicks for arrow handlers
    function handleClick($handle, shortMovement, longMovement) {
        setFlexWidth();
        
        $handle.on('mousedown', function () {
            timeout = setTimeout(function () {
                moveFlex(longMovement);
            }, 500); // Long click
        });

        $handle.on('mouseup mouseleave', function () {
            clearTimeout(timeout);
            if (timeout) {
                moveFlex(shortMovement);
            }
        });
    }

    // Set flexWidth on load and resize
    setFlexWidth();
    $(window).on('resize', setFlexWidth);

    // Set up handlers for arrow elements
    handleClick($handleLeft, -shortMovement, -longMovement); // Move left
    handleClick($handleRight, shortMovement, longMovement);    // Move right

    // ----- Add Drag/Swipe Functionality -----
    let isDragging = false;
    let hasDragged = false;  // flag to indicate a drag occurred
    let startX = 0;
    let initialTranslateX = 0;
    const dragThreshold = 5; // movement threshold in pixels

    // Start drag/swipe on mousedown or touchstart on the slider
    $flex.on('mousedown touchstart', function(e) {
        alertProg(e.type);
        setFlexWidth(); // ensure we have the latest width
        isDragging = true;
        hasDragged = false; // reset the drag flag on new drag start

        // Determine the starting X coordinate for mouse or touch
        let clientX = e.pageX;
        if (e.type === 'touchstart') {
            clientX = e.originalEvent.touches[0].pageX;
        }
        startX = clientX;
        initialTranslateX = getTranslateX($flex);
        $flex.css('transition', 'none'); // remove transition for immediate response
        e.preventDefault(); // prevent text selection or scrolling
    });

    // Bind move events to the document so dragging doesn't get “stuck”
    $(document).on('mousemove touchmove', function(e) {
        if (!isDragging) return;
        let clientX = e.pageX;
        if (e.type === 'touchmove') {
            clientX = e.originalEvent.touches[0].pageX;
        }
        let deltaX = clientX - startX;
        // Mark as a drag if movement exceeds the threshold
        if (Math.abs(deltaX) > dragThreshold) {
            hasDragged = true;
        }
        let newTranslateX = initialTranslateX + deltaX;
        const maxMovement = flexWidth * maxMovementRatio;
        if (newTranslateX > maxMovement) {
            newTranslateX = maxMovement;
        } else if (newTranslateX < -maxMovement) {
            newTranslateX = -maxMovement;
        }
        $flex.css('transform', `translateX(${newTranslateX}px)`);
        alertProg(e.type);
    });

    // End drag/swipe on mouseup or touchend
    $(document).on('mouseup touchend', function(e) {
        if (isDragging) {
            alertProg(e.type);
            isDragging = false;
            $flex.css('transition', 'transform 0.5s'); // restore the transition
        }
    });

    // On click of flex items, ignore the click if a drag occurred
    var clickEvent = ('ontouchstart' in window) ? 'touchend' : 'click';

    $slider.on(clickEvent, ".flex-item", function(e) {
        if (hasDragged) {
            // A drag/swipe occurred; reset flag and cancel the click.
            hasDragged = false;
            e.preventDefault();
            return;
        } else {
            // No drag detected; handle the click.
            clickHandler($(this));
        }
    });

    alertProg("Initializing...");
};

simplestSliderEver();

// Example click handler function
function clickHandler($item) {
    alertProg("Ouch!! clicked me!");
    // Or perform any other click functionality on $item.
}

// Debug messages for the programmer
function alertProg(msg) {
    if ($("body").find("#simplestSliderAlertProg").length === 0) {
        $("body").append("<div id='simplestSliderAlertProg'></div>");
    }
    $("#simplestSliderAlertProg").text(msg);
}

 

Download the demo and code for the simplest slider ever

 

Recommended for you:

JavaScript datetime object helper functions

The cornerSlider jQuery plugin

Using jQuery and AJAX to dynamically update a page

 

Disclaimer

As far as I know, the script on this page is functional and harmless. However, I make no guarantees. I also take no responsibility for any damage that may occur when using the script (the chances of any issues arising are slim, but you never know). Please use this script responsibly and with good judgment.