'Range slider resetting to default on firefox

So I'm making an Etch-a-Sketch with a range slider to change the grid size, but the slider keeps resetting to its default size (16x16) as soon as I move the mouse after changing the value (if I change the value and don't move the mouse, the size doesn't reset). For some reason this doesn't happen on Chrome: the value and grid size both change and stay that way until I change them again.

Here's the JSFiddle: https://jsfiddle.net/CamiCoding/7zpt14cs/

HTML:

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="x-ua-compatible" content="ie=edge">
        <title>Etch-a-Sketch</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" type="text/css" href="css/style.css">
    </head>
    <body>
        <div class="title">
            <h1>Etch-a-Sketch</h1>
        </div>
        <div class="btns">
            <button id="blackBtn">Black</button>
            <button id="rainbowBtn">Rainbow</button>
            <button id="colorBtn">Color</button>
            <button id="eraserBtn">Eraser</button>
            <button id="resetBtn">Reset</button>
            <div class="colorPicker">
                <input type="color" id="color" value="#000000">
                <span>Pick a color</span>
            </div>
            <div class="sliderAndValue">
                <input type="range" min="2" max="100" value="16" id="slider">
                <p class="value">16</p>
            </div>
        </div>
        <div class="grid">
        </div>
        <script src="script.js" defer></script>
    </body>
    </html>

CSS:

@font-face {
  src:  url("../fonts/sf-atarian-system.regular.ttf");
  font-family: Atarian;
}

body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  font-family: Atarian;
  background-color: #D1D1D1;
}

.title h1 {
  font-size: 80px;
  margin: 0px;
}

.btns {
  display: flex;
  flex-direction: row;
  width: 700px;
  height: 50px;
  justify-content: space-evenly;
  margin-top: 20px;
  margin-bottom: 20px;
}

.btns button {
  font-family: Atarian;
  font-size: 24px;
  height: 40px;
  width: 80px;
  border-radius: 5px;
  transition: transform 0.2s ease-in-out;
}

.btns button:hover {
  transform: scale(1.2);
}

.btns .active {
  background-color: #505050;
  color: white;
}

.colorPicker {
  display: flex;
  flex-direction: column;
  align-items: center;
  font-size: 20px;
}

.color span {
  text-align: center;
}

#color {
  width: 90px;
}

.sliderAndValue {
  -webkit-appearance: none;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  font-size: 24px;
}

#slider {
  -webkit-appearance: none;
  width: 150px;
  height: 10px;
  background: #000;
  outline: none;
  border: 4px solid gray;
  border-radius: 4px;
}

/* for firefox */
#slider::-moz-range-thumb {
  width: 5px;
  height: 20px;
  background: #000;
  cursor: pointer;
  border: 4px solid gray;
  border-radius: 4px;
}

/* for chrome/safari */
#slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 5px;
  height: 20px;
  background: #000;
  cursor: pointer;
  border: 4px solid gray;
  border-radius: 4px;
}

.cell {
  border: 1px solid black;
}

.cell.active {
  background-color: black;
}

.grid {
  display: inline-grid;
  grid-template-columns: repeat(16, 2fr);
  grid-template-rows: repeat(16, 2fr);
  border: 5px solid gray;
  border-radius: 5px;
  height: 700px;
  width: 700px;
  background-color: white;
}

JS:

const grid = document.querySelector('.grid');
const resetBtn = document.getElementById('resetBtn');
const eraserBtn = document.getElementById('eraserBtn');
const blackBtn = document.getElementById('blackBtn');
const colorBtn = document.getElementById('colorBtn')
const colorValue = document.getElementById('color');
const slider = document.getElementById('slider');
const sliderValue = document.querySelector('.value');
const DEFAULT_COLOR = '#000000';
const DEFAULT_MODE = 'black';
const DEFAULT_SIZE = 16;

let currentColor = DEFAULT_COLOR;
let currentMode = DEFAULT_MODE;
let mouseDown = false

document.body.onmousedown = () => (mouseDown = true)
document.body.onmouseup = () => (mouseDown = false)

function setCurrentColor(newColor) {
    currentColor = newColor;
}

function setCurrentMode(newMode) {
    activateButton(newMode);
    currentMode = newMode;
}

blackBtn.onclick = () => setCurrentMode('black');
rainbowBtn.onclick = () => setCurrentMode('rainbow');
eraserBtn.onclick = () => setCurrentMode('eraser');
colorBtn.onclick = () => setCurrentMode('color');
resetBtn.onclick = () => createGrid();

