Building a Calculator with HTML, CSS, and JavaScript

huericnan

Eric Hu

Posted on January 2, 2024

Building a Calculator with HTML, CSS, and JavaScript

In this article, we will discuss how to create a calculator using HTML, CSS, and JavaScript. This project focuses on the most fundamental functionalities, making it an excellent practice project to improve your programming skills as a beginner.

➡️ Get the source code for FREE!

calculator

Creating the calculator layout

As usual, let's start by creating the HTML skeleton.



<div class="calculator">
  <div class="display">0</div>
  <div class="buttons">
    <div class="button function">AC</div>
    <div class="button function">+/-</div>
    <div class="button function">%</div>
    <div class="button function">/</div>

    <div class="button number">7</div>
    <div class="button number">8</div>
    <div class="button number">9</div>
    <div class="button function">*</div>

    <div class="button number">4</div>
    <div class="button number">5</div>
    <div class="button number">6</div>
    <div class="button function">-</div>

    <div class="button number">1</div>
    <div class="button number">2</div>
    <div class="button number">3</div>
    <div class="button function">+</div>

    <div class="button number">0</div>
    <div class="button function">.</div>
    <div class="button function">=</div>
  </div>
</div>


Enter fullscreen mode Exit fullscreen mode
  • .calculator is a container that wraps around the whole calculator.
  • .display shows the user input, as well as the output of the calculation.
  • .buttons contains both the .number buttons (0-9) and the .function buttons (+, -, *...).

And, of course, you must set up the event listeners so that when a button is clicked, the corresponding function is executed.



<div class="calculator">
  <div class="display" id="display">0</div>
  <div class="buttons">
    <div class="button function" onclick="clearDisplay()">AC</div>
    <div class="button function" onclick="toggleSign()">+/-</div>
    <div class="button function" onclick="percent()">%</div>
    <div class="button function" onclick="appendOperator('/')">/</div>

    <div class="button number" onclick="appendNumber('7')">7</div>
    <div class="button number" onclick="appendNumber('8')">8</div>
    <div class="button number" onclick="appendNumber('9')">9</div>
    <div class="button function" onclick="appendOperator('*')">*</div>

    <div class="button number" onclick="appendNumber('4')">4</div>
    <div class="button number" onclick="appendNumber('5')">5</div>
    <div class="button number" onclick="appendNumber('6')">6</div>
    <div class="button function" onclick="appendOperator('-')">-</div>

    <div class="button number" onclick="appendNumber('1')">1</div>
    <div class="button number" onclick="appendNumber('2')">2</div>
    <div class="button number" onclick="appendNumber('3')">3</div>
    <div class="button function" onclick="appendOperator('+')">+</div>

    <div class="button number" id="Num0" onclick="appendNumber('0')">0</div>
    <div class="button function" onclick="appendOperator('.')">.</div>
    <div class="button function" onclick="calculate()">=</div>
  </div>
</div>


Enter fullscreen mode Exit fullscreen mode

Before we start coding, we also need to discuss the general structure of this project.

First of all, there should be a global variable (displayValue) to store the displayed value, as well as a helper function (updateDisplay()) that updates the .display based on the variable. The function selects the display element and updates its content.

There should also be an appendNumber() and appendOperator() functions that append new digits to displayValue. Lastly, you need a calculate() function that executes the mathematical expression and returns the value.

And of course, there are other functions such as clearDisplay(), toggleSign(), and percent().

Adding styles

Next, you should add some styles so that our calculator actually looks like a calculator.

First of all, the .buttons should be a grid layout with 4 columns and 5 rows. As an example, I'm making each cell to be 100px wide, and with a 5px gap in between.



.buttons {
  display: grid;
  grid-template-columns: 100px 100px 100px 100px;
  gap: 5px;
}


Enter fullscreen mode Exit fullscreen mode

And then customize the individual buttons to make them look more pleasing.



.button {
  padding: 20px 0px;
  text-align: center;
}

.function {
  background-color: coral;
}

.number {
  background-color: bisque;
}


Enter fullscreen mode Exit fullscreen mode

number pad grid

The number 0 is a special case, as it spans over multiple columns. This can be achieved using the grid-column-start and grid-column-end properties.



<div class="button number" id="Num0" onclick="appendNumber('0')">0</div>


