I'm following this tutorial on building a javascript calculator to learn a little more about web development. The CSS code below adds styling when pressing an operator (+, -, *, /) key. When an operator key is pressed, it should darken until another key is pressed to show that the operator is "active". However, when pressing the same operator key over and over again, there should still be some visual indication of the repeated clicking.
const calculator = document.querySelector(".calculator");
const keys = calculator.querySelector(".calculator__keys");
const display = document.querySelector(".calculator__display");
keys.addEventListener('click', e => {
if (e.target.matches('button')) {
const key = e.target;
const action = key.dataset.action;
const keyValue = key.textContent;
const displayNum = display.textContent;
Array.from(key.parentNode.children).forEach(k=>k.classList.remove('is-depressed'));
if (!action) {
if (displayNum === "0" || calculator.dataset.previousKeyType === "operator") {
display.textContent = keyValue;
calculator.dataset.previousKeyType = null;
} else {
display.textContent = displayNum + keyValue;
}
calculator.dataset.previousKeyType = "number";
console.log("Number key")
}
if (action === "decimal") {
if (calculator.dataset.previousKeyType === "operator") {
display.textContent = "0.";
calculator.dataset.previousKeyType = "decimal";
} else if (!displayNum.includes(".")) {
display.textContent += ".";
}
}
if (
action === 'add' ||
action === 'subtract' ||
action === 'multiply' ||
action === 'divide'
) {
calculator.dataset.previousKeyType = "operator";
calculator.dataset.previousNum = displayNum;
calculator.dataset.operator = action;
key.classList.add("is-depressed");
}
if (action === "clear") {
calculator.dataset.previousKeyType = "clear";
console.log("AC key");
}
if (action === "calculate") {
calculator.dataset.previousKeyType = "calculate";
const secondVal = displayNum;
const firstVal = calculator.dataset.previousNum;
const operator = calculator.dataset.operator;
display.textContent = calculate(firstVal, secondVal, operator);
}
}
});
function calculate(firstVal, secondVal, operator) {
let num1 = +firstVal;
let num2 = +secondVal;
if (operator === "add") {
return num1 + num2;
} else if (operator === "subtract") {
return num1 - num2;
} else if (operator === "multiply") {
return num1 * num2;
} else {
return num1 / num2;
}
}
// NOTE: You don't need to mess around with
// CSS to follow the tutorial. Focus on the
// JavaScript instead!
// =========================
// Some personal resets
html {
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
}
body {
margin: 0;
}
/* Responsive Images */
embed,
iframe,
img,
object,
video {
max-width: 100%;
}
h1,
h2,
h3,
h4,
h5,
h6,
ul,
ol,
li,
p,
pre,
blockquote,
figure,
hr {
margin: 0;
padding-right: 0;
padding-left: 0;
}
a {
text-decoration: none;
}
a:focus {
outline: none;
}
h1,
h2,
h3,
h4,
h5,
h6 {
display: block;
}
/* Removes all decimals and discs from lists */
ol,
ul {
list-style: none;
}
/*
* Completely resets form items
* ----------------------------
* Super hard reset that removes all borders
* and radiuses of all form items (including
* checkboxes and radios)
*/
input,
textarea,
button {
border: 0;
border-radius: 0;
background-color: transparent;
font-size: inherit;
font-family: inherit;
font-weight: inherit;
outline: none;
appearance: none;
text-align: left;
}
input:hover,
input:active,
input:focus,
textarea:hover,
textarea:active,
textarea:focus,
button:hover,
button:active,
button:focus {
outline: none;
}
:root {
font-family: Helvetica, Arial, sans-serif;
}
html {
font-size: 175%;
font-weight: 300;
line-height: 1.3;
}
body {
align-items: center;
background-image: linear-gradient(236deg, #74ebd5, #acb6e5);
display: flex;
height: 100vh;
justify-content: center;
}
.container {
max-width: 20em;
}
.container > p {
text-align: center;
}
.calculator {
border-radius: 12px;
box-shadow: 0 0 40px 0px rgba(0, 0, 0, 0.15);
margin-left: auto;
margin-right: auto;
margin-top: 2em;
max-width: 15em;
overflow: hidden;
}
.calculator__display {
background-color: #222222;
color: #fff;
font-size: 1.714285714em;
padding: 0.5em 0.75em;
text-align: right;
}
.calculator__keys {
background-color: #999;
display: grid;
grid-gap: 1px;
grid-template-columns: repeat(4, 1fr);
}
.calculator__keys > * {
background-color: #fff;
padding: 0.5em 1.25em;
position: relative;
text-align: center;
}
.calculator__keys > *:active::after,
.calculator__keys > .is-depressed::before {
background-color: rgba(0, 0, 0, 0.2);
bottom: 0;
box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.5) inset;
content: "";
left: 0;
opacity: 0.3;
position: absolute;
right: 0;
top: 0;
z-index: 1;
}
.key--operator {
background-color: #eee;
}
.key--equal {
background-image: linear-gradient(to bottom, #fe886a, #ff7033);
grid-column: -2;
grid-row: 2 / span 4;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Calculator</title>
<link rel="stylesheet" href="calculator.css" type="text/css">
<script type="text/javascript" src="calculator.js" defer></script>
</head>
<body>
<div class="container">
<p>
This component works exactly like the calculator you know. Click any number to start calculating!
</p>
<div class="calculator">
<div class="calculator__display">0</div>
<div class="calculator__keys">
<button class="key--operator" data-action="add">+</button>
<button class="key--operator" data-action="subtract">-</button>
<button class="key--operator" data-action="multiply">×</button>
<button class="key--operator" data-action="divide">÷</button>
<button>7</button>
<button>8</button>
<button>9</button>
<button>4</button>
<button>5</button>
<button>6</button>
<button>1</button>
<button>2</button>
<button>3</button>
<button>0</button>
<button data-action="decimal">.</button>
<button data-action="clear">AC</button>
<button class="key--equal" data-action="calculate">=</button>
</div>
</div>
</div>
</body>
</html>
The is-depressed class is a class I add to the operator key element when it is clicked. The code above doesn't give the visual indicator of multiple clicks, but when I change *:active::before to *:active::after, the code does what I want. Why is that?
.calculator__keys > *:active::after,
.calculator__keys > .is-depressed::before {
background-color: rgba(0, 0, 0, 0.2);
bottom: 0;
box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.5) inset;
content: "";
left: 0;
opacity: 0.3;
position: absolute;
right: 0;
top: 0;
z-index: 1;
}