Stop HTML elements from shifting position when content is modified using JavaScript

'use strict';

const countdown = () => {
  // create function to calculate time until launch in Days/Hours/Minutes/Seconds

  // time difference
  const countDate = new Date('May 25, 2024 00:00:00').getTime();
  const now = new Date().getTime();
  const gap = countDate - now;

  const second = 1000;
  const minute = second * 60;
  const hour = minute * 60;
  const day = hour * 24;

  const textDay = Math.floor(gap / day);
  const textHour = Math.floor((gap % day) / hour);
  const textMinute = Math.floor((gap % hour) / minute);
  const textSecond = Math.floor((gap % minute) / second);

  // update time in HTML
  document.querySelector('.day').innerText = textDay;
  document.querySelector('.hour').innerText = textHour;
  document.querySelector('.minute').innerText = textMinute;
  document.querySelector('.second').innerText = textSecond;
};

// runs function every second
setInterval(countdown, 1000);
* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}
html {
  font-size: 62.5%;
  font-family: 'Rubik', sans-serif;
  color: #f8f9fa;
}
.countdown-container {
  color: #343a40;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  background-image: linear-gradient(
      rgba(34, 34, 34, 0.1),
      rgba(34, 34, 34, 0.1)
    ),
    url(./img/countdown.jpg);
  background-size: cover;
}
.countdown-container h2 {
  letter-spacing: 0.1rem;
  font-size: 10rem;
  font-weight: 700;
  padding: 5rem;
  padding-bottom: 8vh;
}
.countdown {
  display: flex;
  text-align: center;
  justify-content: space-around;
}
.day,
.hour,
.minute,
.second {
  font-size: 5rem;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <link rel="preconnect" href="https://fonts.googleapis.com" />
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
  <link href="https://fonts.googleapis.com/css2?family=Rubik:wght@400;600;700&display=swap" rel="stylesheet" />
  <link rel="stylesheet" href="style.css">
  <title>Test</title>
</head>

<body>
  <section class="countdown-container">
    <div>
      <h2 class="countdown-header">Time until Launch</h2>
      <div class="countdown">
        <div class="container-day">
          <h3 class="day">Time</h3>
          <h3>Days</h3>
        </div>
        <div class="container-hour">
          <h3 class="hour">Time</h3>
          <h3>Hours</h3>
        </div>
        <div class="container-minute">
          <h3 class="minute">Time</h3>
          <h3>Minutes</h3>
        </div>
        <div class="container-second">
          <h3 class="second">Time</h3>
          <h3>Seconds</h3>
        </div>
      </div>
    </div>
  </section>
  <script src="./app.js"></script>
</body>
</html>

Hi,

I created a countdown timer, but I am facing an issue where the elements move slightly every time the numbers are updated. How can I fix this? The problem is visible in the code snippet provided above...

(Random text, I need to add more content to post... Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro qui inventore ad fugit ea non harum est quas deserunt quia!)

Thank you :)

Answer №1

One reason for this behavior is the CSS property justify-content: space-around; being applied to the .countdown class. When the div containing the seconds (and others) does not have a fixed width, the width of the parent div changes based on the varying text width when using a variable-width font. Consequently, justify-content: space-around; adjusts the layout to ensure equal spacing between elements.

To mitigate this issue, consider using a monospace font if your design requirements allow it.

An alternative solution is to assign a specific width to all time segments to maintain consistency:

div.countdown>div {
  width: 40px;
}

I opted for a fixed width of 40px in my example, but you may need to experiment with other values. I also tested with 25% width, which improved the situation but caused slight movement in the seconds display.

'use strict';

