diff --git a/custom-range-slider/.vscode/settings.json b/custom-range-slider/.vscode/settings.json
new file mode 100644
index 0000000..6f3a291
--- /dev/null
+++ b/custom-range-slider/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "liveServer.settings.port": 5501
+}
\ No newline at end of file
diff --git a/custom-range-slider/index.html b/custom-range-slider/index.html
new file mode 100644
index 0000000..ebc41e7
--- /dev/null
+++ b/custom-range-slider/index.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+ Custom Range Slider
+
+
+ Custom Range Slider
+
+
+
+
+
+
+
+
diff --git a/custom-range-slider/script.js b/custom-range-slider/script.js
new file mode 100644
index 0000000..8fa6e72
--- /dev/null
+++ b/custom-range-slider/script.js
@@ -0,0 +1,27 @@
+const range = document.getElementById('range')
+
+range.addEventListener('input', (e) => {
+ const value = +e.target.value
+ const label = e.target.nextElementSibling
+
+ const range_width = getComputedStyle(e.target).getPropertyValue('width')
+ const label_width = getComputedStyle(label).getPropertyValue('width')
+
+ const num_width = +range_width.substring(0, range_width.length - 2)
+ const num_label_width = +label_width.substring(0, label_width.length - 2)
+
+ const max = +e.target.max
+ const min = +e.target.min
+
+ const left = value * (num_width / max) - num_label_width / 2 + scale(value, min, max, 10, -10)
+
+ label.style.left = `${left}px`
+
+
+ label.innerHTML = value
+})
+
+// https://stackoverflow.com/questions/10756313/javascript-jquery-map-a-range-of-numbers-to-another-range-of-numbers
+const scale = (num, in_min, in_max, out_min, out_max) => {
+ return (num - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+ }
\ No newline at end of file
diff --git a/custom-range-slider/style.css b/custom-range-slider/style.css
new file mode 100644
index 0000000..b0951d3
--- /dev/null
+++ b/custom-range-slider/style.css
@@ -0,0 +1,108 @@
+@import url('https://fonts.googleapis.com/css?family=Lato&display=swap');
+
+* {
+ box-sizing: border-box;
+}
+
+body {
+ background-image: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
+ font-family: 'Lato', sans-serif;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ height: 100vh;
+ overflow: hidden;
+ margin: 0;
+}
+
+h2 {
+ position: absolute;
+ top: 10px;
+}
+
+.range-container {
+ position: relative;
+}
+
+input[type='range'] {
+ width: 300px;
+ margin: 18px 0;
+ -webkit-appearance: none;
+}
+
+input[type='range']:focus {
+ outline: none;
+}
+
+input[type='range'] + label {
+ background-color: #fff;
+ position: absolute;
+ top: -25px;
+ left: 110px;
+ width: 80px;
+ padding: 5px 0;
+ text-align: center;
+ border-radius: 4px;
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
+}
+
+/* Chrome & Safari */
+input[type='range']::-webkit-slider-runnable-track {
+ background: purple;
+ border-radius: 4px;
+ width: 100%;
+ height: 10px;
+ cursor: pointer;
+}
+
+input[type='range']::-webkit-slider-thumb {
+ -webkit-appearance: none;
+ height: 24px;
+ width: 24px;
+ background: #fff;
+ border-radius: 50%;
+ border: 1px solid purple;
+ margin-top: -7px;
+ cursor: pointer;
+}
+
+/* Firefox */
+input[type='range']::-moz-range-track {
+ background: purple;
+ border-radius: 4px;
+ width: 100%;
+ height: 13px;
+ cursor: pointer;
+}
+
+input[type='range']::-moz-range-thumb {
+ -webkit-appearance: none;
+ height: 24px;
+ width: 24px;
+ background: #fff;
+ border-radius: 50%;
+ border: 1px solid purple;
+ margin-top: -7px;
+ cursor: pointer;
+}
+
+/* IE */
+input[type='range']::-ms-track {
+ background: purple;
+ border-radius: 4px;
+ width: 100%;
+ height: 13px;
+ cursor: pointer;
+}
+
+input[type='range']::-ms-thumb {
+ -webkit-appearance: none;
+ height: 24px;
+ width: 24px;
+ background: #fff;
+ border-radius: 50%;
+ border: 1px solid purple;
+ margin-top: -7px;
+ cursor: pointer;
+}