airbnb/lottie-web

SVG url() doesn't work under <base href="/"> in Safari and Firefox

omer-r opened this issue Β· 13 comments

Maybe someone here encountered the same issue?
I'm using angular 1.5.8, bodymovin 4.6.4, safari 9.1.2 / firefox 51
Both browsers won't display the generated SVG, I've attached my JSON (as txt though, github requires...)

loadAnimation config:

  name: 'bell',
  renderer: 'svg',
  loop: false,
  autoplay: false,
  path: 'http://my.cdn.com/animations/_bell.svg'

I see the <svg> on the dom in devtools but nothing is displayed (supposed to be a white bell)

_bell.txt

if I copy the generated SVG and manually modify the url(....) to the relative path url(/settings...) I can see the SVG displayed:

<svg xmlns="http://www.w3.org/2000/svg" width="443" height="367" viewBox="0 0 443 367" preserveAspectRatio="xMidYMid meet" style="width: 100%; height: 100%;">
    <defs>
        <clipPath id="animationMask_To8CnUAGFw">
            <rect width="443" height="367" x="0" y="0">

            </rect>
        </clipPath>
        <filter id="c6bro9ROY3" filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%">
            <feColorMatrix type="matrix" color-interpolation-filters="sRGB" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0">

            </feColorMatrix>
        </filter>
        <clipPath id="Agitek6DYi">
            <path fill="#ffffff" clip-rule="nonzero" d=" M318.087,264.087 C309.21299999999997,251.459 303.411,235.75900000000001 303.411,220.401 C303.411,220.401 303.411,172.619 303.411,172.619 C303.411,130.65 271.876,96.176 231.019,91.367 C235.446,87.678 238.565,84.012 238.565,77.056 C238.565,67.5 231.056,59.991 221.5,59.991 C211.944,59.991 204.435,67.5 204.435,77.056 C204.435,82.858 207.50699999999998,87.977 211.944,91.049 C211.944,91.049 211.964,91.121 211.971,91.152 C171.333,95.889 139.589,130.527 139.589,172.619 C139.589,172.619 139.589,220.401 139.589,220.401 C139.589,235.75900000000001 133.884,251.528 124.913,264.087 C121.5,268.865 124.913,275.009 130.374,275.009 C130.374,275.009 312.626,275.009 312.626,275.009 C318.087,275.009 321.46299999999997,268.89099999999996 318.087,264.087" fill-opacity="1"></path>
        </clipPath>
        <clipPath id="cp_f1Eeio5T">
            <path d="M0,0 L700,0 L700,875 L0,875z"></path>
        </clipPath>
        <filter id="3SOAm43Yd1" filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%">
            <feColorMatrix type="matrix" color-interpolation-filters="sRGB" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"></feColorMatrix>
        </filter>
        <filter id="nk8JqHmqMY" filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%">
            <feColorMatrix type="matrix" color-interpolation-filters="sRGB" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 -1 1"></feColorMatrix>
        </filter>
        <mask id="ly_EkGBvkuHlM" mask-type="alpha">
            <g filter="url(/settings#nk8JqHmqMY)">
                <rect width="700" height="875" x="0" y="0" fill="#ffffff" opacity="0"></rect>
                <g transform="matrix(3.8199974808151644,1.5433791648735575,-0.6293390769387321,1.5576688756722028,208.23653990308918,469.92279898635593)" opacity="1">
                    <rect width="50" height="50" fill="#ffffff"></rect>
                </g>
            </g>
        </mask>
    </defs>
    <g clip-path="url(/settings#animationMask_To8CnUAGFw)">
        <g clip-path="url(/settings#cp_f1Eeio5T)" filter="url(/settings#3SOAm43Yd1)" transform="matrix(0.9271912720376241,-0.3746095902686593,0.3746095902686593,0.9271912720376241,-250.61336095570687,-157.19882492242974)" opacity="1">
            <g mask="url(/settings#ly_EkGBvkuHlM)">
                <g transform="matrix(1.0286641274491224,0.4156072850652836,-0.424328126560006,1.0502489675834372,339.9754891056624,417.13996791374655)" opacity="1" style="-webkit-user-select: none;">
                    <g opacity="1" transform="matrix(1,0,0,1,-1,155.5)">
                        <path fill="rgb(0,0,0)" fill-opacity="1" d="M0 0 M0,-29.824 C16.4598656,-29.824 29.824,-16.4598656 29.824,0 C29.824,16.4598656 16.4598656,29.824 0,29.824 C-16.4598656,29.824 -29.824,16.4598656 -29.824,0 C-29.824,-16.4598656 -16.4598656,-29.824 0,-29.824z">

                        </path>
                    </g>
                </g>
            </g>
        </g>
        <g filter="url(/settings#c6bro9ROY3)" clip-path="url(/settings#Agitek6DYi)" transform="matrix(1.000008,0,0,1.000008,-0.0017720000000167602,-0.0025080000000201608)" opacity="1">
            <rect width="443" height="367" fill="#000000"></rect>
        </g>
        <g></g>
    </g>
