Кастомный ползунок на JS и CSS

Кастомный ползунок на JS и CSS

Owebs
4 апреля 2023
Просмотры 109
Рейтинг
Время чтения Время чтения: 18 минут

Оглавление
Развернуть Свернуть
 
 
 
 
 
 
 

Сегодня напишем с вами кастомный ползунок. Но не просто стилизуем и напишем к нему код, но и создадим административные кнопки, чтобы можно было назначать максимальную сумму и определять шаг возрастания.

Для создания данной ползунка перекопируйте следующие части кодов:

HTML:
                <div class="rinputRange_container">
                    <div class="set-range">
                        <div class="set-range--min" style="display:none">
                            <label for="min">Min</label>
                            <input class="input input-min" type="number" id="min" name="inputMin" min="0" max="10000" value="0">
                        </div>
                        <div class="set-range--max">
                            <label for="max">>Max</label>
                            <input class="input input-max" type="number" id="max" name="inputMax" min="0" max="100000" value="5000">
                        </div>
            
                        <div class="set-range--step">
                            <label for="step">Step</label>
                            <input class="input input-step" type="number" id="step" name="inputStep" min="1" max="10000" value="50">
                        </div>
                    </div>
            
                    <div class="range-container">
                        <div class="total"></div>
            
                        <div class="range-track">
                            <div class="thumb thumb-left" data-direction="left">
                                <div class="thumb-left--value"></div>
                            </div>
            
                            <div class="range-fill"></div>
            
                            <div class="thumb thumb-right" data-direction="right">
                                <div class="thumb-right--value"></div>
                            </div>
            
                            <div class="range">
                                <div class="range-min"></div>
                                <div class="range-mid"></div>
                                <div class="range-max"></div>
                            </div>
                        </div>
                    </div>
                </div>
            
