This weekend we are going to make something amazing, we are going to re-create Photoshop! Not entirely, but we'll be playing with variable CSS Filters! I choose to build a playground so people can understand what each filter's effect is! I do hope you find it helpful. Things we will address in this article are: CSS VariablesCSS FiltersJavaScript Setting CSS Variables Let's get right to it! HTML Structure Our application is going to have one image on the left hand side, and then our slider controls on the right, so let's start by creating this in HTML: Blur Brightness Contrast Grayscale Hue Invert Opacity Saturate Sepia < = > div class "container" < = = /> img src "https://images.unsplash.com/photo-1508671323699-6df22ecaec2a?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=250&q=80" id "main-image" < = > div class "toolbox" < > label < = = = = = = /> input id "blur" max "20" min "0" step "1" type "range" value "0" </ > label < > label < = = = = = = /> input id "brightness" max "1" min "0" step "0.1" type "range" value "1" </ > label < > label < = = = = = = /> input id "contrast" max "200" min "0" step "1" type "range" value "100" </ > label < > label < = = = = = = /> input id "grayscale" max "100" min "0" step "1" type "range" value "0" </ > label < > label < = = = = = = /> input id "hue" max "360" min "0" step "1" type "range" value "0" </ > label < > label < = = = = = = /> input id "invert" max "100" min "0" step "1" type "range" value "0" </ > label < > label < = = = = = = /> input id "opacity" max "100" min "0" step "1" type "range" value "100" </ > label < > label < = = = = = = /> input id "saturate" max "200" min "0" step "1" type "range" value "100" </ > label < > label < = = = = = = /> input id "sepia" max "100" min "0" step "1" type "range" value "0" </ > label </ > div </ > div There we go, as you can see we are using the HTML range type sliders and give them default values, which are the normal values for each filter. Adding our General Styling Let's start by adding our general styling: { : flex; : center; : center; : ; : ; } { : ; : flex; : center; : column; } { : ; } .container display align-items justify-content height 100vh background #eee .toolbox margin-left 50px display justify-content flex-direction label margin-bottom 5px Nothing fancy, we are using everything and add some primary margin to our elements. Flex to center Adding our CSS Variables In today's topic we are addressing , these are super useful because they can easily be changed by JavaScript! CSS Variables { : ; : ; : ; : ; : ; : ; : ; : ; : ; } :root --blur 0 --brightness 1 --contrast 100 --grayscale 0 --hue 0 --invert 0 --opacity 100 --saturate 100 --sepia 0 Above, you see all the variables we are using. They correspond with the HTML inputs we created! So we set them all to have our basic starting point values, but how do they do something? CSS Filters As we saw in our article about our , CSS Filters are really cool. CSS Disco Text The filters we can use are as follows: url (We won't use this today) blur brightness contrast drop-shadow (Also, won't be used) grayscale hue-rotate invert opacity saturate sepia So let's address this and add the filters to our Image. { : all ease-in-out; : (calc(1px * var(--blur))) (var(--brightness)) ( calc(1% * var(--contrast)) ) (calc(1% * var(--grayscale))) (calc(1deg * var(--hue))) ( calc(1% * var(--invert)) ) (calc(1% * var(--opacity))) (calc(1% * var(--saturate))) (calc(1% * var(--sepia))); : solid ; } #main-image transition 300ms filter blur brightness contrast grayscale hue-rotate invert opacity saturate sepia border 5px #fff Wow! Massive code-block, but basically, you can only have one filter element, so we "chain" the filters after each other! Ok, cool, we now set all the filters on our image, but nothing changed? Correct! These are all the default values of each filter, so let's add some JavaScript to make the sliders affect our variables. JavaScript Setting CSS Variables First let's start and get our image object. img = .getElementById( ); var document 'main-image' Ok, now we need to find all our sliders inputs = .querySelectorAll( ); var document 'input' Next, we want to loop over each input and attach a event listener. [].forEach.call(inputs, { input.addEventListener( , e => { img.style.setProperty( + input.id, input.value); }); }); ( ) function input 'input' '--' We add an event listener to our input event, so every time the slider changes, we execute the function. The function then gets our image variable and uses the setProperty function to set the variables (e.g. --blur) to the input value! Isn't this cool?! Please have a play around with this Codepen, because actually trying it will show you how it works. Browser Support As mentioned before, CSS Filters are cool, but not widely supported yet 😩. There is a , but also limited. polyfill Thank you for reading, and let's connect! Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on or Facebook Twitter Previously published at https://daily-dev-tips.com/posts/building-a-realtime-photoshop-%F0%9F%8E%A8/