</svg>

yes, it's a known issue using the base tag and svg's referencing ids.
Not sure how to fix it yet, need to look into it.
What are you using the base tag for?

p3pp8 commented

Hello, i'd like to have this issue fixed as well. I work with Meteor and i need to use the base tag to reference all my public resources. Unfortunally i don't have any solution to remove it. Is there any workaround to fix this issue with safari browser? Thanx! Bodymovin is a great engine!!!

I haven't found a reliable solution for this that works an all scenarios.
Any suggestions are welcome.

eelke commented

@bodymovin I bumped into this issue today as well, and it was really hard to figure out what was happening. This related answer on StackOverflow suggests that the solution of this problem lies in using a better url() format, which includes the location of the current page.

So to tackle this I think you could try adding an optional setting (something like prependUrl: 'this_page_name.html' or whatever the containing path would be), which should be dynamically inserted inside all occurrences of the url().

This might turn

<line … filter="url(#filtername)" />

into

<line … filter="url(basepath+this_page_name.html#filtername)" />

@p3pp8 You could for now try to do this manually. Wait for the DOMLoaded event, then run through all the nodes with an attribute value containing url( and prepend your window.location.href. That might possibly do the trick.

@eelke, @adamchenwei is working on a PR to fix this.
It will soon be ready to merge.

This is expected behaviour (<base href="/"> causing behaviour changes in URL), see the SVG minutes here: https://www.w3.org/2015/08/25-svg-minutes.html#item08

Rezi commented

Hi, unfortunately referencing the svg from external file make it fail in IE.. Fixing the bug in FF and introducing new one in IE11 is not nice solution...

@Rezi Hi, can you post a link to the issue or a json file?

Hello, i am facing a series issue in safari browser. The lottie json file rendering as svg, is affected by url element when redirecting from the external link to this website. The below issue is redirecting from blog website to main website. It is an angular project.
WhatsApp Image 2020-06-10 at 11 36 53 AM (2)

p3pp8 commented

Safari is a plague...

@p3pp8 Safari is the new IE

About four and a half years ago, the CSS Working Group added an exception "4.5.1.1 Fragment URLs" to the CSS Values and Units specification (w3c/csswg-drafts@acf3ab1). The tl;dr version of the change is basically: when url() value starts with a # character, <base> and pushState() get ignored; only the current document is considered.

The Chromium team quickly prepared a patch to comply with the change. The patch landed on Chrome 54 released on 2016-10-12. The Firefox team followed nextβ€”the patch landed on Firefox 52 released on 2017-03-07.

Note that the original issue mentioned that they encountered the bug on Firefox 51, and the Stack Overflow question was posted on 2013-08-15.

In 2019-09-02, the WebKit team introduced a patch to trunk. While it quickly landed on Safari Technology Preview 92 on 2019-09-18, it took some time for Safari to catch upβ€”Safari 13.1 released on 2020-04-03, in fact.


So the bottom line is, simply don't use setLocationHref()1 if you don't target the browser versions below the aforementioned ones. If not, you might need to selectively use the setLocationHref() workaround2 as mentioned all over the internet.

Note that for SPAs (e.g., React, Angular), this url might need to be changed every time a routing (i.e., history.pushState()) happens. If not, depending on the browser implementation, the SVG might get lostβ€”at this point the <svg> moved on to the new location, and the old location doesn't exist anymore.


1 Keeping the fragment url url(#filtername) as-is.
2 Changing to the absolute url url(https://example.com/page#filtername).

cc/ @bodymovin