Classy Images in Markdown

I was about to update my website with completely unrelated information about front-end data management, when a typo took me to my own 404 page. I hadn't been there in a while, and I realized that I hadn't taken care of the minor issue of getting the image centered.

The main reason I hadn't made any changes was that I didn't really want to muddy the markdown source I was using for that page. I could certainly change

![404][1]

[1]: /content/error/404.png

to something along the lines of:

<img src="/content/error/404.png" alt="404" class="center" />

But I felt like that would defeat the purpose of using markdown for images. I want to write less markup, and not be stuck having to expand every centered image on the site to use raw HTML.

What I really wanted was a way to inject some sort of CSS hook into the <img> element. Certainly something along the lines of:

![404][1]

[1]: /content/error/404.png .center

could work, but I really didn't feel like diving into the markdown source just to resolve a simple styling issue.

That's when it hit me, I already could add CSS hooks into the <img> element, and it wouldn't require changing anything other than the image path and a bit of CSS. The answer was simple, use a query-string and a substring matching attribute selector, or as jQuery calls it, the "Attribute Ends With Selector". The source would remain mostly the same, but this technique would give me better control over the styles of individual images:

HTML:
![404][1]

[1]: /content/error/404.png?center
CSS:
img[src$="center"] {
    display: block;
    margin: 0 auto;
}

This worked like a charm, but I quickly realized that it was nowhere near an optimal solution. What if I had an image from a service that required a specific query-string value? No, while the query-string was a good start, it was definitely the wrong place to put styling (and possibly scripting) meta-data.

Enter the fragment identifier

At the end of every url is the fragment identifier, aka "hash", which can contain all sorts of anything where images are concerned. You see, images rendered in <img> elements don't have any use for the fragment identifier, so it's safe to add whatever value you'd like. It's not sent to the server as part of any request, so it won't adversely affect the rendering of the image, and it will still be accessible with the "Attribute Ends With" selector:

HTML:
![404][1]

[1]: /content/error/404.png#center
CSS:
img[src$="center"] {
    display: block;
    margin: 0 auto;
}

But this leads to the next issue. What if I wanted to apply multiple styles to the same image? The [src] attribute could only ever end with one document fragment...or can it? If I change the selector to the "Attribute Contains Selector" (jQuery linked for the name, no explicit name is given in the w3c spec), I can detect if the value occurs anywhere in the attribute, however this would lead to false-positives for images whose URLs happened to contain the matched substring:

img[src*="center"] would match:

  • /foo.png#center yay!
  • /foo.png#not-quite-center boo!
  • /center.png boo!

The trick is then to add the initial # to the matched substring:

img[src*="#center"] would match:

  • /foo.png#center

but would not match:

  • /foo.png#not-quite-center
  • /center.png

The advantage to this format is that now multiple #hashtags can be added to images to apply whatever styles I choose:

/foo.png#center#framed#and#whatever#else#I#want

Which makes my current implementation:

HTML:
![404][1]

[1]: /content/error/404.png#center
CSS:
img[src*="#center"] {
    display: block;
    margin: 0 auto;
}

The one unresolved issue that I can still see at this point is that the selector will match on longer hashes that start with the same characters:

[src*="#foo"] will match on:

  • /lorem.png#foo yay!
  • /lorem.png#foobar boo!

I will have to keep an eye out for this issue going forward, however I could also see it as a means of extending on some base styles:

[src*="#foo"] would match on:

  • /lorem.png#foo
  • /lorem.png#foo-light
  • /lorem.png#foo-dark

While the more specific selectors [src*="#foo-light"], and [src*="#foo-dark"] could be used to apply the additional styles needed to generate the desired effect.