CSS:
                :root {
                    --white0: #f6f9fb;
                    --white1: #ebf1f6;
                    --white2: #c0d7ed;
        
                    --black0: #0e1011;
                    --black1: #131516;
                    --black2: #242a2d;
                    --black3: #191c1d;
        
                    --grey1: #212529;
                    --grey2: #697680;
                    --darkgrey1: #1f2223;
                    --darkgrey2: #111314;
        
                    --primary1: #2874ae;
                    --primary2: #04508a;
                    --primary3: rgba(40, 116, 174, 0.9);
                    --primary4: #022b41;
        
                    --z-track: 1;
                    --z-fill: 100;
                    --z-thumb: 200;
                    --z-thumb-value: 300;
                }
        
                .rinputRange_container {
                    background-color: #000;
                    color: #fff;
                    padding: 20px 10px;
                }
        
                .set-range {
                    display: flex;
                    max-width: 32rem;
                    width: 100%;
                    height: 4rem;
                    column-gap: 1rem;
                }
        
                .set-range div {
                    display: flex;
                    flex-direction: column;
                    row-gap: .25rem;
                    column-gap: .5rem;
                }
        
                .set-range div label {
                    font-size: .75rem;
                    padding: 0 .25rem;
                    color: var(--white3);
                }
        
                .set-range div input {
                    width: 100%;
                    height: 1.5rem;
                    border: none;
                    border-radius: 4px;
                    background: var(--black2);
                    color: var(--white2);
                    font-size: .75rem;
                    outline: none;
                    padding: 0 .5rem;
                }
        
                .range-container {
                    position: relative;
                    width: 100%;
                    max-width: 32rem;
                    height: 9rem;
                    display: flex;
                    justify-content: center;
                    align-items: center;
                }
        
                .total {
                    position: absolute;
                    top: .375rem;
                    left: 0;
                    width: 100%;
                    user-select: none;
                    font-size: .75rem;
                    margin-left: 2rem;
                    padding: 0 .5rem;
                    line-height: .75rem;
                }
        
                .total::before {
                    position: absolute;
                    content: "TOTAL";
                    line-height: .75rem;
                    font-weight: 600;
                    font-size: .5rem;
                    letter-spacing: 1px;
                    color: var(--white3);
                    transform: translateX(-120%);
                }
        
                .range-track {
                    width: 100%;
                    min-width: 100%;
                    height: 1rem;
                    position: relative;
                    border-radius: 6px;
                    background: var(--black2);
                }
        
                .range-track::after {
                    position: absolute;
                    content: "";
                    width: 100%;
                    margin: 0 auto;
                    height: .5rem;
                    top: 1.5rem;
                    left: 0;
                    border: none;
                    background-image:
                        linear-gradient(to left, var(--grey2) .125rem, transparent 0);
                    background-size: 10% 100%;
                }
        
                .thumb-left,
                .thumb-right {
                    position: absolute;
                    top: 0;
                    height: 2rem;
                    width: .25rem;
                    background: var(--primary1);
                    z-index: var(--z-thumb);
                    border-radius: 4px;
                }
        
                .thumb-left::before,
                .thumb-right::before {
                    position: absolute;
                    top: 0;
                    left: 0;
                    width: .5rem;
                    background: transparent;
                    height: 100%;
                    content: "";
                    border-radius: 4px;
                    transform: translateX(-.125rem);
                }
        
                .thumb-left:hover::before,
                .thumb-right:hover::before {
                    background: var(--primary3);
                }
        
                .thumb-left {
                    transform: translateY(-25%);
                }
        
                .thumb-right {
                    transform: translate(-2px, -25%);
                }
        
                .range-fill {
                    position: absolute;
                    top: 0;
                    background: var(--primary1);
                    height: 100%;
                    z-index: var(--z-fill);
                }
        
                .thumb-left--value,
                .thumb-right--value {
                    position: relative;
                    width: fit-content;
                    padding: 0 .5rem;
                    height: 1rem;
                    background: var(--primary1);
                    color: var(--white0);
                    border-radius: 4px;
                    z-index: var(--z-fill-value);
                    display: flex;
                    justify-content: center;
                    align-items: center;
                    font-size: .625rem;
                    user-select: none;
                    pointer-events: none;
                }
        
                .thumb-left--value {
                    top: -1.8rem;
                    transform: translateX(calc(-50% + 2px));
                }
        
                .thumb-right--value {
                    top: 2.8rem;
                    transform: translateX(calc(-50% + 2px));
                }
        
                .thumb-left--value::after,
                .thumb-right--value::after {
                    content: "";
                    position: absolute;
                    bottom: 0;
                    left: 0;
                    right: 0;
                    width: 0;
                    height: 0;
                    margin: 0 auto;
                    border: 0.25rem solid transparent;
                }
        
                .thumb-left--value::after {
                    transform: translateY(0.15rem);
                    border-top-color: var(--primary1);
                    border-bottom: 0;
                }
        
                .thumb-right--value::after {
                    transform: translateY(-0.95rem);
                    border-bottom-color: var(--primary1);
                    border-top: 0;
                }
        
                .range {
                    position: absolute;
                    width: calc(100% - .125rem);
                    height: 5rem;
                    display: flex;
                    align-items: center;
                    font-size: .625rem;
                    top: 0;
                    left: 0;
                    z-index: var(--z-fill-value);
                    box-sizing: border-box;
                }
        
                .range div {
                    user-select: none;
                    pointer-events: none;
                    height: 100%;
                    display: flex;
                    width: 100%;
                    align-items: flex-end;
                    position: relative;
                }
        
                .range div::after {
                    content: "";
                    position: absolute;
                    bottom: 0;
                    margin: 0 auto;
                    width: .125rem;
                    background: var(--grey2);
                    height: calc(100% - 3.875rem);
                    transform: translateY(-2.5rem);
                    border-radius: 4px;
                }
        
                .range-mid {
                    justify-content: center;
                }
        
                .range-max {
                    justify-content: flex-end;
                }
        
                .range-min::after {
                    left: 0;
                    right: 100%;
                }
        
                .range-mid::after {
                    left: 0;
                    right: 0;
                }
        
                .range-max::after {
                    right: 0;
                    left: 100%;
                }
        
                @media screen and (max-width: 500px) {
                    html {
                        font-size: 16px;
                    }
                }
        
                @media screen and (max-width: 380px) {
                    html {
                        font-size: 12px;
                    }
                }
            
