Safari is not better than IE for a web developer. Here is the issue I saw in Safari.
I am trying to use an SVG sprite to load product icon in my web page.
HTML code:
<img src="https://www.abc123.com/icon_sprite.svg#amex">
SVG Sprite Code:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="276" height="224" viewBox="0 0 276 224" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<view id="affiliate-programs" viewBox="148 0 32 32"/>
<svg width="32" height="32" viewBox="0 0 32 32" x="148"><path .../></svg>
<view id="alipay" viewBox="0 64 49 32"/>
<svg width="49" height="32" viewBox="0 0 49 32" y="64"><path .../></svg>
<view id="amex" viewBox="50 0 49 32"/>
<svg width="49" height="32" viewBox="0 0 49 32" x="50"><path .../></svg>
<view id="auction" viewBox="148 64 32 32"/>
<svg width="32" height="32" viewBox="0 0 32 32" x="148" y="64"><path .../></svg>
<view id="backorder-domain-service" viewBox="180 128 32 32"/>
<svg width="32" height="32" viewBox="0 0 32 32" x="180" y="128"><path .../></svg>
...
...
</svg>
The <img> in HTML locate the <svg> by appending "#" + id of <view> in the sprite url. This way works in Chrome, Firefox, and even IE, but not in Safari.
How it looks like in Chrome:
And how it looks like in Safari 5 and Safari 9:
So it basically means the appended #viewId in <img> can't recognize the view by ID, which is unacceptable.
I am wondering if anyone has seen similar cases and could help me out.
By the way, I also tried another solution.
<object data="https://www.abc123.com/icon_sprite.svg#amex" type="image/svg+xml"></object>
This solution display the correct svg of the sprite, however it will first disappear and then re-appear during AJAX calls, which is not good user experience either.
I answered most of my own questions here by myself. I don't know it is a happy thing or upsetting thing.
I figured out how to fix this issue in the next day after I posted it here.
According to https://www.broken-links.com/2012/08/14/better-svg-sprites-with-fragment-identifiers/, Safari only supports the fragment identifier like xxx.svg#<viewboxId> in Version 7, but not other versions, which I've confirmed in Sauce Labs. It is an even worse browser than IE.
Well, no more complaint. Let's talk about the solution, which is the most important thing.
It is true the fragment identifier xxx.svg#<viewboxId> does not work in most of Safaris. It happens in <img>, but not in <embed>. So for Safari, we can use <embed> to load fragment identifier.
How to differentiate browser:
function isSafari() {
if (navigator && navigator.userAgent) {
var userAgent = navigator.userAgent;
var isChrome = userAgent.indexOf('Chrome') > -1;
var isSafari = userAgent.indexOf('Safari') > -1;
if ((isChrome) && (isSafari)) {
isSafari = false;
}
return isSafari;
}
return false;
}
In Safari:
<embed id="embedSvg" class="pi_svg" src="https://www.abc123.com/icon_sprite.svg#amex" type="image/svg+xml"></embed>
In non-Safari:
<img class="pi_svg" src="https://www.abc123.com/icon_sprite.svg#amex">
Related
We are trying to create an icon font for our custom multi-color icons. Icomoon worked like a charm for our UI icons (mono-color) but with multi-color icons, multiple lines are required to use an icon (look at the example below). Is there any way to achieve a similar behavior as the mono-colors but for multi-color SVG icons?
ex
mono-color icon:
<span class="icon-name">
multi-color icon:
<span class="icon-name">
<span class="path1">
<span class="path2">
<span class="path3">
<span class="path4">
<span class="path5">
<span class="path6">
<span class="path7">
<span class="path8">
</span>
If I understand that correctly, you are struggling with colouring svgs.
The svg code can contain a fill element (https://www.w3schools.com/graphics/tryit.asp?filename=trysvg_circle for reference).
Moreover, you could try to change the color by using CSS (color property).
If you need to use an icon font (instead of inlined svgs) you can't circumvent placing multiple glyphs/elements for each color.
To some extend you might achieve a multicolored text display with Opentype SVG fonts.
Unfortunately browser support is quite limited:
Photoshop, version CC 2017 and above
Illustrator
Firefox, version 32 and above
Microsoft Edge, Windows 10 Anniversary Edition and above
In Windows 10, the DirectWrite and Direct2D platform components allow OpenType-SVG support in any apps that use those APIs
Besides converting svgs to such a font file will require more sophisticated font editors or at least more experience in font file generating/editing.
So using icon svgs directly is certainly more straightforward.
You can achieve a quite font-like behaviour e.g by:
combining multiple icons in a single svg using <defs> or <symbol>
using keyword based fill properties like "currentColor" to color icons via text color
using css-variables to define reusable color themes
Example: inlined svg icons
let iconInserts = document.querySelectorAll(".icon-insert");
let iconDefs = document.querySelector(".iconDefs");
if (iconInserts.length) {
iconInserts.forEach(function (iconSpan) {
let iconName = iconSpan.getAttribute("data-icon");
let symbolHref = "#" + iconName;
let iconDef = iconDefs.querySelector(symbolHref);
let viewBox = iconDef.getAttribute("viewBox");
// insert
let iconSVG = document.createElementNS("http://www.w3.org/2000/svg", "svg");
iconSVG.classList.add("svg-inline");
iconSVG.setAttribute("viewBox", viewBox);
let iconUse = document.createElementNS("http://www.w3.org/2000/svg", "use");
iconSVG.appendChild(iconUse);
iconSpan.appendChild(iconSVG);
iconUse.setAttribute("href", symbolHref);
iconUse.classList.add(iconName);
});
}
body{
font-size:15vmin;
}
.svg-inline{
display:inline-block;
height:1em;
transform:translateY(20%);
}
.theme1{
--col1:green;
--col2:pink;
--col3:purple;
--col4:orange;
--col5:lime;
--col6:cyan;
--col7:#444;
}
.theme2{
--col1:green;
--col2:green;
--col3:green;
--col4:orange;
--col5:orange;
--col6:orange;
--col7:green;
}
.icon-news{
--col1:green;
--col2:pink;
--col3:purple;
--col4:orange;
--col5:lime;
--col6:cyan;
--col7:#444;
}
<p>
<svg class="svg-inline theme1" viewBox="0 0 1000 1000">
<use href="#icon-news" />
</svg>
Sample icon (colored by css vars)
<svg class="svg-inline theme2" viewBox="0 0 1000 1000">
<use href="#icon-news" />
</svg>
Sample icon 2 (colored by css vars)
<svg class="svg-inline" viewBox="0 0 1000 1000" style="color:orange">
<use href="#icon-news2" />
</svg>
Sample icon 3 (colored by currentColor)
<span class="icon-insert" data-icon="icon-news"></span>
Sample icon 4 (injected by js)
</p>
<!-- icon library in hidden svg file -->
<svg class="iconDefs" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000" style="display:none">
<symbol id="icon-news" viewBox="0 0 1000 1000">
<path fill="var(--col1)" id="p6" d="M251 658h313v62H251z" />
<path fill="var(--col2)" id="p5" d="M626 658h252v62H626z" />
<path fill="var(--col3)" id="p4" d="M626 531h252v63H626z" />
<path fill="var(--col4)" id="p3" d="M626 406h252v63H626z" />
<path fill="var(--col5)" id="p2" d="M626 282h252v62H626z" />
<path fill="var(--col6)" id="p1" d="M501 344v187H314V344h187zm63-62H251v312h313V282z" />
<path fill="var(--col7)" id="bg" d="M1003 155H125v64H-1v533c0 52 43 94 94 94h817c51 0 93-42 93-94V155zM125 752c0 17-14 31-32 31-17 0-31-14-31-31V282h63v470zm816 0c0 17-14 31-31 31H182c4-10 6-21 6-31V219h753v533z" />
</symbol>
<symbol id="icon-news2" viewBox="0 0 1000 1000">
<path fill="currentColor" id="p1" d="M501 344v187H314V344h187zm63-62H251v312h313V282z" />
<path fill="currentColor" id="bg" d="M1003 155H125v64H-1v533c0 52 43 94 94 94h817c51 0 93-42 93-94V155zM125 752c0 17-14 31-32 31-17 0-31-14-31-31V282h63v470zm816 0c0 17-14 31-31 31H182c4-10 6-21 6-31V219h753v533z" />
</symbol>
</svg>
You might also write a simple icon insertion script injecting placeholder span elements by svg instances (4. example)
<span class="icon-insert" data-icon="icon-news"></span>
could be replaced by something like this:
<span class="icon-insert" data-icon="icon-news">
<svg class="svg-inline" viewBox="0 0 1000 1000">
<use href="#icon-news" class="icon-news" />
</svg>
</span>
Some icon libraries also provide a similar js based injection approach (e.g feather icons)
See also: css-tricks: Inline SVG vs Icon Fonts [CAGEMATCH]
We have recently switched to SVG for our decorative images and logos. We do this in the form of a single SVG file containing multiple SVG sections for each image. We hide all SVG sections and only display the target SVG.
Here is a shortened example of our SVG file:
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<style>
.img { display: none }
.img:target { display: inline }
.socialicon {fill:white}
.btt {fill:#919191}
</style>
</defs>
<svg viewBox="0 0 16 16">
<g id="icon-facebook" class="img socialicon">
<path d="M9.5 3h2.5v-3h-2.5c-1.93 0-3.5 1.57-3.5 3.5v1.5h-2v3h2v8h3v-8h2.5l0.5-3h-3v-1.5c0-0.271 0.229-0.5 0.5-0.5z"></path>
</g>
</svg>
<svg viewBox="0 0 16 16">
<g id="icon-google-plus" class="img socialicon">
<path d="M5.091 7.147v1.747h2.888c-0.116 0.75-0.872 2.197-2.888 2.197-1.737 0-3.156-1.441-3.156-3.216s1.419-3.216 3.156-3.216c0.991 0 1.65 0.422 2.028 0.784l1.381-1.331c-0.888-0.828-2.037-1.331-3.409-1.331-2.816 0.003-5.091 2.278-5.091 5.094s2.275 5.091 5.091 5.091c2.937 0 4.888-2.066 4.888-4.975 0-0.334-0.037-0.591-0.081-0.844h-4.806z"></path>
<path d="M16 7h-1.5v-1.5h-1.5v1.5h-1.5v1.5h1.5v1.5h1.5v-1.5h1.5z"></path>
</g>
</svg>
<svg viewBox="0 0 16 16">
<g id="icon-twitter" class="img socialicon">
<path d="M16 3.538c-0.588 0.263-1.222 0.438-1.884 0.516 0.678-0.406 1.197-1.050 1.444-1.816-0.634 0.375-1.338 0.65-2.084 0.797-0.6-0.638-1.453-1.034-2.397-1.034-1.813 0-3.281 1.469-3.281 3.281 0 0.256 0.028 0.506 0.084 0.747-2.728-0.138-5.147-1.444-6.766-3.431-0.281 0.484-0.444 1.050-0.444 1.65 0 1.138 0.578 2.144 1.459 2.731-0.538-0.016-1.044-0.166-1.488-0.409 0 0.013 0 0.028 0 0.041 0 1.591 1.131 2.919 2.634 3.219-0.275 0.075-0.566 0.116-0.866 0.116-0.212 0-0.416-0.022-0.619-0.059 0.419 1.303 1.631 2.253 3.066 2.281-1.125 0.881-2.538 1.406-4.078 1.406-0.266 0-0.525-0.016-0.784-0.047 1.456 0.934 3.181 1.475 5.034 1.475 6.037 0 9.341-5.003 9.341-9.341 0-0.144-0.003-0.284-0.009-0.425 0.641-0.459 1.197-1.038 1.637-1.697z"></path>
</g>
</svg>
</svg>
Here is an example of how we reference the SVG images:
<img
alt="Facebook"
id="facebookhome"
class="iconso"
src="/images/svg/svgsprite-1.6.svg#icon-facebook"
>
This works just great in Chrome, Firefox, Opera and Safari. Every new page load has an instant display of the images.
However, in IE11 and Edge, every time the page is loaded it's as if the SVG images are loaded last and it leaves the placeholder empty until everything else is loaded first (it seems). It's only a very short delay (0.5-1s) however not very nice for UX and slightly offputting.
Any ideas on what's causing this?
Any suggestions, tips, and advice are greatly appreciated.
We are also running HTTP2 so maybe SVG sprites won't perform any better anyway?
I have generated an svg spritesheet:
<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<symbol viewBox="0 0 17.5 14.663" id="img--svg--icon-twitter" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M11.283.153c1.736-.485 3.074.263 3.685 1.151.694-.226 1.372-.47 2.072-.691-.004.841-.538 1.478-.883 1.727.704.166 1.343-.48 1.343-.48-.175.976-1.035 1.746-1.611 1.977-.239 6.592-3.272 10.956-10.382 10.823h-.46c-.422 0-4.29-.45-5.047-1.843 2.341.192 4.011-.412 4.835-1.15-.989-.293-2.761-.464-3.07-2.881.362.105.583.223 1.228.117C1.757 8.067.385 7.366.461 5.218c.294.32 1.1.523 1.381.461C1.117 5.444-.188 2.398.921.843 2.794 2.654 4.769 4.364 8.29 4.528 8.506 2.288 9.461.787 11.283.153z"/></symbol>
</svg>
I have saved it as sprite.svg into img directory. Then I want to get svg element from sprite with use tag by ID :
<ul class="social__list">
<li class="social__item">
<a class="social__link social__link--twitter" href="#">
<svg class="social__link social__link--twitter_icon" width="16" height="16"><use xlink:href="img/sprite.svg#img--svg--icon-twitter"></use>
</svg>
</a></li>
<li class="social__item"><a class="social__link--facebook" href="#">Фейсбук</a></li>
<li class="social__item"><a class="social__link--youtube" href="#">Ютуб</a></li>
</ul>
The icon shows in firefox but doesn't shows in chrome at all. My chrome version is 61.0.3163.100. I have tried to turn off all chrome expansion and open page in private mode - it still doesn't shows. What can cause the problem ?
i generated a svg code for a map in illustrator to put in my website but i had this code which has a tag called <image> which i can not handle, can't give it css properties nor just put a foreground text on it, my objective is to have that image or the g or the link changes foreground color as i hover over it, but i can't find any thing about that tag, there is only articles about path or circle or line for svg tags but not <image>
here's my code :
<svg version="1.1" xmlns:x="&ns_extend;" xmlns:i="&ns_ai;" xmlns:graph="&ns_graphs;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1434 1454.3" enable-background="new 0 0 1434 1454.3" xml:space="preserve">
<switch>
<foreignObject requiredExtensions="&ns_ai;" x="0" y="0" width="1" height="1">
<i:pgfRef xlink:href="#adobe_illustrator_pgf">
</i:pgfRef>
</foreignObject>
<g i:extraneous="self">
<a xlink:href="../Reservation/Second Level/index.php">
<g id="Inezgane_Ait_Melloul.svg_xA0_Image_1_">
<image overflow="visible" width="37" height="19" id="Inezgane_Ait_Melloul.svg_xA0_Image" xlink:href="data:image/png;base64,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
CCJS2wAAAABJRU5ErkJggg==" transform="matrix(0.75 0 0 0.75 728.25 568.5)">
</image>
</g>
</a>
</g>
</switch>
it's not the full code because the full one is like thousand lines, the map has a lot of zones to cover.
but i'm kind of not familiar with svg at all, so maybe i'm doing something wrong in the concept of interactive map design
I have an automatically generated SVG spritemap (grunt-svg-sprite) which looks like this file:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="116" height="69" viewBox="0 0 116 69">
<svg width="116" height="25" viewBox="0 0 116 25" id="block1" y="0">
<path fill="#fff" stroke="#FF51D4" stroke-miterlimit="10" d="M0 0h116v25H0z"/>
<path fill="#D5FF54" stroke="#FF51D4" stroke-miterlimit="10" d="M0 0h116v25H0z"/>
</svg>
<svg width="20" height="20" viewBox="0 0 20 20" id="block2" y="25">
<path fill="#FF001A" d="M.5.5h19v19H.5z"/>
<path fill="#1D1D1B" d="M19 1v18H1V1h18m1-1H0v20h20V0z"/>
</svg>
<svg width="27" height="24" viewBox="0 0 27 24" id="block3" y="45">
<path d="M.5.5h26v23H.5z"/>
<path fill="#6BFF4E" d="M26 1v22H1V1h25m1-1H0v24h27V0z"/>
</svg>
</svg>
This SVG consists of three "images" which have the IDs "block1", "block2" and "block3".
I want to display only "block1" on my web page, so that the dimensions of this image should be scalable. I want to set the width to 10rem and the height should be automatically adjusted. I did it this way:
<img src="https://cdn.mediacru.sh/ahw4Jhv0r6GG.svg#block1" style="width:10rem;"/>
And here I created a JSFiddle. The problem is, that the web browser displays all three blocks instead of only "block1". How can I do this with an <img>? I have to support the latest versions of web browsers and only IE11, previous versions would be great, but is not a must.
(I can not use the object HTML tag, because I am limited in my IE11 support - I can not see the objects on this page, I see the images of "iframe", "img" and "CSS background" but "object": three times: "Active content removed").
The easiest way to solve your problem is to add some CSS directly to your SVG file:
<style><![CDATA[ svg svg { display: none; } svg svg:target { display: inline; }]]></style>
This simple CSS prevents all the blocks from display and shows only the one you're targeting to.
Here is your SVG file with added CSS and JSFiddle demo.
While you use Grunt you can automatize it using e.g. grunt-string-replace task (running it on SVG file after processing with grunt-svg-sprite). The task should look more or less like this:
'string-replace': {
dist: {
files: {
'./src/preprocessedSVG.svg': './build/sprite.svg'
},
options: {
replacements: [{
pattern: '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="116" height="69" viewBox="0 0 116 69">',
replacement: '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="116" height="69" viewBox="0 0 116 69"><style><![CDATA[ svg svg { display: none; } svg svg:target { display: inline; }]]></style>'
}]
}
}
You can add some variables or RegExps to pattern to make it more robust and bulletproof.
--
The other solution is to switch to inline SVG nicely described by Chris Coyer (http:// css-tricks.com/svg-sprites-use-better-icon-fonts/). There is also Grunt task for that - [grunt-svgstore] (https:// github.com/FWeinb/grunt-svgstore).
P.S. You need to copy those links and remove space after "https://" cause I am new to StackOverflow and can not post more than 2 links...