Skip to content

Commit 3fd0046

Browse files
committed
Revert to svg on mobile
1 parent 57748e9 commit 3fd0046

1 file changed

Lines changed: 44 additions & 22 deletions

File tree

src/components/AdaptiveSvg.tsx

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useSyncExternalStore } from "react";
1+
import { useCallback, useState, useSyncExternalStore } from "react";
22

33
const MD_BREAKPOINT = 768;
44

@@ -33,36 +33,58 @@ interface AdaptiveSvgProps {
3333
src: string;
3434
alt?: string;
3535
className?: string;
36+
/** Use <img> instead of <object> on mobile (may cause shadow artifacts). */
37+
mobileImg?: boolean;
3638
}
3739

38-
export function AdaptiveSvg({ src, alt, className }: AdaptiveSvgProps) {
40+
export function AdaptiveSvg({
41+
src,
42+
alt,
43+
className,
44+
mobileImg = false,
45+
}: AdaptiveSvgProps) {
3946
const isDesktop = useIsDesktop();
4047
const url = resolveUrl(src);
48+
const useObject = isDesktop || !mobileImg;
49+
const [aspectRatio, setAspectRatio] = useState<string>();
50+
51+
const handleLoad = useCallback(
52+
(e: React.SyntheticEvent<HTMLObjectElement>) => {
53+
try {
54+
const svg = e.currentTarget.contentDocument?.documentElement;
55+
if (!svg) return;
56+
const vb = svg.getAttribute("viewBox");
57+
if (!vb) return;
58+
const parts = vb
59+
.trim()
60+
.split(/[\s,]+/)
61+
.map(Number);
62+
if (parts.length === 4 && parts[2] > 0 && parts[3] > 0) {
63+
setAspectRatio(`${parts[2]} / ${parts[3]}`);
64+
}
65+
} catch {
66+
// cross-origin — ignore
67+
}
68+
},
69+
[],
70+
);
4171

4272
return (
4373
<div
4474
className={`dark:hue-rotate-180 dark:invert${className ? ` ${className}` : ""}`}
4575
>
46-
{isDesktop ? (
47-
<div className="relative w-full">
48-
{/* Hidden <img> provides correct intrinsic sizing from the SVG viewBox,
49-
since <object> can't derive its own height from SVG content. */}
50-
<img
51-
src={url}
52-
alt=""
53-
aria-hidden="true"
54-
className="invisible block h-auto w-full"
55-
/>
56-
<object
57-
data={url}
58-
type="image/svg+xml"
59-
aria-label={alt || src}
60-
role="img"
61-
className="absolute inset-0 block h-full w-full"
62-
>
63-
{alt || src}
64-
</object>
65-
</div>
76+
{useObject ? (
77+
<object
78+
data={url}
79+
type="image/svg+xml"
80+
aria-label={alt || src}
81+
role="img"
82+
className="block h-auto w-full"
83+
style={aspectRatio ? { aspectRatio } : undefined}
84+
onLoad={handleLoad}
85+
>
86+
{alt || src}
87+
</object>
6688
) : (
6789
<img src={url} alt={alt || ""} className="block h-full w-full" />
6890
)}

0 commit comments

Comments
 (0)