SVG 'use' tag in Chrome broken

2019-04-06 03:39发布

There is SAP (AngularJS and Angular Route) with icon-based navigation made by svg-sprite. So, I hava inline code like this:

<div style="height: 0; width: 0; position: absolute; visibility: hidden">
<svg xmlns="http://www.w3.org/2000/svg">
    <symbol id="icon-grid-32" viewBox="0 0 32 32">
        <g stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" stroke-linejoin="round">
            <path d="M2 2h11v11H2zM19 2h11v11H19zM2 19h11v11H2zM19 19h11v11H19z"/>
        </g>
    </symbol>
</svg>
</div>

And the icons in navigation like this:

<a href=""><svg class="icon icon-32 outline black"><use xlink:href="#icon-grid-32"></use></svg></a>

All that I can see in this navigation is nothing, <use> has size 0 × 0 pixels. I know about Firefox bug with xml:base, but adding xml:base didn't help me. You can try this example: http://css.yoksel.ru/assets/demo/svg-in-firefox/svg-has-base.html

It works in Firefox, Safari and other browsers but not in Chrome 49+ (48 version doesn't have this problem).

2条回答
兄弟一词,经得起流年.
2楼-- · 2019-04-06 03:57

This is caused by a combination of AngularJS' dependency of <base href="/" /> and UI routing, when the application is not at its "root" state, the relative hash link in the <use> element would not correctly resolve.

To get around this, you would need to resolve the xlink:href to use absolute path. You may do the following:

angular-icon-template.html

<svg class="c-icon" viewBox="0 0 32 32">
    <use xlink:href="" ng-attr-xlink:href="{{baseUrl + '#' + iconName}}" />
</svg>

angular-icon.js

angular.module('angularIcon', [])
    .directive('angularIcon', {
        templateUrl: 'angular-icon-template.html',
        scope: { iconName: '@' },
        controller: function($scope) {
            $scope.baseUrl = window.location.href.replace(window.location.hash, '');
        }
    });
查看更多
Rolldiameter
3楼-- · 2019-04-06 04:05

I was experiencing really similar issue to what you describe with a difference that I would generate my icons <svg> and <use> in a directive.

I have been looking for an answer for a better part of today and came up with a workaround to the <use> and xlink:href question. Which simply recreates the functionality by inlining the wanted svg.

For the sake of simplicity let's say i have <angular-icon> directive that receives the name of the icon by an attribute icon-name

<angular-icon icon-name="{{someObject.iconName}}">

working directive now looks as follows:

angular.module('angularIcon', [])
.directive('angularIcon', IconDirective);

function IconDirective(){
    return{
        template:'',
        templateNamespace:'svg',

        link:function(scope, element, attributes){

            // my icon name comes from $http call so it doesnt exist when initialising the directive, 
            attributes.$observe( 'iconName', function(iconName){

                // let's grab the icon from the sprite
                var icon = angular.element( document.getElementById( iconName ) ); 
                // let's clone it so we can modify it if we want
                var iconClone = icon.clone();

                var namespace = "http://www.w3.org/2000/svg";

                // manually create the svg element and append the inlined icon as no other way worked
                var svg = document.createElementNS( namespace, 'svg' );
                svg.setAttribute( 'viewBox', '0 0 32 32' );
                svg.setAttribute( 'xml:space', 'preserve' );

                svg.appendChild( iconClone[0] );
                // let's add the newly created svg+icon to the directive's element
                element[0].appendChild( svg );

            });

        },
        scope:{
            iconName: '@'
        }
    }
}
查看更多
登录 后发表回答