function createGrid() {
    removeCells(grid);
    let val = document.getElementById('slider').value;
    sliderValue.textContent = val;
    grid.style.gridTemplateColumns = (`repeat(${val}, 2fr`);
    grid.style.gridTemplateRows = (`repeat(${val}, 2fr`);
    for(let i = 0; i < val * val; i++) {
        const cell = document.createElement('div');
        cell.classList.add('cell');
        cell.addEventListener('mouseover', changeColor);
        cell.addEventListener('mousedown', changeColor);
        grid.appendChild(cell);
    }
}

function activateButton(newMode) {
    if (currentMode === 'rainbow') {
        rainbowBtn.classList.remove('active');
    } else if (currentMode === 'color') {
        colorBtn.classList.remove('active');
    } else if (currentMode === 'eraser') {
        eraserBtn.classList.remove('active');
    } else if (currentMode === 'black') {
        blackBtn.classList.remove('active');
    }

    if (newMode === 'rainbow') {
        rainbowBtn.classList.add('active');
    } else if (newMode === 'color') {
        colorBtn.classList.add('active');
    } else if (newMode === 'eraser') {
        eraserBtn.classList.add('active');
    } else if (newMode === 'black') {
        blackBtn.classList.add('active');
    }
}

function changeColor(e) {
    if (e.type === 'mouseover' && !mouseDown) return;
    if (currentMode === 'rainbow') {
        const randomR = Math.floor(Math.random() * 256);
        const randomG = Math.floor(Math.random() * 256);
        const randomB = Math.floor(Math.random() * 256);
        e.target.style.backgroundColor = `rgb(${randomR}, ${randomG}, ${randomB})`;
    } else if (currentMode === 'color') {
        e.target.style.backgroundColor = colorValue.value;
    } else if (currentMode === 'eraser') {
        e.target.style.backgroundColor = '#ffffff';
    } else if (currentMode === 'black') {
        e.target.style.background = '#000000';
    }
}

slider.addEventListener('input', function(){
    let val = document.getElementById('slider').value;
    sliderValue.textContent = val;
    removeCells(grid);
    grid.style.gridTemplateColumns = (`repeat(${val}, 2fr`);
    grid.style.gridTemplateRows = (`repeat(${val}, 2fr`);
    for (let i = 0; i < val * val; i++) {
        const cell = document.createElement('div');
        cell.classList.add('cell');
        cell.addEventListener('mouseover', changeColor);
        cell.addEventListener('mousedown', changeColor);
        grid.appendChild(cell);
    }
});

function removeCells(parent){
    while(grid.firstChild){
        grid.removeChild(grid.firstChild);
    }
}

window.onload = () => {
    createGrid(DEFAULT_SIZE);
    activateButton(DEFAULT_MODE);
}

I do have another question regarding this same project, but about a different issue, please let me know if I should post a different question for it or if I should post it here too!

Thanks a lot in advance :).



Solution 1:[1]

I was able to track down the source of the issue, and fix it. Sounds weird, but document.body.onmousedown and document.body.onmouseup were creating the issue.
Replacing them with addEventListener seems to fix it.

