Content
Preventing UI Shifting on the Web
One of the things that I hate the most on the web is UI Shifting - that awful movement when the content unexpectedly jumps, often due to images loading late, or dynamic content injected into the layout. It disrupts flow, affects perceived performance, and can even cause users to click the wrong thing.
While this happens mostly to web apps written on complex Javascript UI frameworks, this can also happen on a simple html & css only website (if those even exists at this point).
In this post, we’ll explore what causes layout shifts, how to prevent them with vanilla CSS and Tailwind CSS, and tips to improve your interface stability.
What Causes UI Shifting?
Common causes behind layout shifts include:
- Images without dimensions: Browsers don’t know how much space to reserve before they load.
- Web fonts: Swapping fonts can cause text size to change.
- Async content injection: DOM updates or lazy-loaded elements without reserved space.
- Third-party widgets/ads: External scripts inserting elements late in the render cycle.
How to Prevent UI Shifting (CSS Tips)
1. Reserve Space for Images
Specify “width” and “height” for images so browsers can allocate the correct space.
img {
width: 100%;
height: auto;
aspect-ratio: 16 / 9; /* fallback if no explicit height */
}
Or use fixed dimensions when appropriate:
<img src="hero.webp" width="1200" height="600" alt="Hero image">
2. Use Aspect Ratio Boxes
When dimensions are dynamic, use aspect ratio containers:
.aspect-box {
aspect-ratio: 16 / 9;
}
3. Font Loading Optimization
Prevent “flash of unstyled text” (FOUT) or layout shifts by:
-
Using font-display: swap in your @font-face rule.
-
Preloading fonts with:
<link rel="preload" href="/fonts/custom.woff2" as="font" type="font/woff2" crossorigin>
Prevent UI Shifting with Tailwind CSS
I love Tailwind , most of the stuff that I make uses Tailwind . Hell, this site is writen with tailwind . Tailwind is life. So let’s see how we can apply all of that stuff with tailwind … Tailwind .
1. Use Fixed Sizes or Aspect Ratios
<!-- Fixed image container -->
<div class="w-full h-64 bg-gray-200">
<img src="/image.jpg" class="w-full h-full object-cover" alt="Example">
</div>
2. Skeleton Loaders or Placeholder Elements
Use placeholders to avoid abrupt content jumps:
<div class="w-full h-32 bg-gray-100 animate-pulse rounded"></div>
In the case of this site, I’m using skeleton, placeholder elements, and as well as fixed size style on the containers of the Imgs:
<!-- This is an Astro file btw-->
<div
class={`object-contain md:object-cover overflow-hidden w-auto ${props.footer ? "md:rounded-t-xl" : "md:rounded-xl"}`}>
<img
class="aspect-auto md:rounded-t-xl"
src={props.img_url}
alt={props.alt}
/>
<div
class="absolute flex justify-center items-center w-full h-full top-0 left-0 -z-10 animate-pulse bg-dark/50 rounded-xl"
>
<i class="far fa-spinner text-light font-bold text-3xl animate-spin"></i>
</div>
</div>
This reserves the space for a spinner icon, and indicates loading content.
If you inspect element, you’ll see a spinner behind every post img, do what whatever you want with that forbidden knowledge.
Conclusion
Stable layouts make for smooth, delightful user experiences. Don’t be lazy, prevent UI Shifting!