Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making range output responsive

Ok, so the problem I'm having is making the output for the range responsive.

It's currently working fine when you run the code because the value is being position in pixels, but when you resize the viewport is doesn't align with the slider thumb correctly. I thought maybe aligning the output using percentages instead of pixels might fix the problem but I'm not sure how to implement it correctly.

I have tried messing around with it but no luck, does anyone know how I can achieve this?

HTML:

<form>
    <div class="range-control" data-thumbwidth="20">
        <input id="inputRange" type="range" min="0" max="100" step="1" value="0">
            <div><output name="rangeVal">0</output></div>
    </div>
 </form>

CSS:

*,
*:before,
*:after {
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}

html {
    font-family: Arial, sans-serif;
}

form {
    padding-top: 100px;
    margin: 0 auto;
}

.range-control {
    position: relative;
}

input[type=range] {
    display: block;
    width: 100%;
    margin: 0;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    outline: none;
}

input[type=range]::-webkit-slider-runnable-track {
    position: relative;
    height: 12px;
    border: 1px solid #b2b2b2;
    border-radius: 5px;
    background-color: #e2e2e2;
    box-shadow: inset 0 1px 2px 0 rgba(0,0,0,0.1);
}

input[type=range]::-webkit-slider-thumb {
    position: relative;
    top: -5px;
    width: 20px;
    height: 20px;
    border: 1px solid #999;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    background-color: #fff;
    box-shadow: inset 0 -1px 2px 0 rgba(0,0,0,0.25);
    border-radius: 100%;
    cursor: pointer;
}

output {
    position: absolute;
    top: 20px;
    width: 50px;
    height: 24px;
    border: 1px solid #e2e2e2;
    margin-left: -15px;
    background-color: #fff;
    border-radius: 3px;
    color: #777;
    font-size: .8em;
    line-height: 24px;
    text-align: center;
}

input[type=range]:active + output {
    display: block;
}

JQUERY:

$('.range-control').each(function(){
    var container = $(this),
        input = container.find('input'),
        output = container.find('output'),
        rangeWidth = input.width(),
        thumbWidth = container.attr('data-thumbwidth'),
        startValue = input.val(),
        startOffset = ((rangeWidth - thumbWidth) / 100) * startValue + '%';

    output
        .css({
            'left' : startOffset
        });

    $(input).on('input', function(){
        var value = this.value,
            offset = ((rangeWidth - thumbWidth) / 100) * value;

    output
        .val(value)
        .css({
            'left' : offset
        });

    });
});

JSFiddle

Any help would be appreciated greatly!!!

** EDIT ** Please Read

So below Mohamed-Yousef answered the question in the way he would do it which does work, so I have up voted it, however he has duplicated the variables twice in the code (see his answer for details about this). I think there is a more efficient way of doing this (using less code), so if anyone has a better way of doing this please share.

like image 216
Jordan Avatar asked Jun 07 '15 01:06

Jordan


1 Answers

simply you need to update your variable on window resize to change its values .. and make your input event inside each function print it more than one time and that make it not available to read a new variable after resize .. so I take it out and run each event individual

AFTER EDIT

$(document).ready(function(){
    var container,input,output,rangeWidth,thumbWidth,startValue,startOffset;
    // make a function to update variable
    var update_variable = function(){
        $('.range-control').each(function(){
            container = $(this);
            input = container.find('input');
            output = container.find('output');
            rangeWidth = input.width();
            thumbWidth = container.attr('data-thumbwidth');
            startValue = input.val();
            startOffset = ((rangeWidth - thumbWidth) / 100) * startValue;

        output
            .css({
                'left' : startOffset
            });

        });   
    }
    // update variable after document ready
    update_variable();

    // input input event
    $('.range-control > input').on('input', function(){
            var value = this.value,
                offset = ((rangeWidth - thumbWidth) / 100) * value;

        $(this).closest('.range-control').find('output')
            .val(value +'%')
            .css({
                'left' : offset
            });
        });
    // update variable in window resize
    $(window).on('resize',update_variable);  
});

DEMO HERE

Important Note: this code will work perfect if you have inputs with the same width .. if its not the same width you need to use an array of elements to get each element width

like image 124
Mohamed-Yousef Avatar answered Oct 01 '22 19:10

Mohamed-Yousef