웹 개발 실력을 향상시키기 위해 작은 프로젝트를 진행하고 싶었습니다. 그래서 기본적이지만 중요한 기능을 담은 계산기를 만들기로 결정했습니다.
이 프로젝트에서는 순수 HTML, CSS, JavaScript를 사용하여 계산기를 구현하였습니다.
calculator 폴더를 생성합니다.
calculator 폴더 내부에caculator.html
,caculator.css
,calculator.js
파일을 생성합니다.
calculator.html
button
class를 가지고 있어야 합니다.number
class를 추가합니다.+
, -
, *
, /
)에는 operator
class를 추가합니다.C
, ±
, %
)에는 function
class를 추가합니다.zero
class를 추가합니다.calculator.css
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>계산기 만들기</title>
<link rel="stylesheet" href="calculator.css">
</head>
<body>
<div class="calculator-container">
<!-- 상단 버튼 영역 -->
<div class="window-buttons">
<span class="close"></span>
<span class="minimize"></span>
<span class="maximize"></span>
</div>
<!-- 디스플레이 영역 -->
<div class="display">
<div class="input">0</div>
</div>
<!-- 버튼 영역 -->
<div class="buttons">
<button class="button function">C</button>
<button class="button function">±</button>
<button class="button function">%</button>
<button class="button operator">÷</button>
<button class="button number">7</button>
<button class="button number">8</button>
<button class="button number">9</button>
<button class="button operator">×</button>
<button class="button number">4</button>
<button class="button number">5</button>
<button class="button number">6</button>
<button class="button operator">−</button>
<button class="button number">1</button>
<button class="button number">2</button>
<button class="button number">3</button>
<button class="button operator">+</button>
<button class="button number zero">0</button>
<button class="button number">.</button>
<button class="button operator">=</button>
</div>
</div>
<script src="calculator.js"></script>
</body>
</html>
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
background-color: #333;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.calculator-container {
width: 320px;
background-color: #000;
border-radius: 20px;
overflow: hidden;
position: relative;
}
.window-buttons {
position: absolute;
top: 10px;
left: 15px;
display: flex;
gap: 8px;
cursor: pointer;
}
.window-buttons span {
width: 12px;
height: 12px;
border-radius: 50%;
display: inline-block;
}
.window-buttons .close {
background-color: #ff5f57;
}
.window-buttons .minimize {
background-color: #ffbd2e;
}
.window-buttons .maximize {
background-color: #28c840;
}
.display {
color: #fff;
font-size: 48px;
text-align: right;
padding: 20px;
min-height: 80px;
display: flex;
align-items: center;
justify-content: flex-end;
}
.display .input {
display: block;
word-wrap: break-word;
}
.buttons {
display: flex;
flex-wrap: wrap;
}
.button {
width: 25%;
height: 60px;
font-size: 24px;
border: 1px solid #555;
background-color: #333;
color: #fff;
cursor: pointer;
outline: none;
}
.zero {
width: 50%;
}
.operator {
background-color: #ff9500;
color: #fff;
}
.function {
background-color: #a5a5a5;
color: #000;
}
.button:hover {
filter: brightness(1.2);
}
.button:active {
filter: brightness(0.8);
}
number
인 경우 디스플레이에 값을 표시합니다.0
일 때는 클릭한 숫자로 바뀌어야 합니다.0
이 아닐 때는 클릭한 숫자가 뒤에 추가되어야 합니다.소수점(.
) 버튼을 클릭하면 디스플레이에 소수점을 추가하세요. (이미 소수점이 있는 경우 추가되지 않도록)
C
버튼을 클릭하면 디스플레이를 0
으로 초기화하세요.
디스플레이에 숫자를 입력한 다음 연산기호를 누르면 디스플레이에 있는 숫자를 firstOperand
로 저장하고 연산기호를 기억합니다.
연산기호를 누른 후 디스플레이에 다른 숫자를 입력하면 새로운 숫자가 디스플레이에 입력되도록 합니다.
firstOperand
, operator
변수를 선언합니다.firstOperand
: 첫 번째 피연산자를 저장할 변수입니다.operator
: 연산자를 저장할 변수입니다.firstOperand
로 저장하고, 연산기호를 기억합니다.null
이면 현재 디스플레이 값을 firstOperand
로 저장합니다.operator
변수에 클릭한 연산기호를 값으로 할당합니다.firstOperand
와 operator
를 console에 출력합니다.=
버튼을 눌러서 계산이 완료된 후, 새로운 숫자를 입력하고 연산자 버튼을 누릅니다.firstOperand
로 저장하고, 연산자를 operator
로 저장합니다.secondOperand
로 저장합니다. 다시 연산자를 누르면, 이전에 입력한 secondOperand
와 operator
로 계산이 됩니다.firstOperand
를 결과 값으로 업데이트합니다.// 모든 버튼 요소와 디스플레이 요소를 선택합니다.
const buttons = document.querySelectorAll('.button');
const display = document.querySelector('.input');
// 피연산자와 연산자를 저장할 변수를 선언합니다.
let firstOperand = null;
let operator = null;
let waitingForSecondOperand = false;
// 초기 디스플레이 값을 설정합니다.
display.textContent = '0';
// 각 버튼에 클릭 이벤트 리스너를 추가합니다.
buttons.forEach((button) => {
button.addEventListener('click', () => {
const buttonText = button.textContent;
// 숫자 버튼을 클릭한 경우
if (button.classList.contains('number')) {
inputDigit(buttonText);
}
// 연산자 버튼을 클릭한 경우
else if (button.classList.contains('operator')) {
handleOperator(buttonText);
}
// 소수점 버튼을 클릭한 경우
else if (buttonText === '.') {
inputDecimal(buttonText);
}
// 'C' 버튼을 클릭한 경우
else if (buttonText === 'C') {
resetCalculator();
}
// 그 외의 버튼들 처리 (±, %)
else if (buttonText === '±') {
toggleSign();
} else if (buttonText === '%') {
inputPercent();
}
});
});
// 숫자를 입력하는 함수
function inputDigit(digit) {
if (waitingForSecondOperand) {
display.textContent = digit;
waitingForSecondOperand = false;
} else {
if (display.textContent === '0') {
display.textContent = digit;
} else {
display.textContent += digit;
}
}
updateFontSize();
}
// 소수점을 입력하는 함수
function inputDecimal(dot) {
if (waitingForSecondOperand) {
display.textContent = '0.';
waitingForSecondOperand = false;
return;
}
if (!display.textContent.includes(dot)) {
display.textContent += dot;
}
updateFontSize();
}
// 연산자를 처리하는 함수
function handleOperator(nextOperator) {
const inputValue = parseFloat(display.textContent);
if (operator && waitingForSecondOperand) {
operator = nextOperator === '=' ? null : nextOperator;
console.log(`Operator changed to ${operator}`);
return;
}
if (firstOperand === null) {
firstOperand = inputValue;
} else if (operator) {
const result = calculate(firstOperand, inputValue, operator);
display.textContent = formatResult(result);
firstOperand = result;
}
waitingForSecondOperand = true;
operator = nextOperator === '=' ? null : nextOperator;
console.log(`First Operand: ${firstOperand}, Operator: ${operator}`);
updateFontSize();
}
// 계산을 수행하는 함수
function calculate(firstOperand, secondOperand, operator) {
let result;
if (operator === '+') {
result = firstOperand + secondOperand;
} else if (operator === '−') {
result = firstOperand - secondOperand;
} else if (operator === '×') {
result = firstOperand * secondOperand;
} else if (operator === '÷') {
if (secondOperand === 0) {
alert('0으로 나눌 수 없습니다.');
return 0;
}
result = firstOperand / secondOperand;
} else {
return secondOperand;
}
// 부동소수점 오류를 최소화하기 위해 결과를 반올림합니다.
result = parseFloat(result.toFixed(10));
return result;
}
// 결과를 포맷팅하는 함수
function formatResult(result) {
if (result.toString().length > 12) {
// 지수 표기법으로 변환
return result.toExponential(5);
} else {
return result.toString();
}
}
// 계산기를 초기화하는 함수
function resetCalculator() {
display.textContent = '0';
firstOperand = null;
operator = null;
waitingForSecondOperand = false;
updateFontSize();
}
// 부호를 변경하는 함수
function toggleSign() {
const currentValue = parseFloat(display.textContent);
if (currentValue === 0) return;
display.textContent = (-currentValue).toString();
updateFontSize();
}
// 퍼센트를 계산하는 함수
function inputPercent() {
const currentValue = parseFloat(display.textContent);
const newValue = currentValue / 100;
display.textContent = newValue.toString();
updateFontSize();
}
// 디스플레이 글자 크기를 조정하는 함수
function updateFontSize() {
const length = display.textContent.length;
if (length > 10) {
display.style.fontSize = '30px';
} else if (length > 7) {
display.style.fontSize = '40px';
} else {
display.style.fontSize = '48px';
}
}
마무리로 테스트 실행하고 끝~