<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div data-js="filter" data-filter-file="#svgfilters">
<form class="app" data-elm="app">
<div class="app__header-holder">
<strong class="app__header">CSS Filters</strong>
<button type="reset" class="app__button app__button--reset" data-elm="resetPreset">↺ Reset</button>
</div>
<div class="app__edit">
<div class="app__preview">
<figure class="app__img-wrapper">
<img src="https://fruntend.com/storage/photos/1/raimond-klavins.jpg" class="app__img" data-elm="preview">
</figure>
<div class="app__thumbnails" data-elm="thumbnail">
<button type="button" data-index="0" style="background-image:url(https://fruntend.com/storage/photos/1/raimond-klavins.jpg);"
class="app__img-thumb"></button>
<button type="button" data-index="1" style="background-image:url(https://fruntend.com/storage/photos/1/alex-perri-m2D.jpg);"
class="app__img-thumb"></button>
<button type="button" data-index="2" style="background-image:url(https://fruntend.com/storage/photos/1/sonnie-hiles.jpg);"
class="app__img-thumb"></button>
<button type="button" data-index="3" style="background-image:url(https://fruntend.com/storage/photos/1/zach-miles-Y84.jpg);"
class="app__img-thumb"></button>
<button type="button" data-index="4" style="background-image:url(https://fruntend.com/storage/photos/1/turtle-in-ocean.jpg);"
class="app__img-thumb"></button>
</div>
</div>
<div class="app__controls">
<label class="app__label--range"><span>grayscale</span>
<div class="c-rng--output c-rng__wrapper" style="--rng-thumb-w: 1.5rem;">
<output class="c-rng__output" style="--rng-unit: 0;">0</output>
<input type="range" class="c-rng" min="0" max="1" value="0" step="0.01" name="grayscale" data-elm="grayscale"
data-range="output" id="c36a387f-a7ec-41c1-afcd-3310296d385d" style="--rng-percent: 0%; --rng-value: 0;">
</div>
</label>
<label class="app__label--range"><span>sepia</span>
<div class="c-rng--output c-rng__wrapper" style="--rng-thumb-w: 1.5rem;">
<output class="c-rng__output" style="--rng-unit: 0;">0</output>
<input type="range" class="c-rng" min="0" max="1" step="0.01" value="0" name="sepia" data-elm="sepia"
data-range="output" id="69d04bae-2ef2-42a8-bbbb-b4e28dc5eef4" style="--rng-percent: 0%; --rng-value: 0;">
</div>
</label>
<label class="app__label--range"><span>saturate</span>
<div class="c-rng--output c-rng__wrapper" style="--rng-thumb-w: 1.5rem;">
<output class="c-rng__output" style="--rng-unit: 33.333333333333336;">1</output>
<input type="range" class="c-rng" min="0" max="3" value="1" step="0.1" name="saturate" data-elm="saturate"
data-range="output" id="9d9c6b2a-165e-43bc-84d7-1a061b62bf86"
style="--rng-percent: 33.333333333333336%; --rng-value: 1;"></div>
</label>
<label class="app__label--range"><span>brightness</span>
<div class="c-rng--output c-rng__wrapper" style="--rng-thumb-w: 1.5rem;">
<output class="c-rng__output" style="--rng-unit: 33.333333333333336;">1</output>
<input type="range" class="c-rng" min="0" max="3" value="1" step="0.1" name="brightness" data-elm="brightness"
data-range="output" id="bdc00cfb-aaa7-4c8c-8c7d-aa56a9c640a5"
style="--rng-percent: 33.333333333333336%; --rng-value: 1;"></div>
</label>
<label class="app__label--range"><span>contrast</span>
<div class="c-rng--output c-rng__wrapper" style="--rng-thumb-w: 1.5rem;">
<output class="c-rng__output" style="--rng-unit: 33.333333333333336;">1</output>
<input type="range" class="c-rng" min="0" max="3" value="1" step="0.1" name="contrast" data-elm="contrast"
data-range="output" id="c8ebc330-8cca-44a1-82bd-842077b955ed"
style="--rng-percent: 33.333333333333336%; --rng-value: 1;"></div>
</label>
<label class="app__label--range"><span>hue-rotate</span>
<div class="c-rng--output c-rng__wrapper" style="--rng-thumb-w: 1.5rem;">
<output class="c-rng__output" style="--rng-unit: 0;">0</output>
<input type="range" class="c-rng" min="0" max="360" value="0" name="hue-rotate" data-elm="hue-rotate"
data-suffix="deg" data-range="output" id="52905cd8-de3d-488d-92e0-3f0e160501e8"
style="--rng-percent: 0%; --rng-value: 0;"></div>
</label>
<label class="app__label--range"><span>invert</span>
<div class="c-rng--output c-rng__wrapper" style="--rng-thumb-w: 1.5rem;">
<output class="c-rng__output" style="--rng-unit: 0;">0</output>
<input type="range" class="c-rng" min="0" max="1" value="0" step="0.01" name="invert" data-elm="invert"
data-range="output" id="333e0f67-1b97-44d0-917c-47d4802747c3" style="--rng-percent: 0%; --rng-value: 0;">
</div>
</label>
<label class="app__label--range"><span>blur</span>
<div class="c-rng--output c-rng__wrapper" style="--rng-thumb-w: 1.5rem;">
<output class="c-rng__output" style="--rng-unit: 0;">0</output>
<input type="range" class="c-rng" min="0" max="10" value="0" step="0.1" name="blur" data-elm="blur" data-suffix="px"
data-range="output" id="8812a488-9bb8-4468-89e3-c054f53c729c" style="--rng-percent: 0%; --rng-value: 0;">
</div>
</label>
<label class="app__label--range"><span>opacity</span>
<div class="c-rng--output c-rng__wrapper" style="--rng-thumb-w: 1.5rem;">
<output class="c-rng__output" style="--rng-unit: 100;">1</output>
<input type="range" class="c-rng" min="0" max="1" value="1" step="0.01" name="opacity" data-elm="opacity"
data-range="output" id="1626ff97-15cb-40b7-8e39-a2f605470c79" style="--rng-percent: 100%; --rng-value: 1;">
</div>
</label>
</div>
</div>
</form>
</div>
<script src="scripts.js"></script>
</body>
</html>
.app {
--blur: 0;
--brightness: 1;
--contrast: 1;
--grayscale: 0;
--hue-rotate: 0;
--invert: 0;
--opacity: 1;
--saturate: 1;
--sepia: 0;
}
[data-elm="preview"] {
filter: blur(calc(var(--blur) * 1px)) brightness(var(--brightness)) contrast(var(--contrast)) grayscale(var(--grayscale)) hue-rotate(calc(var(--hue-rotate) * 1deg)) invert(var(--invert)) opacity(var(--opacity)) saturate(var(--saturate)) sepia(var(--sepia));
max-width: 100%;
will-change: filter;
}
.app__img-wrapper::after {
content: '';
display: block;
padding-bottom: 100%;
}
.app__thumbnails {
display: flex;
width: 100%;
}
.app__img-thumb {
background-size: 100%;
border: 2px solid #FFF;
flex: 1;
height: 100px;
background-position: 50% 50%;
cursor: pointer;
background-repeat: no-repeat;
background-size: cover;
}
.app {
--app-fz-large: 1.25rem;
--app-fz-small: 0.75rem;
--app-bdc: #DDD;
--app-inp-brd: 1px solid #DDD;
--app-inp-bdrs: 0.25rem;
--app-inp-ff: monospace;
--app-inp-fz: 1rem;
--app-inp-h: 1.75rem;
--app-inp-p: 0.25rem 0;
--app-lbl-c: #606060;
--app-lbl-m: 0.5rem 0.1rem 0 0.1rem;
--app-m-unit: 1rem;
--app-maw: 64rem;
font-family: -apple-system,BlinkMacSystemFont,segoe ui,Roboto,Oxygen-Sans,Ubuntu,Cantarell,helvetica neue,sans-serif;
margin: var(--app-m-unit) auto;
max-width: var(--app-maw);
padding: 0 calc(var(--app-m-unit)/2)
}
.app * {
box-sizing: border-box
}
.app .c-rng {
--rng-h: 0.25rem;
--rng-m: 1rem 0;
--rng-thumb-h: 1.5rem;
--rng-thumb-w: 1.5rem
}
.app .c-rng__output {
--rng-output-bgc: transparent;
--rng-output-c: #444;
float: right;
left: auto;
position: relative!important;
text-align: right;
top: 1em!important
}
.app .c-rng--output {
margin-bottom: 0
}
.app__button {
background: #ea1515;
color: #fff;
display: inline-flex;
border: 1px solid #ea1515;
border-radius: .25rem;
margin-left: 2rem;
padding: .35rem;
font-size: 1rem;
min-width: 100px;
justify-content: center;
cursor: pointer;
}
.app__controls {
flex: 1 1 100%
}
.app__preview {
display: flex;
flex-direction: column;
width: 100%;
}
@media screen and (min-width: 767px) {
.app__controls {
flex:0 1 calc(50% - (var(--app-m-unit)/2))
}
.app__preview {
max-width: calc(50% - (var(--app-m-unit)/2));
}
}
.app__edit {
display: flex;
flex-wrap: wrap;
justify-content: space-between
}
.app__header-holder {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: .75rem;
}
.app__header {
align-items: center;
color: #222;
display: flex;
font-size: 2rem;
flex-grow: 1;
flex-shrink: 0;
}
.app__img {
bottom: 0;
height: 100%;
left: 0;
object-fit: cover;
position: absolute;
right: 0;
top: 0;
width: 100%
}
.app__img-wrapper {
margin: 0;
padding: 0;
position: relative;
flex-grow: 1;
}
.app__img-wrapper::after {
content: '';
display: block;
padding-bottom: 56.25%
}
.app__label--range {
display: block;
position: relative
}
.app__label--range span {
top: .5rem;
color: gray;
font-size: x-small;
position: absolute
}
.c-rng {
--rng-focus: #064374;
--rng-lower: #6495ED;
--rng-upper: #CFD8DC;
--rng-percent: 0%;
--rng-percent-upper: 80%;
--rng-bdrs: .375rem;
--rng-bgi: linear-gradient(to right, var(--rng-lower) var(--rng-percent), var(--rng-upper) var(--rng-percent));
--rng-h: 0.75rem;
--rng-m: 2rem 0;
--rng-w: 100%;
--rng-label-c: #333;
--rng-label-fz: 0.75rem;
--rng-label-off: 0.25rem;
--rng-thumb-bdrs: 50%;
--rng-thumb-bxsh: none;
--rng-thumb-bxsh--focus: inset 0 0 0 0.25rem var(--rng-focus);
--rng-thumb-bgc: #0960A5;
--rng-thumb-h: 2rem;
--rng-thumb-w: 2rem;
--rng-thumb-z: 1;
background-image: var(--rng-bgi);
border-radius: var(--rng-bdrs);
box-sizing: border-box;
font-family: inherit;
height: var(--rng-h);
margin: var(--rng-m);
outline: none;
position: relative;
width: var(--rng-w)
}
.c-rng::-moz-range-thumb {
background-color: var(--rng-thumb-bgc);
border-radius: var(--rng-thumb-bdrs);
box-shadow: var(--rng-thumb-bxsh);
color: #000;
cursor: ew-resize;
height: var(--rng-thumb-h);
margin-top: calc(0px - ((var(--rng-thumb-h) - var(--rng-h))/2));
position: relative;
width: var(--rng-thumb-w);
z-index: var(--rng-thumb-z)
}
.c-rng::-webkit-slider-thumb {
background-color: var(--rng-thumb-bgc);
border-radius: var(--rng-thumb-bdrs);
box-shadow: var(--rng-thumb-bxsh);
cursor: ew-resize;
height: var(--rng-thumb-h);
margin-top: calc(0px - ((var(--rng-thumb-h) - var(--rng-h))/2));
position: relative;
width: var(--rng-thumb-w);
z-index: var(--rng-thumb-z)
}
.c-rng:focus::-webkit-slider-thumb {
box-shadow: var(--rng-thumb-bxsh--focus)
}
.c-rng::-moz-range-track {
background: 0 0;
background-size: 100%;
border-radius: var(--rng-bdrs);
box-sizing: border-box;
height: var(--rng-h)
}
.c-rng::-webkit-slider-runnable-track {
background: 0 0;
background-size: 100%;
border-radius: var(--rng-bdrs);
box-sizing: border-box;
height: var(--rng-h)
}
.c-rng,.c-rng::-webkit-slider-runnable-track,.c-rng::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none
}
.c-rng::after,.c-rng::before {
color: var(--rng-label-c);
font-size: var(--rng-label-fz);
line-height: 1;
position: absolute;
top: calc(var(--rng-h) + var(--rng-label-off));
z-index: -1
}
.c-rng[data-range*=labels]::after {
content: attr(max);
right: 0
}
.c-rng[data-range*=labels]::before {
content: attr(min)
}
.c-rng__output {
--rng-output-bgc: #444;
--rng-output-c: #EEE;
--rng-output-p: 0.25rem 0 0 0;
--rng-output-t: 0.25rem;
--rng-output-w: 2rem;
background-color: var(--rng-output-bgc);
color: var(--rng-output-c);
display: inline-block;
font-family: sans-serif;
font-size: .675rem;
left: calc(1% * var(--rng-unit) - ((var(--rng-thumb-w)/100) * var(--rng-unit)));
padding: var(--rng-output-p);
position: relative;
text-align: center;
top: var(--rng-output-t);
width: var(--rng-output-w)
}
.c-rng__output::after {
border-left: calc(var(--rng-output-w)/2) solid transparent;
border-right: calc(var(--rng-output-w)/2) solid transparent;
border-top: calc(var(--rng-output-w)/3) solid var(--rng-output-bgc);
content: "";
height: 0;
left: 0;
position: absolute;
top: 100%;
width: 0
}
.c-rng__wrapper .c-rng {
bottom: 1rem;
left: 0;
margin: 0;
position: absolute
}
.c-rng__wrapper .c-rng__output {
position: absolute;
top: 0
}
.c-rng__wrapper {
--rng-ticks-fill: #B0B0B0;
flex: 1;
height: 4rem;
margin-bottom: 1rem;
position: relative
}
const rangeSliders = document.querySelectorAll('.app__label--range');
rangeSliders.forEach(slider => {
const input = slider.querySelector('input');
const output = slider.querySelector('output');
input.addEventListener('input', () => {
const value = input.value;
const variableName = input.getAttribute('data-elm');
const appElement = document.querySelector('.app');
appElement.style.setProperty(`--${variableName}`, value);
const percentValue = ((value - input.min) / (input.max - input.min)) * 100;
input.style.setProperty('--rng-percent', `${percentValue}%`);
output.textContent = value;
});
});
const resetButton = document.querySelector('.app__button--reset');
resetButton.addEventListener('click', () => {
setTimeout(() => {
rangeSliders.forEach(slider => {
const input = slider.querySelector('input');
const output = slider.querySelector('output');
const value = input.value;
const variableName = input.getAttribute('data-elm');
const appElement = document.querySelector('.app');
appElement.style.setProperty(`--${variableName}`, value);
const percentValue = ((value - input.min) / (input.max - input.min)) * 100;
input.style.setProperty('--rng-percent', `${percentValue}%`);
output.textContent = value;
})
}, 0);
});
const imageThumbnails = document.querySelectorAll('.app__img-thumb');
imageThumbnails.forEach(thumbnail => {
thumbnail.addEventListener('click', () => {
const backgroundImage = thumbnail.style.backgroundImage;
const imageIndex = thumbnail.getAttribute('data-index');
const imageSrc = thumbnail.getAttribute('style').match(/url\((.*?)\)/)[1];
const imagePreview = document.querySelector('.app__img');
imagePreview.setAttribute('src', imageSrc);
});
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.