There is a way to make image.svg#1 and image.svg#2 point to a variant of the same image.

bucket.svg#fill1 bucket.svg#fill2 bucket.svg#fill3 bucket.svg#fill4

This is the same image 4 times. Only one svg is downloaded as the part after the # is not sent in the HTTP request.

The :target pseudo class

The trick is to use CSS. Thanks to the :target selector we can differentiate between various states of the image.

The :target pseudo-class represents the unique element, if any, with an id matching the fragment identifier of the URI of the document.

Mozilla Developper Network

A fragment identifier of a URI is the part that comes after the # in the URI. In other words: if the uri is bucket.svg#fill1 the fragment is fill1, thus :target will match the element with id="fill1". By cleverly using this you can do some cool things.

How to use it in SVG

SVG allows you to add a style sheet. This can be placed in the defs element of the code. The following SVG code resembles the code of bucket.svg from above.

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" ...>
  <defs>
    <style>
      #fill1,
      #fill2,
      #fill3,
      #fill4 {
        visibility: hidden;
      }
      :target {
        visibility: visible !important;
        fill: #0000ff;
        paint-order: markers stroke fill;
      }
    </style>
  </defs>
  <path d="m19.543 11.888v-1.5822c0-1.007..." />
  <path id="fill4" d="m4.3895 24.698h21.89..." />
  <path id="fill3" d="m4.3895 32.108h21.89..." />
  <path id="fill2" d="m4.7935 38.578 21.49..." />
  <path id="fill1" d="m5.3995 44.968 20.52..." />
  <path d="m27.261 22.197c-.79074 10.136-..." />
</svg>

The image below explains the structure:

Each level of filling has its own element filling the bucket to the desired level. Because all the fill... elements have visibility: hidden, only the fill... that is in the fragments specifier will be shown (because the visibility is overwritten).

Showing and hiding multiple elements

The fragment specifier can only match one element at a time. If you want to match multiple elements, you can assign them a class, for example hidden. By assigning an id to the root svg-tag itself, the CSS selector :root:target .hidden will select all elements with the class hidden. The :root element is an identifier for the root svg-tag. Note that if there is no id assigned to the root element, the URI without fragment specifier will target the root element in some browsers.

The same trick can be used by grouping all elements in multiple <g> tags, and assigning each of them with a unique id. the code below gives an example

<svg ...>
  <defs>
    <style>
      .inframe1,
      .inframe2,
      .inframe3,
      .inframe4 {
        visibility: hidden;
      }
      #frame1:target .inframe1 {
        visibility: visible !important;
      }
      #frame2:target .inframe2 {
        visibility: visible !important;
      }
      #frame3:target .inframe3 {
        visibility: visible !important;
      }
      #frame4:target .inframe4 {
        visibility: visible !important;
      }
    </style>
  </defs>
  <g id="frame1">
    <g id="frame2">
      <g id="frame3">
        <path class="inframe1" ... />
        <path class="inframe2" ... />
        <path class="inframe3" ... />
        <path class="inframe1 inframe2" ... />
        <path class="inframe1 inframe2 inframe4" ... />
        <path class="inframe4" ... />
      </g>
    </g>
  </g>
</svg>