Sunday, October 26, 2014

SVG fallback pure CSS: Can I use Part 5

Previous: External SVG: Can I use Part 4


SVG is old technology, but there are even older browsers in use that do not support SVG.
The idea of supporting such pure browsers is to provide PNG (JPG or GIF) image in background.

After making big research the best solution without using java-script is found with SVG trick:
  • switch tag, which takes first supported element
  • foreignObject tag, that gives ability to insert object from alien namespace
For inline SVG this works as:
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40">
  <switch>
     <circle cx="20" cy="20" r="18" stroke="grey" stroke-width="2" fill="#99FF66" />
     <foreignObject>
         <div class="nicolas_cage fallback"></div>
     </foreignObject>
  </switch>
</svg>
If browser supports SVG it will take <circle> as first child, otherwise <div class="nicolas_cage fallback"> is shown.

For external SVG we can use standard object fallback:
    <object type="image/svg+xml" data="circle_orange.svg">
     <div class="nicolas_cage fallback"></div>
    </object>

And inside <HEAD> just add a class with background image for fallback:
  <head>
    <style type="text/css">
     .nicolas_cage {
         background: url('nicolas_cage.jpg');
         width: 20px;
         height: 15px;
     }
     .fallback {
     }
    </style>
  </head>

For "No SVG" Nicolas Cage will show up

The <div> is chosen instead of <img> because image is mostly always downloaded by browsers, though {display: none} is set for <img>.

However test also showed that IE and Firefox still download background images for <div>, while Chrome and Safari works great with it. The twice download problem only occurs with
<foreignObject>
   <div class="nicolas_cage fallback"></div>
</foreignObject>
and is not a trouble for <object> fallback. At first I tried to set {display: none;} for <fallback> element in <head> style, but Android 2.x and Mobile Safari 4.0.4 parses it as object and hides hole object.

The solution is to set {display: none; background: none; } for <div>, then IE and Firefox stops download <div> background images. Finally the question appears:

How can we update <div> for SVG supporting browsers and hide it while leave it unchanged for those browsers that do not support SVG?

One solution is found, though it can not feet for all.
The trick is with ability of SVG to take a style from another SVG object.
 <svg id="SVG_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"  
      width="20" height="20">
      <style>
        <![CDATA[
        .orange {
          fill: #FF9900;
        }
        ]]>
      </style>
 </svg>
 <svg id="SVG_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"  
  width="20" height="20">
 <circle cx="10" cy="10" r="8" class="orange" />
</svg>

SVG_2 takes .orange style from SVG_1 even though they are different objects in one HTML file.

The solution is to paste special SVG inside <body> element with clear image style:
.fallback { background: none; background-image: none; display: none; }

And the result test page:
<!DOCTYPE html>
<html>
  <head>
    <title>HTML5 SVG demo</title>
    <style type="text/css">
     .nicolas_cage {
         background: url('nicolas_cage.jpg');
         width: 20px;
         height: 15px;
     }
     .fallback {
     }
    </style>
  </head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" style="width:0; height:0; display:0">
 <style>
 <![CDATA[ 
  .fallback { background: none; background-image: none; display: none; }
 ]]>
 </style>
</svg>

<!-- inline svg -->
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40">
  <switch>
     <circle cx="20" cy="20" r="18" stroke="grey" stroke-width="2" fill="#99FF66" />
     <foreignObject>
         <div class="nicolas_cage fallback"></div>
     </foreignObject>
  </switch>
</svg>
<hr/>
<!-- external svg -->
    <object type="image/svg+xml" data="circle_orange.svg">
     <div class="nicolas_cage fallback"></div>
    </object>
</body>
</html>

Starting tests in different browsers:

All renders great: small Cage for "No SVG" browsers and circles for those that support SVG.

What about fallback image downloading for SVG supporting browsers? 

Gladly double downloading does not occur with latest versions of browsers (IE 11, Chrome 38, Safari 8, Firefox 33).
As a plus this solution pushes strong hint to avoid downloading fallback images with
.fallback { background: none; background-image: none; display: none; },  
and it with a high degree will work for new SVG browsers that are hard to test (Kindle, Noble, etc).


