Edit: OK, I updated my response with a dynamic solution. I created wrapper <div>
elements around the display/input elements. These wrappers allow you to define both a start-hue
and end-hue
data attribute. These are used as the gradient start/end for the display.
It's easy to miss (since you have to scroll all the way to the bottom), but with the plugin below; you can call GradientSlider()
after your page loads.
The "static" default properties are at the bottom of the function definition. This can easily be re-written into an ES5/6 class.
GradientSlider.defaultOptions = {
selector : '.gradient-slider'
};
Various sliders are created below. I borrowed Infodev's absolute-value trick to adjust the saturation value as the slider approaches and 50%.
function GradientSlider(options) {
let opts = Object.assign({}, GradientSlider.defaultOptions, options);
construct(opts.selector); // Begin...
function construct(selector) {
Array.from(document.querySelectorAll(selector))
.forEach(gradientSlider => initializeSlider(gradientSlider));
}
function initializeSlider(gradientSlider) {
let hueStart = parseInt(gradientSlider.getAttribute('data-start-hue'), 10);
let hueEnd = parseInt(gradientSlider.getAttribute('data-end-hue'), 10);
let display = gradientSlider.querySelector('.gradient-slider-display');
let slider = gradientSlider.querySelector('.gradient-slider-input');
slider.addEventListener('input', onSliderChange);
let percentage = getSliderPercentage(slider);
let hue = percentage < 50 ? hueStart : hueEnd;
display.style.backgroundColor = calculateColor(hue, percentage);
}
function onSliderChange(e) {
let gradientSlider = e.target.parentElement;
let hueStart = parseInt(gradientSlider.getAttribute('data-start-hue'), 10);
let hueEnd = parseInt(gradientSlider.getAttribute('data-end-hue'), 10);
let display = gradientSlider.querySelector('.gradient-slider-display');
let percentage = getSliderPercentage(e.target);
let hue = percentage < 50 ? hueStart : hueEnd;
display.style.backgroundColor = calculateColor(hue, percentage)
}
function calculateColor(hue, percentage) {
return `hsl(${hue}, ${Math.abs(50 - percentage)}%, 50%)`;
}
function getSliderPercentage(slider) {
let value = parseInt(slider.value, 10);
let minValue = parseInt(slider.getAttribute('min'), 10);
let maxValue = parseInt(slider.getAttribute('max'), 10);
return scaleBetween(value, 0, 100, minValue, maxValue);
}
// Source: https://stackoverflow.com/a/60514474/1762224
function scaleBetween(n, tMin, tMax, sMin, sMax) {
return (tMax - tMin) * (n - sMin) / (sMax - sMin) + tMin;
}
}
GradientSlider.defaultOptions = {
selector : '.gradient-slider'
};
GradientSlider(); // Call the plugin...
.gradient-slider,
.gradient-slider > .gradient-slider-display,
.gradient-slider > .gradient-slider-input {
width: 100%;
}
.gradient-slider-display {
height: 50px;
}
<div class="gradient-slider" data-start-hue="120" data-end-hue="0">
<div class="gradient-slider-display"></div>
<input class="gradient-slider-input" type="range" min="1" max="200" value="1" />
</div>
<div class="gradient-slider" data-start-hue="240" data-end-hue="300">
<div class="gradient-slider-display"></div>
<input class="gradient-slider-input" type="range" min="50" max="150" value="75" />
</div>
<div class="gradient-slider" data-start-hue="30" data-end-hue="180">
<div class="gradient-slider-display"></div>
<input class="gradient-slider-input" type="range" min="0" max="10" value="7" />
</div>