Enter fullscreen mode Exit fullscreen mode


#Num0 {
  grid-column-start: 1;
  grid-column-end: 3;
}


Enter fullscreen mode Exit fullscreen mode

As for the display, it may be designed however you like, as long as it looks good to you. Here is what I did:



.calculator {
  width: fit-content;
}

.display {
  border: 1px solid;
  margin-bottom: 5px;
  padding: 15px 10px;
  text-align: right;
  font-family: "Courier New", Courier, monospace;
  font-size: xx-large;
}


Enter fullscreen mode Exit fullscreen mode

Adding scripts

And finally, for the most important part, the scripts. First of all, as we've discussed before, you need a global variable to store the value that will be displayed, as well as a helper function that updates the display based on the variable.



let displayValue = "";

function updateDisplay() {
  if (displayValue === "") {
    document.getElementById("display").innerHTML = "0";
  } else {
    document.getElementById("display").innerHTML = displayValue;
  }
}


Enter fullscreen mode Exit fullscreen mode

Here, I'm using the ID selector getElementById("display"), so make sure your display element has the correct ID as well.



<div class="calculator">
  <div class="display" id="display">0</div>
  <div class="buttons">. . .</div>
</div>


Enter fullscreen mode Exit fullscreen mode

innerHTML points to the content of the selected HTML node.

In this example, if the displayValue is empty, 0 will be displayed. If not, the actual value will be displayed.

appendNumber() and appendOperator()

Next, you need an appendNumber() function that updates the displayValue by appending new numbers and also updates the display afterward.



function appendNumber(number) {
  displayValue += number;
  updateDisplay();
}


Enter fullscreen mode Exit fullscreen mode

And of course, the appendOperator() function does the same thing, but with the operator keys.



function appendOperator(operator) {
  if (
    displayValue !== "" &&
    !isNaN(displayValue.charAt(displayValue.length - 1))
  ) {
    displayValue += operator;
    updateDisplay();
  }
}


Enter fullscreen mode Exit fullscreen mode

However, this function is a bit tricker for two reasons. First, you can't have two consecutive operators. For example, the equation 12 */--+ 21 doesn't make any sense. So before adding a new operator digit, you must check that the last digit of displayValue is not an operator.

In this example, displayValue.charAt(displayValue.length - 1) retrieves the last digit of displayValue, isNaN() returns true if the given value is NOT a number, and ! flips the given value. Putting them together, line 4 returns true if the last digit of displayValue is a number.

And second, an equation should not start with an operator, so you have to ensure displayValue is not empty before adding an operator (displayValue !== "").

calculate()



function calculate() {
  if (
    displayValue !== "" &&
    !isNaN(displayValue.charAt(displayValue.length - 1))
  ) {
    try {
      const result = eval(displayValue);
      displayValue = result.toString();
      updateDisplay();
    } catch (error) {
      displayValue = "Error";
      updateDisplay();
    }
  }
}


Enter fullscreen mode Exit fullscreen mode

The calculate() function is at the heart of this project, but it is actually rather easy to understand. We are using the built-in function eval() to do all the heavy lifting. You simply pass the displayValue to the function eval(), and it will return the result. However, you should remember to catch the potential errors, just in case the equation doesn't evaluate to a result that makes sense.

In practice, it is not recommended to use eval() in the production environment, as it evaluates all JavaScript expressions given to it without proper validation, and this opens the door to code injection attacks. The source code for this article implemented a more production-ready solution, and it is available for free here.

clearDisplay()



function clearDisplay() {
  displayValue = "";
  updateDisplay();
}


Enter fullscreen mode Exit fullscreen mode

Lastly, the clearDisplay() function resets displayValue to an empty string.

Conclusion

You may have noticed we neglected two functions, toggleSign() and percent(). The exact implementation of these functions is available in the source code, which you can download for free. But if you prefer implementing your own version, here is a hint:

  • The toggleSign() function should examine the first digit of displayValue. If it is a number, add a - sign in the front. If it is not a number, that means displayValue is already a negative value, so simply remove it.
  • The percent() function should first convert displayValue into a number, and then calculate displayValue / 100.

If you need more assistance regarding HTML and CSS, check out my course HTML & CSS: A Practical Guide.

Happy coding!

💖 💪 🙅 🚩
huericnan
Eric Hu

Posted on January 2, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related