I am trying to get the same effect as when using background-size: cover
in CSS, but by using SVG filters - feImage
in particular.
div {
width: 10em;
aspect-ratio: 1;
background: gold
}
.svg { filter: url(#f) }
.css {
background: url(https://images.unsplash.com/photo-1705339613128-28b8d900fb52?w=600) 50%/ cover
}
svg[height='0'] { position: fixed }
<svg width='0' height='0'>
<filter id='f' x='0' y='0' width='100%' height='100%' primitiveUnits='objectBoundingBox'>
<feImage xlink:href='https://images.unsplash.com/photo-1705339613128-28b8d900fb52?w=400'
preserveAspectRatio='xMidyMid meet'/>
</filter>
</svg>
<em>Result using SVG filter</em>
<div class='svg'></div>
<em>Desired result should look like</em>
<div class='css'></div>
According to MDN, preserveAspectRatio='xMidyMid meet'
should be the default, so I shouldn't even need to add it, but not even adding it seems to work.
I also shouldn't even need to set the width
and height
, as they should default to the filter area - also according to MDN.
What am I missing here? How can I make that feImage
cover the entire div/ filter area without distortion (preserveAspectRatio='none'
achieves the cover part, but introduces distortion).
You want xMidYMid and slice. Firefox will log an error in the Javascript console to tell you that xMidyMid is not valid. SVG is case sensitive and you want to slice off the sides of the image and use the height to fill it rather than the width.
div {
width: 10em;
aspect-ratio: 1;
background: gold
}
.svg { filter: url(#f) }
.css {
background: url(https://images.unsplash.com/photo-1705339613128-28b8d900fb52?w=600) 50%/ cover
}
svg[height='0'] { position: fixed }
<svg width='0' height='0'>
<filter id='f' x='0' y='0' width='100%' height='100%' primitiveUnits='objectBoundingBox'>
<feImage xlink:href='https://images.unsplash.com/photo-1705339613128-28b8d900fb52?w=400'
preserveAspectRatio='xMidYMid slice'/>
</filter>
</svg>
<em>Result using SVG filter</em>
<div class='svg'></div>
<em>Desired result should look like</em>
<div class='css'></div>