Solving the Blank Screen Problem on Initial App Load in the Frontend
Seeing just a blank white screen when the app first opens feels a bit bare, right? I wanted to give users a good first impression, so I decided to add something that reflects our app's identity.
Attempts and Pitfalls
Initially, I tried to implement a feature where our mascot, 'Riel', would appear and greet the user on an initial screen, along with a growth bar.
<!-- initial_screen.html -->
<div class="splash-screen">
<img src="/assets/riel_greeting.png" alt="Riel greeting">
<div class="progress-bar-container">
<div class="progress-bar" style="width: 0%;"></div>
</div>
</div>
However, it turned out to be trickier than I expected. I kept running into an issue where the screen would briefly flash empty before Riel appeared. It was like Riel couldn't quite time her entrance.
// App.vue
<script setup>
import { ref, onMounted } from 'vue';
import RielGreeting from './components/RielGreeting.vue';
const showRiel = ref(false);
const growthProgress = ref(0);
onMounted(() => {
setTimeout(() => {
showRiel.value = true; // Let's show Riel!
}, 500); // Appear after 0.5 seconds
const interval = setInterval(() => {
if (growthProgress.value < 100) {
growthProgress.value += 10;
} else {
clearInterval(interval);
}
}, 200);
});
</script>
<template>
<div id="app">
<div v-if="!showRiel" class="initial-blank-screen"></div>
<riel-greeting v-if="showRiel" :progress="growthProgress" />
</div>
</template>
<style>
.initial-blank-screen {
width: 100%;
height: 100vh;
background-color: white; /* White background */
}
</style>
Even though I was clearly setting showRiel to true, a blank white screen would briefly appear before rendering. This happened even with the setTimeout delay.
The Cause
It turned out to be a problem with Vue's reactivity system and component rendering order. Because of the v-if="!showRiel" condition, the blank screen was being rendered briefly before the riel-greeting component was mounted. Then, showRiel would change to true, and the riel-greeting component would appear. The setTimeout, it seems, doesn't actually prevent the rendering itself.
The Solution
The fix was surprisingly simple. Instead of having a separate blank screen, I modified the riel-greeting component itself to appear blank initially, and then reveal its content when the data was ready.
<!-- components/RielGreeting.vue -->
<script setup>
import { computed } from 'vue';
const props = defineProps({
progress: Number
});
const progressBarWidth = computed(() => `${props.progress}%`);
</script>
<template>
<div class="riel-container">
<div v-if="progress === 0" class="riel-placeholder">
<!-- Appears as a blank screen during loading -->
</div>
<template v-else>
<img src="/assets/riel_greeting.png" alt="Riel greeting" class="riel-image">
<div class="progress-bar-wrapper">
<div class="progress-bar" :style="{ width: progressBarWidth }"></div>
</div>
</template>
</div>
</template>
<style scoped>
.riel-container {
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: #f0f0f0; /* Default background color */
}
.riel-placeholder {
width: 100%;
height: 100%;
background-color: white; /* White initially */
}
.riel-image {
width: 150px;
height: 150px;
margin-bottom: 20px;
}
.progress-bar-wrapper {
width: 200px;
height: 10px;
background-color: #ddd;
border-radius: 5px;
overflow: hidden;
}
.progress-bar {
height: 100%;
background-color: #4CAF50;
transition: width 0.3s ease-in-out;
}
</style>
// App.vue (Modified parts)
<script setup>
import { ref, onMounted } from 'vue';
import RielGreeting from './components/RielGreeting.vue';
const growthProgress = ref(0);
onMounted(() => {
const interval = setInterval(() => {
if (growthProgress.value < 100) {
growthProgress.value += 10;
} else {
clearInterval(interval);
}
}, 200);
});
</script>
<template>
<div id="app">
<riel-greeting :progress="growthProgress" />
</div>
</template>
Now, the riel-greeting component itself decides whether to show its content based on the progress value. When progress is 0, riel-placeholder is rendered, making it look like a blank screen. As progress increases, Riel's image and the growth bar gradually appear.
Results
- Provided users with a friendly character greeting experience ('Riel') upon the app's initial load.
- Added a visual element that reinforces the app's identity.
- No more blank screens during loading.
Takeaways — Avoiding the Same Pitfalls
- [ ] Double-check your understanding of component rendering order and how
v-ifworks in Vue. - [ ] Remember that
setTimeoutdelays the execution of a callback, it doesn't prevent rendering itself. - [ ] For initial loading blank screens, it's often better to manage the loading state within the component itself and show a placeholder until data is ready.
- [ ] Consider using characters or symbolic elements to create a more engaging first impression for your app.