<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Modern Calculator</title>
<style>
/* Global Reset and Body Styling */
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
background-color: #f0f2f5; /* Light grey background for a modern feel */
font-family: 'Roboto', sans-serif; /* Using a clean, modern font stack */
}
/* Calculator Container Styling (The main card) */
.calculator {
background-color: #ffffff;
border-radius: 20px; /* Large rounded corners for the whole unit */
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.15); /* Soft shadow like Material Design elevation */
width: 320px;
padding: 25px;
}
/* Display Screen Styling */
#display {
background-color: #e8f0fe; /* Very light blue/blue tint for the display area */
color: #1a237e; /* Deep indigo color for text */
font-size: 3em;
padding: 20px 15px;
text-align: right;
border-radius: 15px; /* Rounded corners on the display area */
margin-bottom: 20px;
overflow: hidden;
height: 70px;
white-space: nowrap; /* Prevent numbers from wrapping */
}
/* Button Grid Layout */
.buttons {
display: grid;
grid-template-columns: repeat(4, 1fr); /* Four equal columns */
gap: 12px; /* Spacing between buttons */
}
/* Base Button Styling */
button {
border: none;
padding: 20px 0;
font-size: 1.5em;
cursor: pointer;
border-radius: 50%; /* Makes the button perfectly round when square */
transition: background-color 0.2s ease, transform 0.1s ease;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.1); /* Subtle shadow for depth */
}
/* Specific Styling for Number/Operator Buttons (Default look) */
button:not(.operator):not(.clear):not(.equals) {
background-color: #f5f5f5; /* Light grey background */
color: #333;
}
button:hover:not(.operator):not(.clear):not(.equals) {
background-color: #eeeeee;
}
/* Styling for Operator Buttons (+, -, *, /) - Highlighting interaction */
.operator {
background-color: #ff9800; /* Amber/Orange color for operations */
color: white;
font-weight: bold;
}
.operator:hover {
background-color: #fb8c00;
}
/* Styling for Clear and AC buttons - Distinctive look */
.clear {
background-color: #ff5252; /* Reddish color for clear/delete */
color: white;
}
.clear:hover {
background-color: #e53935;
}
/* Styling for the Equals button - Primary action highlight */
.equals {
background-color: #4caf50; /* Green color for equals */
color: white;
grid-column: span 1; /* Ensures it takes one spot */
}
.equals:hover {
background-color: #388e3c;
}
/* State when the button is pressed (Active state) */
button:active {
transform: scale(0.95); /* Slight press down effect */
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
/* Adjusting grid for specific button sizes if needed (though not strictly necessary here) */
button[data-value="0"] {
grid-column: span 1; /* Ensure zero spans one column */
}
</style>
</head>
<body>
<div class="calculator">
<!-- Display Screen -->
<div id="display">0</div>
<!-- Buttons Grid -->
<div class="buttons">
<!-- Row 1 -->
<button class="clear" data-action="AC">AC</button>
<button class="operator" data-value="/">÷</button>
<button class="operator" data-value="*">×</button>
<button class="operator" data-value="-">−</button>
<!-- Row 2 -->
<button data-value="7">7</button>
<button data-value="8">8</button>
<button data-value="9">9</button>
<button class="operator" data-value="+">+</button>
<!-- Row 3 -->
<button data-value="4">4</button>
<button data-value="5">5</button>
<button data-value="6">6</button>
<!-- The plus sign in row 2 is replaced by a button that spans two rows if we wanted, but here we stick to standard layout -->
<!-- Row 4 -->
<button data-value="1">1</button>
<button data-value="2">2</button>
<button data-value="3">3</button>
<!-- We use the space below for the equals button and zero layout logic -->
<!-- Row 5 (Adjusting for better flow, we'll place 0 and = in the last row) -->
<button data-value="0" style="grid-column: span 2;">0</button>
<button data-value=".">.</button>
<button class="equals" data-action="calculate">=</button>
</div>
</div>
<script>
const display = document.getElementById('display');
const buttons = document.querySelector('.buttons');
let currentInput = '0';
let firstOperand = null;
let operator = null;
let waitingForSecondOperand = false;
// Function to update the display element
function updateDisplay() {
display.textContent = currentInput;
}
// Core calculation logic function
async function calculate(first, second, op) {
const num1 = parseFloat(first);
const num2 = parseFloat(second);
if (op === '+') return num1 + num2;
if (op === '-') return num1 - num2;
if (op === '*') return num1 * num2;
if (op === '/') {
if (num2 === 0) {
return 'Error: Div by zero';
}
return num1 / num2;
}
return num2; // Should not happen if logic is correct
}
// Event listener for button clicks
buttons.addEventListener('click', (event) => {
const target = event.target;
if (!target.matches('button')) return;
const value = target.dataset.value;
const action = target.dataset.action;
// 1. Handle Number/Decimal Input
if (value !== undefined && !isNaN(parseFloat(value))) {
if (waitingForSecondOperand === true) {
// Start a new number after an operation was pressed
currentInput = value;
waitingForSecondOperand = false;
} else {
// Standard digit entry
if (currentInput === '0' && value !== '.') {
currentInput = value; // Replace initial zero
} else if (value === '.' && currentInput.includes('.')) {
return; // Prevent multiple decimals
} else {
currentInput += value;
}
}
updateDisplay();
}
// 2. Handle Operators (+, -, *, /)
else if (value !== undefined && ['+', '-', '*', '/'].includes(value)) {
const inputValue = parseFloat(currentInput);
if (operator && waitingForSecondOperand) {
// If an operator was pressed immediately after another one, just change the operator
operator = value;
return;
}
if (firstOperand === null) {
// First operand is being set
firstOperand = inputValue;
} else if (operator) {
// Perform calculation with the current input as the second operand
const result = await calculate(firstOperand, inputValue, operator);
currentInput = String(result).substring(0, 12); // Limit length for display
firstOperand = parseFloat(currentInput);
updateDisplay();
}
// Set up for the next calculation step
operator = value;
waitingForSecondOperand = true;
}
// 3. Handle Equals (=)
else if (action === 'calculate') {
if (firstOperand === null || operator === null) return; // Do nothing if incomplete
const secondOperand = waitingForSecondOperand ? parseFloat(currentInput) : firstOperand;
const result = await calculate(firstOperand, secondOperand, operator);
currentInput = String(result).substring(0, 12);
firstOperand = null; // Reset state after calculation
operator = null;
waitingForSecondOperand = false;
updateDisplay();
}
// 4. Handle All Clear (AC)
else if (action === 'AC') {
currentInput = '0';
firstOperand = null;
operator = null;
waitingForSecondOperand = false;
updateDisplay();
}
});
// Initialize display on load
updateDisplay();
</script>
</body>
</html>