const countdown = () => {
  // Function to calculate time until launch in Days/Hours/Minutes/Seconds

  // Time difference
  const countDate = new Date('May 25, 2024 00:00:00').getTime();
  const now = new Date().getTime();
  const gap = countDate - now;

  const second = 1000;
  const minute = second * 60;
  const hour = minute * 60;
  const day = hour * 24;

  const textDay = Math.floor(gap / day);
  const textHour = Math.floor((gap % day) / hour);
  const textMinute = Math.floor((gap % hour) / minute);
  const textSecond = Math.floor((gap % minute) / second);

  // Update time in HTML
  document.querySelector('.day').innerText = textDay;
  document.querySelector('.hour').innerText = textHour;
  document.querySelector('.minute').innerText = textMinute;
  document.querySelector('.second').innerText = textSecond;
};

// Run function every second
setInterval(countdown, 1000);
* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}
html {
  font-size: 62.5%;
  font-family: 'Rubik', sans-serif;
  color: #f8f9fa;
}
.countdown-container {
  color: #343a40;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  background-image: linear-gradient(
      rgba(34, 34, 34, 0.1),
      rgba(34, 34, 34, 0.1)
    ),
    url(./img/countdown.jpg);
  background-size: cover;
}
.countdown-container h2 {
  letter-spacing: 0.1rem;
  font-size: 10rem;
  font-weight: 700;
  padding: 5rem;
  padding-bottom: 8vh;
}
.countdown {
  display: flex;
  text-align: center;
  justify-content: space-around;
}
.day,
.hour,
.minute,
.second {
  font-size: 5rem;
}