JS:
                const $ = document.querySelector.bind(document);
                class Range {
                    constructor() {
                        this.track = $(".range-track");
                        this.thumbLeft = $(".thumb-left");
                        this.thumbRight = $(".thumb-right");
                        this.thumbLeftValue = $(".thumb-left--value");
                        this.thumbRightValue = $(".thumb-right--value");
        
                        this.rangeFill = $(".range-fill");
                        this.rangeMin = $(".range-min");
                        this.rangeMid = $(".range-mid");
                        this.rangeMax = $(".range-max");
        
                        this.inputContainer = $(".set-range");
                        this.inputMin = $(".input-min");
                        this.inputMax = $(".input-max");
                        this.inputStep = $(".input-step");
                        this.total = $(".total");
                    }
        
                    init() {
                        this.setLeft(+this.inputMin.value);
                        this.setRight(+this.getMidValue());
                        this.calcFill();
                        this.setTotal();
                        this.setRangeValues();
                        this.setDefaultInputSteps();
                    }
        
                    getInputMin() {
                        return +this.inputMin.value;
                    }
        
                    getInputMax() {
                        return +this.inputMax.value;
                    }
        
                    getInputStep() {
                        return +this.inputStep.value;
                    }
        
                    getMidValue() {
                        return Math.floor((this.getInputMax() - this.getInputMin()) / 2);
                    }
        
                    getLeftValue() {
                        return parseInt(this.thumbLeft.getAttribute("data-value"));
                    }
        
                    getRightValue() {
                        return parseInt(this.thumbRight.getAttribute("data-value"));
                    }
        
                    getLeft() {
                        return +this.thumbLeft.style.left.slice(0, -1);
                    }
        
                    getRight() {
                        return +this.thumbRight.style.left.slice(0, -1);
                    }
        
                    getWidth() {
                        return this.getRight() - this.getLeft();
                    }
        
                    setInputStep(e) {
                        const =;
                        const val = +e.target.value;
                        if (min % val !== 0) { this.inputMin.value = Math.round(min / val) * val; }
                        if (max % val !== 0) { this.inputMax.value = Math.round(max / val) * val; }
                        this.init();
                    }
        
                    setDefaultInputSteps() {
                        const step = this.getInputStep();
                        this.inputMin.step = step;
                        this.inputMax.step = step;
                    }
        
                    setRangeValues() {
                        this.rangeMin.textContent = `$${this.getInputMin()}`;
                        this.rangeMid.textContent = `$${this.getMidValue()}`;
                        this.rangeMax.textContent = `$${this.getInputMax()}`;
                    }
        
                    setLeft(val) {
                        this.thumbLeftValue.textContent = `$${val}`;
                        this.thumbLeft.style.left = `${this.calcPercent(parseInt(val))}%`;
                        this.thumbLeft.setAttribute("data-value", val);
                    }
        
                    setRight(val) {
                        this.thumbRightValue.textContent = `$${val}`;
                        this.thumbRight.style.left = `${this.calcPercent(parseInt(val))}%`;
                        this.thumbRight.setAttribute("data-value", val);
                    }
        
                    setTotal() {
                        this.total.textContent = `$ ${this.getRightValue() - this.getLeftValue()}`;
                    }
        
                    calcPercent(val) {
                        const =;
                        return ((val - min) / (max - min)) * 100;
                    }
        
                    calcFill() {
                        const =;
                        this.rangeFill.style.width = `${right - left}%`;
                        this.rangeFill.style.left = `${left}%`;
                    }
        
                    calcValue(percent) {
                        const =;
                        return Math.round((max - min) * percent) + min;
                    }
        
                    move(e, direction) {
                        const parentRect = this.track.getBoundingClientRect();
                        const =;
                        const =;
                        const =;
                        const step = this.getInputStep();
        
                        const handlemove = (e) => {
                            const offsetLeft = e.clientX - parentLeft;
                            const percent = offsetLeft / parentWidth;
                            const val = this.calcValue(percent);
        
                            if (direction === "left" && (val <= min || val > right - step)) return;
                            if (direction === "right" && (val < (left + step)) || val > max) return;
        
                            const stepVal = Math.round(val / step) * step;
                            if (direction === "left") {
                                this.setLeft(stepVal);
                            } else {
                                this.setRight(stepVal);
                            }
                            this.calcFill();
                            this.setTotal();
                        };
        
                        const handleup = () => {
                            document.removeEventListener("mousemove", handlemove);
                            document.removeEventListener("mouseup", handleup);
                        };
                        document.addEventListener("mousemove", handlemove);
                        document.addEventListener("mouseup", handleup);
                    }
                }
        
                const delegateMove = e => {
                    if (e.target.closest(".thumb")) {
                        e.target.getAttribute("data-direction") === "left"
                            ? range.move(e, "left") : range.move(e, "right");
                    }
                };
                const delegateInput = e => {
                    if (e.target.closest(".input")) {
                        e.target.name === "inputStep" ? range.setInputStep(e) : range.init();
                    }
                };
        
                const range = new Range();
                range.init();
                range.track.onmousedown = delegateMove;
                range.inputContainer.oninput = delegateInput;
            

После копирования вышеупомянутых кусков кода, наш ползунок готов. 

Ow
Имя:
Комментарий:
Развернуть все Скрыть
Декор Декор

Популярные Популярные

Анимированный индикатор для пунктов меню на сайте
Просмотры 151
Рейтинг 15
8 декабря
4 месяцев назад

Расскажем как написать анимированный индикатор для пунктов меню на сайте. Так портал станет более интерактивным и привлекательным для пользователей.

Оформления блока акций через CSS
Просмотры 258
Рейтинг 6
14 декабря
4 месяцев назад

В данном уроке будем стилизовать текст для объявлений об акции. Необходимо сделать так, чтобы наше объявление привлекло потенциальных покупателей

Создание сайтов через нейросети
Просмотры 322
Рейтинг 4
9 февраля
2 месяцев назад

Популярность нейросетей в 2024 году набирает обороты. Нет, они не заменяют полноценных специалистов. Зато существенно упрощают и ускоряют работу тех же копирайтеров, сеошников и дизайнеров.

Сегодня мы расскажем, какие нейросети можно использовать в работе, разберем их функционал и приведем примеры генерации.

Оставьте заявку СЕЙЧАС

Поставив галочку, Вы даете согласие на обработку ваших Персональных данных

>