Key Takeaways
- The CSS reveal animation can be created using only the
element, without the need for any extra elements or pseudo-elements, by manipulating padding, background color, and image positioning.
- The key to the reveal animation is to add padding to the image, then gradually reduce it to zero on hover, while using a background color to create the illusion of the image being revealed. The âobject-fit: coverâ and âobject-position: rightâ properties are used to maintain the imageâs aspect ratio and prevent it from moving during the animation.
- The reveal animation can be extended to create more variations by manipulating the padding from different sides. The âobject-fit: noneâ property can also be used in certain configurations to create different effects, but it requires the CSS width and height to match the intrinsic dimension of the image.
In this article, weâll explore some CSS tricks that allow us to create a hover animation for revealing our images.
We might be thinking âWell, thatâs an easy task! An extra element above the image that you animate and itâs done.â True, but we wonât use any extra element or pseudo-element. Weâre going to work using only the <img> element. Nothing more!
It may sound impossible because, using only the image element, we canât have something above it. Indeed, we wonât have something above it, but we will fake it!
Below is a CodePen demo of what weâre going to explore together.
See the Pen
A reveal hover effect with one element by Temani Afif (@t_afif)
on CodePen.
Cool, right? A reveal animation using only a few lines of code and no extra element. Follow me, and letâs dissect the magic behind the code.
The Initial Configuration
Weâll start by defining the size of the image:
img {
--s: 200px; /* the image size */
width: var(--s);
height: var(--s);
box-sizing: border-box;
}
Nothing complex so far. Weâre using a square image for simplicity, but it can be an image of any dimension. Itâs important to explicitly set width and height and not use aspect-ratio or leave the default size of the image. This is mandatory for our animation, and weâll see why later.
Note the use of box-sizing: border-box as well, which is also important. It has no effect for now, but letâs move to the next step to understand why itâs needed.
Adding Some Padding
What will happen if we add some padding to an image where weâve defined a fixed dimension and weâve used box-sizing: border-box? Letâs try!
See the Pen
Untitled by Temani Afif (@t_afif)
on CodePen.
The image is squished, as we can see in the above demo. We add 100px of padding on the left, which will leave only 100px of space for the image (the content-area). Thatâs the effect of box-sizing: border-box.
As explained by MDN:
border-boxtells the browser to account for any border and padding in the values you specify for an elementâs width and height. If you set an elementâs width to 100 pixels, that 100 pixels will include any border or padding you added, and the content box will shrink to absorb that extra width.
Now, imagine a situation where the padding is equal to the width. Yes, the image will disappear! In the demo below, hover over the image and see the result.
See the Pen
Animating the padding by Temani Afif (@t_afif)
on CodePen.
There are two things in particular to note in the above demo. Padding can be animated, which is cool, and we can see the importance of the CSS variable we used previously to define the size of the image. Weâve used the same variable to define the padding, so we donât have to repeat the same value.
Adding a Background Color
Letâs take the previous example and add a background to it.
See the Pen
Untitled by Temani Afif (@t_afif)
on CodePen.
Weâre starting to get somewhere now. The background will logically cover the whole element. We donât see it under the image (unless we use one with transparency), but we see it on the padding area.
Our goal is to reveal the image, so letâs start by having the padding and then making it 0 on hover â the opposite of what we currently have.
See the Pen
Untitled by Temani Afif (@t_afif)
on CodePen.
This still isnât what weâre aiming for, but weâre getting closer! Weâre missing only one ingredient to make our âfakeâ reveal animation perfect!
Adding object-fit and object-position
The missing part is to avoid the squishing of the image, and here comes the final trick. Weâre going to use object-fit with the cover value.
As explained by MDN:
The replaced content is sized to maintain its aspect ratio while filling the elementâs entire content box. If the objectâs aspect ratio does not match the aspect ratio of its box, then the object will be clipped to fit.
Two parts are important here:
- âThe replaced content is sized to maintain its aspect ratioâ. This means that the image wonât get squished but will keep its intrinsic ratio. We used a square image, so it will remain square.
- âfilling the elementâs entire content box ⊠will be clipped to fitâ. The image should fill all the content area (the area we reduce by adding some padding), but if it wonât fit inside, we clip it.
Letâs try this in the following demo.
See the Pen
Untitled by Temani Afif (@t_afif)
on CodePen.
See that? The image is no longer squished! Itâs keeping its ratio inside the content area while we add/remove the padding.
Okay, so we may be thinking that the effect isnât the same as in the initial demo. The image is moving strangely. True. So now we turn to object-position. The default value is center, so the image will be centered in the content area all the time and will get clipped to fit inside. Thatâs why it moves with the animation.
What weâll do next should be easy to predict. Weâll change the position to make sure the image wonât move. Weâll add the padding from the left, so we should fix the position of the image to the right using object-position: right.
See the Pen
Untitled by Temani Afif (@t_afif)
on CodePen.
Our reveal animation is done! We didnât need any overlay or an extra element above the image. By using a simple background color, along with some positioning tricks for the image, we get a fancy reveal animation with a small amount of simple code.
We can easily update the direction by adjusting the padding direction and the object-position. Hereâs the first demo from earlier, which includes the four directions.
See the Pen
A reveal hover effect with one element by Temani Afif (@t_afif)
on CodePen.
Hereâs the CSS weâre using:
img {
--s: 200px; /* the image size */
width: var(--s);
height: var(--s);
box-sizing: border-box;
object-fit: cover;
cursor: pointer;
transition: .5s;
}
img.left {
object-position: right;
padding-left: var(--s);
background: #542437;
}
img.right {
object-position: left;
padding-right: var(--s);
background: #8A9B0F;
}
img.top {
object-position: bottom;
padding-top: var(--s);
background: #E94E77;
}
img.bottom {
object-position: top;
padding-bottom: var(--s);
background: #7A6A53;
}
img:hover {
padding: 0;
}
More Reveal Animations
We can extend the trick to create more variations using the same idea. Instead of adding/removing the padding from one side, we can do it for two sides or even all sides.
See the Pen
A reveal hover effect with one element II by Temani Afif (@t_afif)
on CodePen.
If we inspect the code of the demo above, we wonât find a big difference from the previous one. All that weâre doing is setting different padding configurations to create more variation for the same effect.
Thereâs one trick in the first and last example where weâre using object-fit: none instead of object-fit: cover. In those cases, the padding will reduce the width and the height of the content area to 0, while in all the others cases, we either reduce the height or width. In such configurations, cover wonât work, but none can do the job.
MDN states:
The replaced content is not resized.
Why arenât we just using none in all cases? We can use it, and it works, but it has a small drawback. none will consider the intrinsic dimension of the image, so weâre obliged to have the CSS width and height equal to the intrinsic dimension for the trick to work. cover, on the other hand, keeps only the ratio of the image and will resize it to fit the area, so we can safely define any CSS size for the images.
Hereâs a comparison so we can see the difference.
See the Pen
Untitled by Temani Afif (@t_afif)
on CodePen.
In both cases, we have the reveal animation, but when using object-fit: none, the image isnât resized and is keeping its default size (500x500), which isnât good. object-fit: cover is only keeping the ratio and will resize the image to fit the box dimension.
Conclusion
I hope you enjoyed this little CSS experiment. Using simple tricks and a few lines of code, we achieved a cool reveal animation with only the <img> element. We also did many variations using the same code structure.
We can do even more with this trick. Iâll leave you with a last example where I transform black and white images into colored ones on hover.
See the Pen
Color your image with a sliding hover effect by Temani Afif (@t_afif)
on CodePen.
Iâll let you continue the exploration and try to find more fancy animations!

