2학년 1학기 때 인터넷 프로그래밍을 들은 후 처음 잡아본 웹이다. 기억을 되살리는 겸 간단히 프로젝트를 진행해보았다. 생각보다 기억나지 않는 게 많아서 구글링에 의지하며 만들어보았다.
완성 모습

HTML
먼저 html이다. 뭘 어떻게 해야할 지 모르겠어서 기본적인 틀을 잡았다.

calculator 클래스로 전체 틀을 묶고, display 칸을 만들었다.
<div class="calculator">
<div class="display">
<input type="text" id="display" value="0">
</div>
class display는 표시되는 입력 칸 전체(컨테이너)를, id display는 입력되는 텍스트 부분만을 의미한다.
타입을 text로 지정하여 사용자가 텍스트를 입력할 수 있는 필드로 지정해주었다. 기본값은 0으로 설정했다.
<div class="buttons">
<button class="operator">C</button>
<button class="operator">AC</button>
<button class="operator">%</button>
<button class="operator"><</button>
</div>
<div class="buttons">
<button class="number">7</button>
<button class="number">8</button>
<button class="number">9</button>
<button class="operator">/</button>
</div>
<div class="buttons">
<button class="number">4</button>
<button class="number">5</button>
<button class="number">6</button>
<button class="operator">*</button>
</div>
<div class="buttons">
<button class="number">1</button>
<button class="number">2</button>
<button class="number">3</button>
<button class="operator">-</button>
</div>
<div class="buttons">
<button class="number">0</button>
<button class="decimal">.</button>
<button id="equals">=</button>
<button class="operator">+</button>
</div>
button은 크게 연산자(operator)와 숫자(number)로 구분했다. "."과 "="만 따로 decimal과 equals로 구분하였다.
다음은 html 전체 코드이다.
<div class="calculator">
<div class="display">
<input type="text" id="display" value="0">
</div>
<div class="buttons">
<button class="operator">C</button>
<button class="operator">AC</button>
<button class="operator">%</button>
<button class="operator"><</button>
</div>
<div class="buttons">
<button class="number">7</button>
<button class="number">8</button>
<button class="number">9</button>
<button class="operator">/</button>
</div>
<div class="buttons">
<button class="number">4</button>
<button class="number">5</button>
<button class="number">6</button>
<button class="operator">*</button>
</div>
<div class="buttons">
<button class="number">1</button>
<button class="number">2</button>
<button class="number">3</button>
<button class="operator">-</button>
</div>
<div class="buttons">
<button class="number">0</button>
<button class="decimal">.</button>
<button id="equals">=</button>
<button class="operator">+</button>
</div>
</div>
CSS
* {
margin: 0;
padding: 0;
box-sizing: border-box;
user-select: none;
}
모든 요소에 대하여 html의 기본값의 여백을 없애고 원하는 대로 여백을 주기 위하여 margin과 padding을 0으로 설정했다.
box-sizing는 각 요소의 크기 계산 방식을 정하는 값이다. 기본값은 content-box로, 이 경우 width와 height가 요소의 콘텐츠 영역 크기만을 기준으로 계산된다. 이를 border-box로 설정하여, width와 height가 요소의 전체 크기(padding과 border를 포함한 크기)로 계산되도록 해주었다.
user-select를 none으로 설정하여 사용자가 텍스트를 마우스로 드래그하거나 복사하지 못하도록 하였다.
.calculator {
width: 300px;
height: 500px;
padding: 20px;
background-color: #f4faf5;
border: 1px solid #cecfce;
border-radius: 10px;
display: flex;
flex-direction: column;
}
width, height로 크기 지정, padding으로 여백 지정, background-color로 계산기의 색을 정했다.
border로 테두리의 두께, 모양, 색을 정하고, border-radius로 모서리를 약간 둥글게 해주었다.
display: flex로 calculator를 플렉스 컨테이너로 만들어, 내부의 자식 요소들이 calculator의 크기에 따라 자동으로 크기, 위치를 조정하도록 해주었다.
flex-direction: column로 지정하여, calculator의 자식 요소들이 세로로 쌓이게 만들었다. flex-direction의 기본값은 가로 배치(row)이다.
.display {
text-align: center;
height: 50px;
margin: 10px;
}
display의 컨테이너를 계산기 내에서 가운데 정렬 하고, 높이와 여백을 지정했다.
.display input {
width: 250px;
text-align: right;
padding: 10px;
border: none;
font-size: 2rem;
background-color: #f4faf5;
color: black;
}
display의 텍스트 입력부의 넓이를 지정하고, 실제 계산기처럼 오른쪽 정렬했다.
padding으로 여백을 지정하고, border: none으로 테두리를 없도록 설정했다.
font size와 background color, 그리고 글자 색인 color를 지정했다.
.buttons {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
margin-top: 15px;
height: 100%;
}
버튼 전체 부분을 의미하는 buttons 클래스에 대해서,
display: grid;와 grid-template-columns: repeat(4, 1fr);를 통해 정해진 범위(계산기) 내에서 버튼을 grid 형태로 정렬하고, 각 버튼이 동일한 크기로 4등분되어 배치되게 했다.
각각 display: grid는 buttons 클래스를 그리드 컨테이너로 만들어, 그 내부 자식 요소들인 button을 그리드 항목으로 배치하게 해주는 코드이고, grid-template-columns: repeat(4, 1fr)는 그리드의 열을 4개로 설정하고, 각 열의 크기를 1fr로 지정한 것이다. 여기서 1fr은 가용 공간을 균등하게 나누겠다는 의미로, 4개의 열이 동일한 너비를 가지게 한다.
button {
width: 100%;
height: 100%;
background-color: #eaf5eb;
border-radius: 50%;
border: 1px solid #cecfce;
}
각 버튼에 대한 설정이다.
width와 height는 가용 범위 내의 최대 크기를 사용하도록 했고(100%), background color를 지정해주었다.
border-radius를 50%로 주어 버튼이 원형이 되도록 했고, border 설정으로 테두리 굵기, 모양, 색을 지정했다.
| html에서 | css에서 |
| id (id: button) | #으로 호출 (#button) |
| class (class: button) | .으로 호출 (.button) |
| 태그 (<button>) | 그냥 호출 (button) |
button:hover {
border-color: #9c9d9c;
}
button 태그에 hover를 주어, 사용자가 마우스를 올리면 border color(테두리 색)이 약간 더 진한 색으로 변하게 하였다.
#equals {
background-color: #bbe2c1;
}
마지막으로 등호만 다른 버튼들과 차별되는 색을 주었다.
다음은 CSS 전체 코드이다.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
user-select: none;
}
.calculator {
width: 300px;
height: 500px;
padding: 20px;
background-color: #f4faf5;
border: 1px solid #cecfce;
border-radius: 10px;
display: flex;
flex-direction: column;
/*display margin 0 auto;*/
}
.display {
text-align: center;
height: 50px;
margin: 10px;
}
.display input {
width: 250px;
text-align: right;
padding: 10px;
border: none;
font-size: 2rem;
background-color: #f4faf5;
color: black;
}
.buttons {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
margin-top: 15px;
height: 100%;
}
button {
width: 100%;
height: 100%;
background-color: #eaf5eb;
border-radius: 50%;
border: 1px solid #cecfce;
}
button:hover {
border-color: #9c9d9c;
}
#equals {
background-color: #bbe2c1;
}
JS
const display = document.getElementById("display");
const buttons = document.querySelectorAll("button");
const operators = ['+', '-', '*', '/', '%'];
가장 먼저 document(html 파일)에서 display와 button 항목을 찾아와 변수에 지정해주었다.
(document는 현재 로드된 HTML 문서의 DOM(Document Object Model)을 참조한다.)
operators는 따로 지정하여 밑에서 이벤트 발생 시 연산자라면~을 판별하는 조건문에 사용할 예정이다.
buttons.forEach(button => {
button.addEventListener("click", function() {
const value = button.textContent;
if (value === "=") {
display.value = eval(display.value);
} else if (value === "AC") {
display.value = "0";
} else if (value === "C") {
display.value = "0";
} else if (value === "<") {
display.value = display.value.slice(0, -1);
} else if (operators.includes(value)) {
display.value += value;
} else {
if (display.value === "0") {
display.value = value;
} else {
display.value += value;
}
}
});
});
button이 click되는 이벤트이다.
button.forEach(button => { : 모든 버튼에 대하여 반복 작업을 수행한다.
button.addEventListener("click", function() { : 버튼에 대하여 "click"이 일어나면 해당 함수를 실행
const value = button.textContent; : value에 현재 클릭된 버튼의 text 내용이 들어간다.
다음 조건문을 보기 전에, display.value는 현재 display에 있는 모든 텍스트를 의미한다.
if (value === "=") {
display.value = eval(display.value);
=이 눌리면 현재 display에 있는 텍스트를 계산(eval 함수)하여 display.value에 넣는다. 즉, display에 있는 값이 계산된 값으로 바뀐다.
} else if (value === "AC") {
display.value = "0";
} else if (value === "C") {
display.value = "0";
AC와 C가 눌리면 display에 있는 값을 0으로 초기화한다.
} else if (value === "<") {
display.value = display.value.slice(0, -1);
<가 눌리면 현재 display에 있는 텍스트에서 하나를 지운다. (ex: 123 -> 12)
} else if (operators.includes(value)) {
display.value += value;
operators에 있는 값들 중 하나가 눌렸다면 (연산자가 눌렸다면) display에 있는 텍스트의 끝에 해당 텍스트를 추가한다.
} else {
if (display.value === "0") {
display.value = value;
} else {
display.value += value;
}
그밖의 경우, 즉 숫자가 눌리는 경우에는,
실제 계산기에서 0이 display에 있고 다른 숫자(ex: 3)가 눌리면 03이 되는게 아니라 0이 되므로,
현재 display에 0이 있고 다른 숫자가 눌린다면 현재 눌린 값을 0 대신 써주도록 하고, 그게 아니라면 operator처럼 현재 텍스트의 끝에 해당 텍스트를 추가한다.
다음은 키보드가 눌리는 이벤트이다.
document.addEventListener("keydown", function(e) {
const value = e.key;
if (value === "Enter") {
display.value = eval(display.value);
} else if (value == "Backspace") {
display.value = display.value.slice(0, -1);
} else if (value >= "0" && value <= "9") {
if (display.value === "0") {
display.value = value;
} else {
display.value += value;
}
} else if(operators.includes(value)) {
display.value += value;
}
});
document.addEventListener("keydown", function(e) { : keydown 이벤트, 즉 키보드가 눌리는 이벤트가 발생한다면 해당 함수를 실행한다.
const value = e.key; value라는 변수에 현재 눌린 키를 넣어준다.
if (value === "Enter") {
display.value = eval(display.value);
Enter가 눌리면 "=" 버튼이 눌린 이벤트와 마찬가지로 현재 display에 있는 텍스트를 연산하여 display에 업데이트한다.
} else if (value == "Backspace") {
display.value = display.value.slice(0, -1);
Backspace가 눌렸다면 현재 display에 있는 텍스트에서 하나를 지운다. (ex: 123 -> 12)
} else if (value >= "0" && value <= "9") {
if (display.value === "0") {
display.value = value;
} else {
display.value += value;
}
숫자가 들어온다면, 현재 display에 있는 값이 0이라면 현재 눌린 값으로 display값을 업데이트 한다. 아니라면 현재 텍스트에 지금 눌린 텍스트를 추가한다.
} else if(operators.includes(value)) {
display.value += value;
}
현재 눌린 값이 operators중 하나라면, 즉 연산자가 눌렸다면 현재 텍스트에 지금 눌린 텍스트를 추가한다.
다음은 JS 코드 전체이다.
const display = document.getElementById("display");
const buttons = document.querySelectorAll("button");
const operators = ['+', '-', '*', '/', '%'];
buttons.forEach(button => {
button.addEventListener("click", function() {
const value = button.textContent;
if (value === "=") {
display.value = eval(display.value);
} else if (value === "AC") {
display.value = "0";
} else if (value === "C") {
display.value = "0";
} else if (value === "<") {
display.value = display.value.slice(0, -1);
} else if (operators.includes(value)) {
display.value += value;
} else {
if (display.value === "0") {
display.value = value;
} else {
display.value += value;
}
}
});
});
document.addEventListener("keydown", function(e) {
const value = e.key;
if (value === "Enter") {
display.value = eval(display.value);
} else if (value == "Backspace") {
display.value = display.value.slice(0, -1);
} else if (value >= "0" && value <= "9") {
if (display.value === "0") {
display.value = value;
} else {
display.value += value;
}
} else if(operators.includes(value)) {
display.value += value;
}
});
아쉬운 부분이자 앞으로 보완할 부분
1. 연산자가 연속으로 들어오면 실제 계산기에서는 새로운 연산자로 계속 업데이트하는데, 내 계산기에서는 +-이런식으로 텍스트에 계속 추가된다.
2. 실제 계산기처럼 맨 앞에 -가 들어오면 음수로 시작 할 수 있게 하는 기능
3. =로 연산을 끝내고 나서 새로운 입력을 시도하면 실제 계산기에서는 현재 계산 값이 초기화되고 새로 입력이 진행되는데, 내 계산기에서는 계산이 완료된 후의 텍스트에 추가 입력이 뒤에 추가된다.
인터넷 프로그래밍을 복기하는 의미에서 시작한 프로젝트로 이정도로 간단하게 마무리하고, 추후 공부가 더 된 후에 보완하도록 하겠다.