Skip to content

Instantly share code, notes, and snippets.

@tomhermans
Created March 3, 2026 06:40
Show Gist options
  • Select an option

  • Save tomhermans/a54eb073feef1f701830360e92cb4be8 to your computer and use it in GitHub Desktop.

Select an option

Save tomhermans/a54eb073feef1f701830360e92cb4be8 to your computer and use it in GitHub Desktop.
CSS / SVG Filter Generator

CSS / SVG Filter Generator

Play with different filters and combine them to produce amazing results. CSS and SVG filter codes are generated automatically.

A Pen by Tom Hermans on CodePen.

License.

<body>
<header class="d-flex flex-wrap justify-content-center py-3 mb-4 border-bottom">
<h1>Filter Generator</h1>
</header>
<div class="container-sm">
<div class="row">
<div class="col">
<div class="row d-flex justify-content-center ">
<div class="col-4 my-auto">
<h2>Filters</h2>
</div>
<div class="col-8 my-auto">
<input type="text" id="search" placeholder="Search filters...">
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title">CSS Filters</h5>
<div class="buttons">
<button class="btn btn-danger" id="resetStyle">Reset All</button>
<button class="btn btn-light" id="brightStyle">Bright</button>
<button class="btn btn-light" id="oldStyle">Old</button>
<button class="btn btn-light" id="rawStyle">Raw</button>
<button class="btn btn-light" id="nuclearStyle">Nuclear</button>
<button class="btn btn-light" id="creepyStyle">Creepy</button>
</div>
<div class="filter-range" data-filter-name="greyscale">
<label for="greyscale" class="form-label">Greyscale:<span id="greyscale-value">0%</span></label>
<input type="range" value="0" class="form-range" min="0" max="100" id="greyscale">
</div>
<div class="filter-range" data-filter-name="sepia">
<label for="sepia" class="form-label">Sepia:<span id="sepia-value">0%</span></label>
<input type="range" value="0" class="form-range" min="0" max="100" id="sepia">
</div>
<div class="filter-range" data-filter-name="blur">
<label for="blur" class="form-label">Blur:<span id="blur-value">0%</span></label>
<input type="range" value="0" class="form-range" min="0" max="100" id="blur">
</div>
<div class="filter-range" data-filter-name="brightness">
<label for="brightness" class="form-label">Brightness:<span id="brightness-value">0%</span></label>
<input type="range" value="100" class="form-range" min="0" max="200" id="brightness">
</div>
<div class="filter-range" data-filter-name="hue rotate">
<label for="huerotate" class="form-label">Hue Rotate:<span id="huerotate-value">0%</span></label>
<input type="range" value="0" class="form-range" min="0" max="360" id="huerotate">
</div>
<div class="filter-range" data-filter-name="saturate">
<label for="saturate" class="form-label">Saturate:<span id="saturate-value">0%</span></label>
<input type="range" value="100" class="form-range" min="0" max="1000" id="saturate">
</div>
<div class="filter-range" data-filter-name="opacity">
<label for="opacity" class="form-label">Opacity:<span id="opacity-value">0%</span></label>
<input type="range" value="100" class="form-range" min="0" max="100" id="opacity">
</div>
<div class="filter-range" data-filter-name="contrast">
<label for="contrast" class="form-label">Contrast:<span id="contrast-value">0%</span></label>
<input type="range" value="100" class="form-range" min="0" max="1000" id="contrast">
</div>
<div class="filter-range" data-filter-name="invert">
<label for="invert" class="form-label">Invert:<span id="invert-value">0%</span></label>
<input type="range" value="0" class="form-range" min="0" max="100" id="invert">
</div>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title">SVG Filters</h5>
<div class="filter-range" data-filter-name="edges">
<label for="svg-edges" class="form-label"><input id="svg-edges-checkbox" type="checkbox"> Sharp Edges:<span id="svg-edges-value">0%</span></label>
<input type="range" class="form-range" min="-2" max="2" step="0.05" id="svg-edges">
</div>
</div>
</div>
</div>
<div class="col">
<div id="image" class="full d-flex justify-content-center">
<img id="currentImage" class="filtered" src="https://images.unsplash.com/photo-1546811740-23e671faf31c?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3MTY1ODU4NzZ8&ixlib=rb-4.0.3&q=80&w=2000" alt="Sunshine and and a landscape in the distance, photographed from the point of view of a person reclining in a tent, whose shoes are visible in the photo. " title="Photo by Will Truettner for Unsplash. ">
<div id="svg-filters"></div>
</div>
<div class="row d-flex justify-content-center ">
<div class="col-12 mt-3">
<b> Upload Your Own Image: </b><input type="file" id="imageUpload" accept="image/*">
<canvas id="canvas" style="display:none;"></canvas>
</div>
</div>
<div class="row d-flex justify-content-center ">
<div class="col-12 mt-5">
<h2>Results</h2>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title">CSS</h5>
<span id="result"></span>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title">HTML</h5>
<span id="resultHtml"></span>
</div>
</div>
</div>
</div>
</div>
</body>
// JS filter to find a filter
document.getElementById("search").addEventListener("input", function () {
const query = this.value.toLowerCase();
const filters = document.querySelectorAll(".filter-range");
filters.forEach((filter) => {
const filterName = filter.getAttribute("data-filter-name").toLowerCase();
if (filterName.includes(query)) {
filter.style.display = "block";
} else {
filter.style.display = "none";
}
});
});
const image = document.getElementById("currentImage");
const inputs = {
greyscale: document.getElementById("greyscale"),
sepia: document.getElementById("sepia"),
blur: document.getElementById("blur"),
brightness: document.getElementById("brightness"),
huerotate: document.getElementById("huerotate"),
saturate: document.getElementById("saturate"),
opacity: document.getElementById("opacity"),
contrast: document.getElementById("contrast"),
invert: document.getElementById("invert"),
svgEdges: document.getElementById("svg-edges"),
svgEdgesCheckbox: document.getElementById("svg-edges-checkbox")
};
const valueLabels = {
greyscale: document.getElementById("greyscale-value"),
sepia: document.getElementById("sepia-value"),
blur: document.getElementById("blur-value"),
brightness: document.getElementById("brightness-value"),
huerotate: document.getElementById("huerotate-value"),
saturate: document.getElementById("saturate-value"),
opacity: document.getElementById("opacity-value"),
contrast: document.getElementById("contrast-value"),
invert: document.getElementById("invert-value"),
svgEdges: document.getElementById("svg-edges-value")
};
const resultSpan = document.getElementById("result");
function updateFilter() {
const filterValues = {
greyscale: inputs.greyscale.value + "%",
sepia: inputs.sepia.value + "%",
blur: inputs.blur.value + "px",
brightness: inputs.brightness.value + "%",
huerotate: inputs.huerotate.value + "deg",
saturate: inputs.saturate.value + "%",
opacity: inputs.opacity.value + "%",
contrast: inputs.contrast.value + "%",
invert: inputs.invert.value + "%"
};
// Update the labels with the current values
Object.keys(valueLabels).forEach((key) => {
if (key !== "svgEdges") {
valueLabels[key].textContent = ` ${filterValues[key]}`;
}
});
valueLabels.svgEdges.textContent = ` ${inputs.svgEdges.value}%`;
// Construct the filter string, excluding default values
let filterValue = "";
if (inputs.greyscale.value != 0)
filterValue += `grayscale(${filterValues.greyscale}) `;
if (inputs.sepia.value != 0) filterValue += `sepia(${filterValues.sepia}) `;
if (inputs.blur.value != 0) filterValue += `blur(${filterValues.blur}) `;
if (inputs.brightness.value != 100)
filterValue += `brightness(${filterValues.brightness}) `;
if (inputs.huerotate.value != 0)
filterValue += `hue-rotate(${filterValues.huerotate}) `;
if (inputs.saturate.value != 100)
filterValue += `saturate(${filterValues.saturate}) `;
if (inputs.opacity.value != 100)
filterValue += `opacity(${filterValues.opacity}) `;
if (inputs.contrast.value != 100)
filterValue += `contrast(${filterValues.contrast}) `;
if (inputs.invert.value != 0) filterValue += `invert(${filterValues.invert}) `;
filterValue = filterValue.trim();
// Apply the filter to the image
if (inputs.svgEdgesCheckbox.checked) {
image.style.filter = `url(#svgEdges) ${filterValue}`;
} else {
image.style.filter = filterValue;
}
// Update the result span
resultSpan.textContent = `filter: ${filterValue}`;
}
function updateSvgFilter() {
inputs.svgEdgesCheckbox.checked = true;
var svgEdges = `
<svg xmlns="http://www.w3.org/2000/svg">
<filter id="svgEdges">
<feConvolveMatrix order="3 3" preserveAlpha="true" divisor="1" bias="${inputs.svgEdges.value}" kernelMatrix="-1,-1,-1 -1,9,-1 -1,-1,-1" />
</filter>
</svg>
`;
document.getElementById("svg-filters").innerHTML = svgEdges;
document.getElementById("resultHtml").textContent =
'<div id="svg-filters">' + svgEdges + "</div>";
updateFilter();
}
function checkSvgFilter() {
if (inputs.svgEdgesCheckbox.checked) {
updateSvgFilter();
} else {
inputs.svgEdgesCheckbox.checked = false;
document.getElementById("svg-filters").innerHTML = "";
updateFilter();
}
}
// Add event listeners
Object.values(inputs).forEach((input) => {
input.addEventListener("input", () => {
if (input === inputs.svgEdges) {
updateSvgFilter();
} else if (input === inputs.svgEdgesCheckbox) {
checkSvgFilter();
} else {
updateFilter();
}
});
});
// Initialize the filter on page load
updateFilter();
// Play with filters
// Update input values and dispatch input event
function updateInputs(newValues) {
Object.keys(newValues).forEach((key) => {
const input = document.getElementById(key);
if (input) {
input.value = newValues[key];
// Trigger input event to update the filter
input.dispatchEvent(new Event("input"));
}
});
}
// Function to apply creepy style
function creepyStyle() {
const newValues = {
greyscale: 78,
sepia: 57,
blur: 0,
brightness: 167,
huerotate: 138,
saturate: 232,
opacity: 100,
contrast: 100,
invert: 100
};
inputs.svgEdgesCheckbox.checked = false;
var svgEdges = ``;
document.getElementById("svg-filters").innerHTML = svgEdges;
updateInputs(newValues);
}
// Function to reset style
function resetStyle() {
const newValues = {
greyscale: 0,
sepia: 0,
blur: 0,
brightness: 100,
huerotate: 0,
saturate: 100,
opacity: 100,
contrast: 100,
invert: 0
};
inputs.svgEdgesCheckbox.checked = false;
var svgEdges = ``;
document.getElementById("svg-filters").innerHTML = svgEdges;
updateInputs(newValues);
}
// Function to apply bright style
function brightStyle() {
const newValues = {
greyscale: 25,
sepia: 0,
blur: 0,
brightness: 160,
huerotate: 0,
saturate: 100,
opacity: 100,
contrast: 110,
invert: 0
};
inputs.svgEdgesCheckbox.checked = false;
var svgEdges = ``;
document.getElementById("svg-filters").innerHTML = svgEdges;
updateInputs(newValues);
}
// Function to apply old style
function oldStyle() {
const newValues = {
greyscale: 0,
sepia: 100,
blur: 0,
brightness: 100,
huerotate: 0,
saturate: 100,
opacity: 100,
contrast: 110,
invert: 0
};
inputs.svgEdgesCheckbox.checked = true;
var svgEdges = `
<svg xmlns="http://www.w3.org/2000/svg">
<filter id="svgEdges">
<feConvolveMatrix order="3 3" preserveAlpha="true" divisor="1" bias="0" kernelMatrix="-1,-1,-1 -1,9,-1 -1,-1,-1" />
</filter>
</svg>
`;
document.getElementById("svg-filters").innerHTML = svgEdges;
updateInputs(newValues);
}
// Function to apply old style
function rawStyle() {
const newValues = {
greyscale: 100,
sepia: 0,
blur: 0,
brightness: 200,
huerotate: 0,
saturate: 0,
opacity: 100,
contrast: 180,
invert: 0
};
inputs.svgEdgesCheckbox.checked = true;
var svgEdges = `
<svg xmlns="http://www.w3.org/2000/svg">
<filter id="svgEdges">
<feConvolveMatrix order="3 3" preserveAlpha="true" divisor="1" bias="-0.05" kernelMatrix="-1,-1,-1 -1,9,-1 -1,-1,-1" />
</filter>
</svg>
`;
document.getElementById("svg-filters").innerHTML = svgEdges;
updateInputs(newValues);
}
// Function to apply old style
function nuclearStyle() {
const newValues = {
greyscale: 0,
sepia: 100,
blur: 0,
brightness: 105,
huerotate: 340,
saturate: 1000,
opacity: 100,
contrast: 205,
invert: 0
};
inputs.svgEdgesCheckbox.checked = false;
var svgEdges = ``;
document.getElementById("svg-filters").innerHTML = svgEdges;
updateInputs(newValues);
}
// Add event listeners to the buttons
document.getElementById("resetStyle").addEventListener("click", resetStyle);
document.getElementById("brightStyle").addEventListener("click", brightStyle);
document.getElementById("creepyStyle").addEventListener("click", creepyStyle);
document.getElementById("oldStyle").addEventListener("click", oldStyle);
document.getElementById("rawStyle").addEventListener("click", rawStyle);
document.getElementById("nuclearStyle").addEventListener("click", nuclearStyle);
document
.getElementById("imageUpload")
.addEventListener("change", function (event) {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function (e) {
const img = document.getElementById("currentImage");
img.src = e.target.result;
img.onload = function () {
// Make the image container visible when the image is loaded
document.getElementById("image").style.display = "block";
};
};
reader.readAsDataURL(file);
// Save the file extension
window.uploadedFileExtension = file.name.split(".").pop();
}
});
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
body {
background: #f5f5f5;
font-family: "Plus Jakarta Sans", sans-serif;
}
h1,
h2,
h3,
h4,
h5 {
font-weight: 700;
}
.gallery {
display: flex;
justify-content: center;
margin-bottom: 20px;
}
.container {
display: flex;
justify-content: center;
gap: 20px;
}
.filter-range {
display: flex;
gap: 1.5vw;
flex-direction: row;
align-items: center;
> *:first-child {
width: 35%;
font-size: 90%;
}
.form-range {
width: auto;
flex-grow: 1;
}
}
#svg-filters {
position: absolute;
}
.card {
margin-top: 24px;
margin-bottom: 24px;
border-radius: 24px;
padding: 24px;
box-shadow: rgba(0, 0, 0, 0.1) 0px 10px 15px -3px,
rgba(0, 0, 0, 0.05) 0px 4px 6px -2px;
border: none;
}
#search {
border-radius: 24px;
border: none;
padding: 12px;
float: right;
box-shadow: rgba(0, 0, 0, 0.1) 0px 10px 15px -3px,
rgba(0, 0, 0, 0.05) 0px 4px 6px -2px;
}
.full {
width: 100%;
position: relative;
background: #f5f5f5;
border-radius: 24px;
overflow: hidden;
}
#image img {
object-fit: contain;
width: 100%;
object-position: center center;
}
#image {
background: white;
box-shadow: rgba(0, 0, 0, 0.1) 0px 10px 15px -3px,
rgba(0, 0, 0, 0.05) 0px 4px 6px -2px;
}
.card h5 {
margin-bottom: 24px;
}
.buttons {
margin-bottom: 24px;
}
.btn {
border-radius: 24px;
box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px,
rgba(0, 0, 0, 0.06) 0px 1px 2px 0px;
margin: 4px;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment