I am using Nuxt 3 for a project and I have created a countdown component. The countdown code is a simple setInterval with Nuxt ClientOnly tags around it to prevent hydration mismatch errors. The CountdownItem simply displays its property value.
Countdown template:
<div>
<h2 class="w-full text-center uppercase">
{{ $t("message.countdownTitle") }}
</h2>
<ClientOnly>
<div class="flex justify-center w-full gap-x-1">
<CountdownItem :number="days" text="days" />
<CountdownItem :number="hours" text="hours" />
<CountdownItem :number="minutes" text="minutes" />
<CountdownItem :number="seconds" text="seconds" />
</div>
</ClientOnly>
</div>
Countdown script
<script setup lang="ts">
import type { StrapiCountdown } from "~/types/api";
const { findOne } = useStrapi();
const { data: countdownData } = await useAsyncData("countdown", () =>
findOne<StrapiCountdown>("countdown")
);
const countDownDate = new Date(
countdownData.value?.data.attributes.date as string
).getTime();
var now = new Date().getTime();
var distance = countDownDate - now;
const days = ref<number>(Math.floor(distance / (1000 * 60 * 60 * 24)));
const hours = ref<number>(
Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
);
const minutes = ref<number>(
Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60))
);
const seconds = ref<number>(Math.floor((distance % (1000 * 60)) / 1000));
setInterval(setCountdownVariables, 1000);
function setCountdownVariables() {
// Get today's date and time
var now = new Date().getTime();
// Find the distance between now and the count down date
var distance = countDownDate - now;
// Time calculations for days, hours, minutes and seconds
days.value = Math.floor(distance / (1000 * 60 * 60 * 24)) || 0;
hours.value =
Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)) || 0;
minutes.value = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)) || 0;
seconds.value = Math.floor((distance % (1000 * 60)) / 1000) || 0;
}
</script>
CountdownItem template
<div
class="flex flex-col items-center justify-center flex-none w-20 h-20 bg-opacity-60 rounded-2xl bg-lightPurple"
>
<span class="mr-2 text-4xl font-bold antialiased">{{ number }}</span>
<span class="text-xs font-bold">{{ text }}</span>
</div>
The code works fine on every device except on iOS Safari. On iOS it creates this visual bug:
It happens when the text updates to a different number. The boundaries of the previous number get left behind as a visual artifact.
The font is Prompt Bold Italic if it helps.
It was an issue with rendering bold italic fonts. The project is using the nuxt/google-fonts
module. I had set it to import Prompt with multiple font weights. However, I had not set it to import italic font weights. Importing that fixed the problem:
I changed this:
"@nuxtjs/google-fonts",
{
families: {
"Prompt": {
wght: [300, 400, 600, 700],
},
},
},
To this:
"@nuxtjs/google-fonts",
{
families: {
"Prompt": {
wght: [300, 400, 600, 700],
ital: [300, 400, 600, 700], // Added this
},
},
},