UPD: eliminated error in CDATA closing tag ]]>, added style="width:0; height:0; display:0" to SVG fallback.

Saturday, October 25, 2014

External SVG: Can I use Part 4

Previous: Inline SVG, CSS and defs: Can I use Part 3

External SVG file can be included inside HTML with one of the next methods:
  • <object type="image/svg+xml" data="circle_orange.svg" class="blockSize" />
    
  • <img src="circle_orange.svg" class="blockSize" />
  • <iframe src="circle_orange.svg" class="blockSize" />
    
  • <embed type="image/svg+xml" src="circle_orange.svg" class="blockSize" />
  • CSS background with svg file
Each method, except CSS background, is tested for browser support. In addition we investigated CSS support in <head> section of HTML page and style inlining in external SVG file.

All browsers (except that do not support SVG) showed good results and support external svg referencing.


While investigating render with browsers that do not support SVG, at first all went as expected. Here is the result for IE 7:


But then Android Mobile Browser 2.2 showed this: 

You can see the CSS code, which should not be shown. It is inlined in external SVG.
The suggestion falls in 3d section with iframe in both cases. To confirm the suggestion the page with iframe reference is created:
<!DOCTYPE html>
<html>
  <head>
    <title>HTML5 SVG demo</title>
  </head>
 <body>
    <iframe src="circle_orange_defs.svg" class="blockSize"></iframe>
</body>
</html>

