The shorthand for embedding an image in Markdown is the following:

![descriptive text goes here](example.jpg)

This works for rendering an image in the same way a skateboard is a minimum viable replacement for car; it rolls, but not fast. To render an image responsibly in modern times you need a handful more properties than src and alt ; namely height, width, loading, and decoding attributes.

<img src="example.jpg" 
     alt="descriptive text goes here" 
     height="400" 
     width="300" 
     decoding="async"
     loading="lazy">

Here’s a quick summary of what those other attributes do and why you should have them:

  • height + width - The HTML spec changed slightly and now setting a height and width draws an aspect-ratio’d box for the image to paints in. This prevents layout shift as the image loads.
  • decoding="async" (Optional) - This prevents the browser from blocking other content and move image decoding it decodes the image data to a bitmap. I feel like this should be the browser default?
  • loading="lazy" (Optional) - Recommended for any image below the fold.

Honorable mentions

  • srcset + sizes - If you want the fastest images, you can offer different sizes and cuts of your images. I don’t do this and Lighthouse is always mad about it.
  • fetchpriority - This is like driving a manual stick shift, but may be useful. I think loading="lazy|eager" are easier to reason about than fetchpriority but I’m not your boss.

Some Markdown formatters have a custom syntax that supports adding more attributes, like Kramdown…

![descriptive text goes here](example.jpg){: height="36px" width="36px" decoding="async" loading="lazy" }

This makes your Markdown less readable and less portable to other engines. If you’re going to include all these attributes, you might as well use an HTML <img> tag. This will make your images consistent with the other (unsupported without plugins) media like <video>, <audio>, <picture>, and <svg> in your Markdown posts.