I also removed some repeated code (in slider's input listener), by making maximum use of createGrid() function.

const grid = document.querySelector('.grid');
const resetBtn = document.getElementById('resetBtn');
const eraserBtn = document.getElementById('eraserBtn');
const blackBtn = document.getElementById('blackBtn');
const colorBtn = document.getElementById('colorBtn')
const colorValue = document.getElementById('color');
const slider = document.querySelector('#slider');
const sliderValue = document.querySelector('.value');
const DEFAULT_COLOR = '#000000';
const DEFAULT_MODE = 'black';
const DEFAULT_SIZE = 16;

let currentColor = DEFAULT_COLOR;
let currentMode = DEFAULT_MODE;
let mouseDown = false

document.body.addEventListener("mousedown", () => (mouseDown = true))
document.body.addEventListener("mouseup", () => (mouseDown = false))

function setCurrentColor(newColor) {
  currentColor = newColor;
}

function setCurrentMode(newMode) {
  activateButton(newMode);
  currentMode = newMode;
}

blackBtn.onclick = () => setCurrentMode('black');
rainbowBtn.onclick = () => setCurrentMode('rainbow');
eraserBtn.onclick = () => setCurrentMode('eraser');
colorBtn.onclick = () => setCurrentMode('color');
resetBtn.onclick = () => createGrid();

function createGrid(val = 16) {
  slider.value = val;
  sliderValue.textContent = val;
  removeCells(grid);
  grid.style.gridTemplateColumns = (`repeat(${val}, 2fr`);
  grid.style.gridTemplateRows = (`repeat(${val}, 2fr`);
  for (let i = 0; i < val * val; i++) {
    const cell = document.createElement('div');
    cell.classList.add('cell');
    cell.addEventListener('mouseover', changeColor);
    cell.addEventListener('mousedown', changeColor);
    grid.appendChild(cell);
  }

}

function activateButton(newMode) {
  if (currentMode === 'rainbow') {
    rainbowBtn.classList.remove('active');
  } else if (currentMode === 'color') {
    colorBtn.classList.remove('active');
  } else if (currentMode === 'eraser') {
    eraserBtn.classList.remove('active');
  } else if (currentMode === 'black') {
    blackBtn.classList.remove('active');
  }

  if (newMode === 'rainbow') {
    rainbowBtn.classList.add('active');
  } else if (newMode === 'color') {
    colorBtn.classList.add('active');
  } else if (newMode === 'eraser') {
    eraserBtn.classList.add('active');
  } else if (newMode === 'black') {
    blackBtn.classList.add('active');
  }
}

function changeColor(e) {
  if (e.type === 'mouseover' && !mouseDown) return;
  if (currentMode === 'rainbow') {
    const randomR = Math.floor(Math.random() * 256);
    const randomG = Math.floor(Math.random() * 256);
    const randomB = Math.floor(Math.random() * 256);
    e.target.style.backgroundColor = `rgb(${randomR}, ${randomG}, ${randomB})`;
  } else if (currentMode === 'color') {
    e.target.style.backgroundColor = colorValue.value;
  } else if (currentMode === 'eraser') {
    e.target.style.backgroundColor = '#ffffff';
  } else if (currentMode === 'black') {
    e.target.style.background = '#000000';
  }
}

slider.addEventListener('input', function(e) {
  let val = parseInt(document.getElementById('slider').value);
  createGrid(val);
});

function removeCells(parent) {
  while (grid.firstChild) {
    grid.removeChild(grid.firstChild);
  }
}

window.onload = () => {
  createGrid(DEFAULT_SIZE);
  activateButton(DEFAULT_MODE);
}
@font-face {
  src:  url("../fonts/sf-atarian-system.regular.ttf");
  font-family: Atarian;
}

body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  font-family: Atarian;
  background-color: #D1D1D1;
}

.title h1 {
  font-size: 80px;
  margin: 0px;
}

.btns {
  display: flex;
  flex-direction: row;
  width: 700px;
  height: 50px;
  justify-content: space-evenly;
  margin-top: 20px;
  margin-bottom: 20px;
}

.btns button {
  font-family: Atarian;
  font-size: 24px;
  height: 40px;
  width: 80px;
  border-radius: 5px;
  transition: transform 0.2s ease-in-out;
}

.btns button:hover {
  transform: scale(1.2);
}

.btns .active {
  background-color: #505050;
  color: white;
}

.colorPicker {
  display: flex;
  flex-direction: column;
  align-items: center;
  font-size: 20px;
}

.color span {
  text-align: center;
}

#color {
  width: 90px;
}

.sliderAndValue {
  -webkit-appearance: none;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  font-size: 24px;
}

#slider {
  -webkit-appearance: none;
  width: 150px;
  height: 10px;
  background: #000;
  outline: none;
  border: 4px solid gray;
  border-radius: 4px;
}

/* for firefox */
#slider::-moz-range-thumb {
  width: 5px;
  height: 20px;
  background: #000;
  cursor: pointer;
  border: 4px solid gray;
  border-radius: 4px;
}

/* for chrome/safari */
#slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 5px;
  height: 20px;
  background: #000;
  cursor: pointer;
  border: 4px solid gray;
  border-radius: 4px;
}

.cell {
  border: 1px solid black;
}

.cell.active {
  background-color: black;
}

.grid {
  display: inline-grid;
  grid-template-columns: repeat(16, 2fr);
  grid-template-rows: repeat(16, 2fr);
  border: 5px solid gray;
  border-radius: 5px;
  height: 700px;
  width: 700px;
  background-color: white;
  user-select: none;
}
<!doctype html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="x-ua-compatible" content="ie=edge">
        <title>Etch-a-Sketch</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" type="text/css" href="css/style.css">
    </head>
    <body>
        <div class="title">
            <h1>Etch-a-Sketch</h1>
        </div>
        <div class="btns">
            <button id="blackBtn">Black</button>
            <button id="rainbowBtn">Rainbow</button>
            <button id="colorBtn">Color</button>
            <button id="eraserBtn">Eraser</button>
            <button id="resetBtn">Reset</button>
            <div class="colorPicker">
                <input type="color" id="color" value="#000000">
                <span>Pick a color</span>
            </div>
            <div class="sliderAndValue">
                <input type="range" min="2" value="16" id="slider">
                <p class="value">16</p>
            </div>
        </div>
        <div class="grid">
        </div>
        <script src="script.js" defer></script>
    </body>
    </html>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1