div.countdown>div {
  width: 40px;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <link rel="preconnect" href="https://fonts.googleapis.com" />
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
  <link href="https://fonts.googleapis.com/css2?family=Rubik:wght@400;600;700&display=swap" rel="stylesheet" />
  <link rel="stylesheet" href="style.css">
  <title>Test</title>
</head>

<body>
  <section class="countdown-container">
    <div>
      <h2 class="countdown-header">Time until Launch</h2>
      <div class="countdown">
        <div class="container-day">
          <h3 class="day">Time</h3>
          <h3>Days</h3>
        </div>
        <div class="container-hour">
          <h3 class="hour">Time</h3>
          <h3>Hours</h3>
        </div>
        <div class="container-minute">
          <h3 class="minute">Time</h3>
          <h3>Minutes</h3>
        </div>
        <div class="container-second">
          <h3 class="second">Time</h3>
          <h3>Seconds</h3>
        </div>
      </div>
    </div>
  </section>
  <script src="./app.js"></script>
</body>
</html>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Hybrid component that combines static and dynamic elements in Gatsby

The inconsistency in behavior between the site generated by gatsby develop and gatsby build is causing an issue where the site works during development but not when it's in production. An overview of my website: My website is a simple blog-like plat ...

Adjusting the cell size to align with the height of another cell in the same row

Within a table row, I have two cells that contain divs and the height varies due to changing content. Is there a way for one cell to take up 100% height to match the other cell? You can see an example here. The goal is for the second cell and its div to ...

Which one should I use: ng-repeat or ng-options?

I am looking to display JSON data in a dropdown list, and I have two options to choose from. The first option is using ng-repeat, while the other option is ng-options. Using ng-repeat: In the HTML file: <select> <option ng-repeat="prod in testA ...

Every time I try to access Heroku, I encounter an issue with Strapi and the H10 error code

Upon opening Heroku and running the command "heroku logs --tail", my app encountered a crash and I can't seem to locate my Strapi application in Heroku. 2020-05-04T19:05:38.602418+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GE ...

Building a custom form layout using Bootstrap v4 with three input fields and a button all lined up on one

I am struggling to create a form with 3 input fields and a button on the same row using Bootstrap v4 for the design. Can anyone help me figure this out? Take a look at my current design: Click here My Code <div class="col-sm-7 mx-auto bg-faded"&g ...

Converting Ajax to JSON with Jquery offline and Manifest for enhanced offline web applications

Looking to create an offline web application, I'm in the process of transitioning from Ajax to JSON using JQuery offline. Here is the initial Ajax code: $.ajax({ url: contentpage, data: contentpagedata, cache: false }).done(function( html ) { ...

What is the best way to swap out an HTML file with another without altering the link?

I'm working on an HTML file, which is basically a webpage. My goal is to create a functionality where clicking a button will dynamically replace the content of the page with another HTML file, complete with its own CSS, JavaScript functions, and other ...

What methods can I use to ensure the headline remains fixed like the table headers?

I am currently working on creating sticky table headers. Below is an example showcasing my progress and what I am aiming to accomplish. Below is the script I discovered from another source. function makeTableHeadersSticky(tableId) { var thArr = $(tableId ...

Error: Unable to execute workouts.map as a function in "React" due to a TypeError

This is the JSON data retrieved from the server: {workouts: Array(3)} workouts: Array(3) 0: {_id: 'idnumber1', title: 'pullup', reps: 40, load: '20', createdAt: '2022-07-20T18:06:39.642Z', …} 1: {_id: 'idnumb ...

I keep encountering a 'Missing Permissions' issue whenever I attempt to execute the ban command in Discord.js. What could be causing this problem?

While working on coding a ban command for my Discord server, I encountered an issue where the command was not working as expected. Upon testing, I received an error message on the console stating DiscordAPIError[50013]: Missing Permissions. This was puzzli ...

Personalize Material design slider Label - final element

When using Material-ui, the default position of Slider's labels is centered: However, I require the labels to have a space-between position. For example: To achieve this, I tried using the '&:last-child' property for the markLabel clas ...

Using a percentage width on a <div> element with the "overflow-x: scroll" property does not seem to be functioning properly, even when encapsulated within

My code includes a div within another div, taking up 50% of the page's width: <div id="mainContainer" class="mainContainer"> <div id="scroller" class="scrolling"> <!-- items here should make the div really long --> & ...

Preventing navbar resizing on websites

I'm trying to have a section on the navbar dedicated for text or alerts that appear based on certain events. However, even when the alert is hidden, it still affects the height of the navbar. How can I resolve this issue? It may be difficult to see i ...

Encountering a 404 error when typing a link and refreshing the page in Laravel combined with VueJS

I encountered an issue while working on a Laravel VueJS application for our Proof of Concept (POC). I have integrated vue-router into the project and it is functional. However, whenever I attempt to navigate to a specific page defined in the routes of app. ...

Ensure that items are properly aligned within a container with full width and an overflow:scroll property

I'm facing a bit of a challenge here... I have a container with a max-width setting, and inside that container, I want to have a slider that spans the full width with horizontal scrolling capability. To achieve this, I followed the instructions from ...

Is there an easy way to determine if an element inside a Vue component is overflowing?

I created a unique component called ResultPill which includes a tooltip feature (implemented using vuikit). The text displayed in the tooltip is determined by a getter function called tooltip, utilizing vue-property-decorator. Here are the relevant parts o ...

What is the proper way to add process.env.PORT to the script declarations string within my package.json file?

I am facing an issue while trying to upload my file on Heroku that requires including the PORT specification. Unlike my previous projects, this project consists of only html, js, and css files instead of an index.js file. To run it, I am using "live-server ...

Acquire HTML content and save it in a MYSQL database: A Step-by-Step Guide

How can I effectively store an HTML page with CSS in a MYSQL database? Is this even feasible? What type of column should be used for storage? And how can I retrieve the stored formatted HTML and display it correctly using PHP? If the page contains imag ...

Encounter the error "Attempting to access object using Object.keys on a non-object" when attempting to retrieve all fields in request.body in Node.js?

I am working with a piece of code that handles the PUT method: module.exports.addRoutes = function(server) { //PUT server.put('/api/public/place/:id', function(request, response) { //this is just for testing, please do not care ...

limitation in bootstrap ensures that only one collapse element is open at any

Hey, can someone help me fix this code? I'm trying to make it so that only one element opens at a time, but I can't seem to figure out how. Right now, if I click on two elements, they both open and the other one doesn't close. This is what ...