ponyfoo.com

SVG and the DOM, or “The Weirdest Bug I’ve Ever Encountered”

Fix
A relevant ad will be displayed here soon. These ads help pay for my hosting.
Please consider disabling your ad blocker on Pony Foo. These ads help pay for my hosting.
You can support Pony Foo directly through Patreon or via PayPal.

I wanted to take a step back from all of the ES6 articles that have been popping up on Pony Foo lately to talk about a bug I came across last week. As I mentioned yesterday, the first thing I did during the redesign was to come up with an animated version of the logo, but some fringe events started to occur when I tried to embed it into the site.

For the record, here’s the animation. If all is well with the world, you should be able to set it in motion yourself by hovering over the icon at the top of this page, but I’m still adding the animation below – for posterity.

The ponyfoo.com logo in all of its animated glory
The ponyfoo.com logo in all of its animated glory

I put together the logo on CodePen. I find CodePen to be extremely useful when doing this kind of thing, as I don’t have to set up any live reloading stuff and I can just focus on the little thing I’m trying to accomplish – in this case, embellish a logo. Earlier this year I had turned the logo into an SVG graphic, making for a much nicer favicon than I used to have. So I took that, I put it up on CodePen, and added a bunch of styles to animate the logo on hover.

See the Pen EVZLLm by Nicolas Bevacqua (@bevacqua) on CodePen.

The styles are fairly simple. Each “pixel” in the logo is an SVG <rect>. These have an SVG fill color, and that’s used to determine what color should be animated. The sweep effect is caused by the following bit of code. It adds 10 milliseconds to the total length of the animation, times the index in the DOM tree. That means the first pixel animates in full for 710ms, the second one takes 720ms to complete, and so on. It really is very simple, and I love how new patterns unfold as the animation goes on.

for offset in (1..107)
  &:nth-child({offset})
    animation-duration 0.7s + offset * 0.01

Then I tried adding it to my site.

Using an <img> tag

Specifically, in the header of the site. I saved the file as ponyfoo.svg and placed it in my images directory. Then I updated my HTML markup with something like the code below. The fallback onerror was a nice touch, I guess.

<a href='/'>
  <img src='/img/ponyfoo.svg' onerror='this.src="/img/ponyfoo.png"' />
</a>

The problem with using an <img> tag to embed SVG graphics in a site is that it completely ignores CSS. That approach was immediately out then, as I couldn’t animate the logo on hover – or at all – with an <img> tag. After that approach failed me, I tried an <object> next.

Using an <object> tag

I know, what year is this? Anyways. Here’s the HTML code I used.

<a href='/'>
  <object data='/img/ponyfoo.svg' type='image/svg+xml'>
    <img src='/img/ponyfoo.png' />
  </object>
</a>

This one was even weirder. The link stopped working altogether, because the <object> goes into obscure sandboxing mode. The CSS animation wouldn’t work either, but I could place the CSS styles inside the SVG graphic, and then they worked on hover. Still, the link wasn’t working either. I guess I could add the link inside the SVG as well! At this point the SVG was an utter mess.

<svg>
  <style><!-- lots of compiled css --></style>
  <!-- all the rects -->
  <a xmlns='http://www.w3.org/2000/svg' xlink:href='/' xmlns:xlink='http://www.w3.org/1999/xlink' target='_top'>
    <rect x='0' y='0' width='100%' height='100%' fill-opacity='0' />
  </a>
</svg>

That worked – kind of. It wasn’t the prettiest of files, though. I hated the fact that I had to inline the entire CSS inside the SVG, and even the link. So un-DRY of you, SVG.

Okay then, I decided to try one more and that’s when it all went to hell.

Using an <svg> tag

I decided that maybe using an inline <svg> tag wouldn’t be that bad. After all, this was the logo. It’s a relatively small graphic, and then I could have the CSS lying around with all its other CSS rule pals. This time, the markup went like below. I included an <image> tag as a clever hack that provided a fallback for older browsers.

<a href='/'>
  <svg>
    <!-- all the rects -->
    <image src='/img/ponyfoo.png'/>
  </svg>
</a>

This one was supposed to work great. You can find the full snippet of code here. If you paste that code into an HTML file and open it, it’ll work in most browsers. If you host that same file in a Node.js server, and navigate to that page under Google Chrome 45.0.2454, the animation won’t work.

Let’s recap to highlight how fringe all this is.

  • It doesn’t matter whether you set <!doctype> or not, that’s inferred
  • The snippet works on all browsers when opened as a file
  • The animation doesn’t work on Google Chrome 45.0.2454 when hosted on a server (example in CodePen)
  • The animation works if you remove the <a> around the SVG
  • The animation works if the snippet is opened as a file
  • The animation works if you aren’t logged into your Google Chrome profile
  • The animation works if you use Chrome Canary (we didn’t try older versions)
  • It gets Google engineers to go “holy shit!”

For the record, I’m not bashing Google Chrome here. I’m just pointing at a very weird bug I came across and got pretty frustrated about. I guess this is one of those things Chris Heilmann talks about when he speaks of how we’re failing the web.

Granted, we may not need a moratorium on web features – but we do need this kind of primitives to be fixed. Basic stuff like styling a <select> or an <input type='check'> shouldn’t be an art form (as Chris points out). It should be really simple to embed SVG graphics in our websites. It should be easier to set up SSL.

We can do better.

Liked the article? Subscribe below to get an email when new articles come out! Also, follow @ponyfoo on Twitter and @ponyfoo on Facebook.
One-click unsubscribe, anytime. Learn more.

Comments