When Square Pixels Aren’t Square: Why Video Aspect Ratios Can Trip Your Layouts
Share this article
When Square Pixels Aren’t Square
In web development, the most common way to reserve space for a video is to declare its aspect ratio in CSS or HTML:
<video style="aspect-ratio: 1920 / 1080"></video>
The browser can then lay out the page before the media loads, preventing cumulative layout shift. But what happens when the video file’s dimensions don’t match that ratio? A handful of videos with non‑square pixels will either appear letterboxed or force the page to reflow once the file is decoded.
The Two Resolutions You’ll See
QuickTime’s Movie Inspector shows two sets of numbers:
Resolution: 1920 × 1080 (1350 × 1080)
The first is the storage aspect ratio (SAR) – the raw pixel width and height of each frame. The second is the display aspect ratio (DAR) – how the video will appear when the player applies the pixel aspect ratio (PAR). DAR = SAR × PAR.
The pixel aspect ratio tells a player how to stretch or squash the stored pixels when displaying them. It can make square pixels appear rectangular.
This distinction is often overlooked because most modern content uses square pixels. Yet, non‑square pixels still surface in legacy SD broadcasts and in certain vertical‑video formats like YouTube Shorts.
Why It Matters for Web Layouts
If you reserve space based on SAR, the browser will allocate a box that matches the raw pixel dimensions. When the video loads, the player stretches or squashes the image to match DAR, causing the content to shift – the dreaded layout jump.
“I was telling the browser the wrong aspect ratio, and the browser had to update the page when it loaded the video file.”
By using DAR instead, you preallocate exactly the space the final image will occupy, eliminating letterboxing and layout shifts.
Extracting the Correct Dimensions
The author’s original Python helper used pymediainfo to fetch width and height, which only returns SAR. The fix is to call ffprobe and read the sample_aspect_ratio field:
import json
import subprocess
from fractions import Fraction
from pathlib import Path
def get_display_aspect_ratio(video_path: Path) -> tuple[int, int]:
cmd = [
"ffprobe",
"-v", "error",
"-select_streams", "v:0",
"-show_entries", "stream=width,height,sample_aspect_ratio",
"-print_format", "json",
str(video_path),
]
output = subprocess.check_output(cmd)
resp = json.loads(output)
stream = resp["streams"][0]
try:
par = Fraction(stream["sample_aspect_ratio"].replace(":", "/"))
except KeyError:
par = 1
width = round(stream["width"] * par)
height = stream["height"]
return width, height
The Fraction module preserves the exact ratio, avoiding floating‑point drift that can lead to a pixel‑off error.
Visualizing the Difference
A side‑by‑side comparison of a frame from Mars EDL 2020 Remastered illustrates the distortion caused by ignoring PAR:
The left image shows the raw frame (1920 × 1080) with a visibly stretched parachute. The right image applies the 45:64 PAR, restoring the intended circle.
Takeaway for Developers
- Always use the display aspect ratio when reserving space for videos.
- Non‑square pixels are rare but still present, especially in legacy or vertical formats.
- ffprobe is a reliable way to extract SAR, DAR, and PAR without relying on higher‑level libraries that may round values.
By integrating these practices, you can eliminate layout jumps and ensure your video content looks as intended from the first paint.
Source: Alex W. Lchan, “When square pixels aren’t square”, 5 December 2025 – https://alexwlchan.net/2025/square-pixels/