File circle_orange_defs.svg:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" 
      width="20" height="20">
      <style>
      <![CDATA[
        .orange_internal {
          fill: #FF9900;
        }
        >
      </style>
      <defs>
          <circle id="circle_orange" cx="10" cy="10" r="8" stroke="grey" stroke-width="2" class="orange_internal" />
      </defs>
      <use xlink:href="#circle_orange" width="20" height="20" />
</svg>
And Android 2.2 renders it as

As suggested old Android cannot clearly render iframe with external SVG, that contains inlined style.
We can use some tricks to fix it, but simple solution is not to use iframe for SVG at all, there are at least 4 alternatives to reference SVG file.

CSS support

All browsers that can render SVG support style in external files if they are inlined in SVG.
There is no possibility to apply HTML CSS from <head> section to external SVG file, because browser does not consider it as part of the DOM. This is the reason why one of the line with circles is black (lack of style).


Test results

Browsers that support SVG process external files without a problem. Android Mobile browser 2.2 has bad behaviour with <iframe>.

The results for desktop:
Chrome: 38, ..., 16 *
Internet Explorer: 11, 10, 9,  8, 7, 6
Firefox: 31, ..., 4, 3.6, 3.5
Safari: 8, 7, 6.1, 5.1

* - green - works as expected, red - does not support SVG 

The result for mobile devices:
Chrome Mobile: 37, ..., 31
Android Browser: 4.0, 2.2
Mobile Safari: 5.1, 5.02, 4.0.5, 4.0.4

In this test external reference with hash tag is not tested and will be done in future. There are some known problems with partial referencing (#) <img src="circle_orange.svg#circle" />. 

Next: SVG  fallback image without java-script.

Inline SVG, CSS and defs: Can I use Part 3

Previous: Inline SVG: Can I use Part 2

One of the great feature of SVG is <defs> or definitions, that allows graphic reusing.
Take a star with path
<path d="M46.19 9.21l1.96 7.76 7.98-.54-6.77 4.26 2.97 7.43-6.14-5.12-6.14 5.12 2.97-7.43-6.77-4.26 7.98.54z" id="star">

We can reuse the code of star and make some transformation (move, scale, rotate) for basic figure.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="160" height="152">
  <defs>
    <path id="star" d="M46.19 9.21l1.96 7.76 7.98-.54-6.77 4.26 2.97 7.43-6.14-5.12-6.14 5.12 2.97-7.43-6.77-4.26 7.98.54z"/>
  </defs>
    <use xlink:href="#star"/>
    <use xlink:href="#star" x="90" y="20" />
    <use xlink:href="#star" x="14" y="80" />
</svg>

What about browser support?

For test we use same page and the results are gladly equals to previous test.


Test are taken with inlined SVG (inside HTML as in previous tests).

The results for desktop:
Chrome: 38, ..., 16 *
Internet Explorer: 11, 10, 9,  8, 7, 6
Firefox: 31, ..., 4, 3.6, 3.5
Safari: 8, 7, 6.1, 5.1

* - green - works as expected, red - does not support SVG

The result for mobile devices:
Chrome Mobile: 37, ..., 31
Android Browser: 4.0, 2.2
Mobile Safari: 5.1, 5.02, 4.0.5, 4.0.4

Combining it with previous test we can make a rule:
If browsers supports SVG then it supports <defs> definitions.

There is convenient diagram for browser support: Can I use SVG.  And our tests confirm there topicality.


Next section: External SVG using Part 4

Friday, October 24, 2014

Inline SVG: Can I use Part 2

Let's draw simple circle in svg file.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" 
  width="200" height="200">
 <circle cx="100" cy="100" r="80" stroke="grey" stroke-width="3" fill="#3f85e5" />
</svg>



We can inline svg inside HTML page, svg becomes an element in any part inside <body> tag:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Inline SVG Demo</title>
</head>
<body>
</body>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" 
  width="200" height="200">
 <circle cx="100" cy="100" r="80" stroke="grey" stroke-width="3" fill="#3f85e5" />
</svg>
</html>

The test window for cross browser testing:


The test results are shown in small windows and can be opened in own virtual machine.


Next point is to test CSS styling. It can be added in two ways with SVG inlined. 
First approach is usual CSS styling in HTML <head> section:
<!DOCTYPE html>
<html>
  <head>
    <title>CSS and SVG test</title>
    <style type="text/CSS">
      .redness {
        fill: #FF0066;
      }
    </style>
  </head>
 <body>
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"  
      width="20" height="20">
     <circle cx="10" cy="10" r="8" stroke="grey" stroke-width="2" class="redness" />
    </svg>
</body>
</html>

Second approach is to inline CSS within SVG itself. To ignore special symbols, like less or grater sign use <![CDATA[ ... ]]> for CSS:
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"  
      width="20" height="20">
      <style>
        <![CDATA[
        .orange {
          fill: #FF9900;
        }
        >
      </style>
     <circle cx="10" cy="10" r="8" stroke="grey" stroke-width="2" class="orange" />
    </svg>

For SVG support testing special page is created at http://highrobotics.com/media/context/article/svg_compatability/svg_test.html 

Test results

Next desktop operating systems were in use: Mac OSX 10.9 and 10.6, Windows 7 x64, Windows XP SP2 x32, Ubuntu 11.10 (only Chrome v. 16).

Mobile and tablet devices are shown on the left with their browsers. Only Windows Phone is missing.

The results for desktop:

Chrome: 38, ..., 16 *
Internet Explorer: 11, 10, 9,  8, 7, 6
Firefox: 31, ..., 4, 3.6, 3.5
Safari: 8, 7, 6.1, 5.1

* - green - works as expected, red - does not support SVG

The result for mobile devices are very good for developers. Every tested browser, except Android Browser v. 2.2, supports basic SVG:
Chrome Mobile: 37, ..., 31
Android Browser: 4.0, 2.2
Mobile Safari: 5.1, 5.02, 4.0.5, 4.0.4


Mostly all popular browsers have support for basic inlined SVG:
  • simple graphics
  • SVG CSS from HTML <head> section
  • CSS inside SVG


Problematic browsers are Internet Explorer 6, 7, 8 and Android Mobile Browser 2.2, they are still popular, but do not support vector graphics at all.
Here is how Andoroid 2.2 renders simple SVG test page
Similar works IE version 8 or earlier and shows empty place.

SVG: Can I use Part 1

For one of our client we decided to add delight vector images in motion. SVG feet best in this case: it is scalable and takes small file size.

One of the image is a pencil with form:


It would be brilliant to have a working solution and show this image to every user. However not all browsers support different technologies produced by W3C. There is a rumor on the internet whether SVG will work or not in one or another case. We decided to make our own investigation on this field and clear the dirty spots.

CrossBrowserTesting is chosen to help in inspection in variety of browsers.

First test is simple: browser compatibility for svg image inlined in HTML.