I’m trying to apply a CSS fade-in effect to a text paragraph when the page loads. I have the following markup:
<div id="test">
<p>This is a test</p>
</div>
And here’s the CSS I’m using:
#test p {
opacity: 0;
margin-top: 25px;
font-size: 21px;
text-align: center;
transition: opacity 2s ease-in;
}
The transition is defined, but it doesn’t automatically trigger when the page loads.
What’s the proper way to make this fade-in effect happen as soon as the page loads, without using JavaScript if possible?
Should I be toggling a class or using a body.loaded type of approach with CSS animations instead? Looking for the cleanest solution using pure CSS, if achievable.
Absolutely, the cleanest way to handle a CSS fade in on page load without JavaScript is by using @keyframes
. You can animate the opacity and even adjust the delay or duration as needed:
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
#test p {
opacity: 0;
animation: fadeIn 2s ease-in forwards;
}
This will trigger the animation as soon as the element renders. I use this method a lot for hero sections or landing page intros, it’s simple, elegant, and pure CSS.
If you plan to have multiple elements fade in at different intervals, CSS animation-delay is super handy.
Here’s how you could make your CSS fade in more dynamic:
@keyframes fadeIn {
0% { opacity: 0; }
100% { opacity: 1; }
}
#test p {
opacity: 0;
animation: fadeIn 2s ease-in 0.5s forwards;
}
I use this approach on dashboards or content-heavy pages where I want to gently reveal text or cards in sequence. Keeps things lightweight and user-friendly.
If you’re using modern browsers that support :has()
(Safari/Chrome 105+), you can simulate a CSS fade in trigger by using a container class.
Combine this with a utility class like .loaded added to the body (manually or through server-side rendering):
body:has(.loaded) #test p {
opacity: 1;
transition: opacity 2s ease-in;
}
Just make sure .loaded is present on initial render.
I’ve used this in JAMstack sites to simulate load states without touching JavaScript, it’s progressive enhancement done right.