Scalable SVG Masks (Clipping Paths) for Video Elements in HTML/CSS – Even in Safari
Adding a clipping path to a video element in HTML/CSS can be a challenging task,
especially when dealing with browser inconsistencies. Safari, for example,
doesn’t fully support clip-path
applied directly to video elements.
Why does this matter? In modern web design, custom clipping paths allow you to create unique, dynamic visuals that elevate user experience. However, achieving this with video elements often requires creative workarounds due to limited browser support.
After some trial and error, I discovered a robust solution that leverages SVG
clipping paths with clipPathUnits="objectBoundingBox"
. This approach ensures
that the clipping path scales properly with the video’s dimensions. The critical
piece of this solution is the transform applied to the <path>
, which ensures
the clipping path works as intended.
Here’s the code example:
function Diamond({
className,
style
}: {
className?: string;
style?: CSSProperties;
}) {
return (
<div
className={classNames(
'tw-relative tw-aspect-[220/191] tw-flex tw-justify-center tw-items-center',
className
)}
style={style}
>
<svg width="0" height="0" className="tw-absolute tw-pointer-events-none">
<defs>
<clipPath id="diamondShape" clipPathUnits="objectBoundingBox">
<path
d="M47.373 10.77A21.889 21.889 0 0164.185 2.9h91.63a21.887 21.887 0 0116.812 7.87l39.599 47.493c6.991 8.384 6.727 20.636-.619 28.712l-85.414 93.906c-8.683 9.546-23.703 9.546-32.386 0L8.393 86.975C1.047 78.9.783 66.647 7.774 58.263l39.599-47.494z"
transform={`scale(${1 / 220}, ${1 / 191})`}
/>
</clipPath>
</defs>
</svg>
<object
className="tw-block tw-w-full tw-h-full tw-media-adjust-cover"
style={{ clipPath: 'url(#diamondShape)' }}
>
<video src="videos/2608621.webm" autoPlay loop muted playsInline />
</object>
</div>
);
}
Key Details of the Solution:
SVG with clipPathUnits
:
The clipping path is defined in an SVG using the objectBoundingBox units, which are normalized to the bounding box of the element (values from 0 to 1). This allows the path to scale proportionally with the target element's dimensions.
Critical Use of transform
:
Without the transform attribute in the <path>
, the clipping path will not work
correctly. The scale(${1 / width}, ${1 / height})
transformation adjusts the
normalized values to match the aspect ratio of the clipping path (220×191 in
this example).
Why it’s crucial: The transform
bridges the gap between the SVG's native
coordinate system and the objectBoundingBox
scaling. By default, the
coordinate system assumes a square (1×1) bounding box, which would distort the
path for non-square elements. The scale operation rescales the clipping path to
match the actual aspect ratio of the element, ensuring accurate rendering.
Debugging Tip: If the path doesn’t align with your element, verify the
aspect ratio and adjust the scaling values accordingly. For example, if your
element’s dimensions are 300×150, the transform should use
scale(${1 / 300}, ${1 / 150})
which calculates to scale(0.00333, 0.00667)
.
Video
in an Object
Element:
Instead of applying clip-path
directly to the <video>
(which is poorly
supported in some browsers, including Safari), the video is wrapped in an
<object>
. The clipPath
is then applied to the <object>
, ensuring
consistent rendering.
Dynamic Scaling with Aspect Ratio:
The tw-aspect-[220/191]
utility maintains the proper aspect ratio of the
clipping mask while allowing the video to scale fluidly within its container.
Why This Solution Works
Cross-browser compatibility: Safari-friendly by wrapping the video in an
<object>
.
Precision and scalability: Properly scaled clipping paths with the critical transform.
Flexibility: The clipping path adjusts dynamically with the video size while maintaining its proportions.
If you’ve faced issues applying clipping paths to videos in HTML/CSS, this method is worth a try. For a live example and to experiment with the implementation, check out my CodePen playground. It demonstrates the full setup and lets you see the results in action.