Is it okay to add SVGs at the bottom of HTML and reference them later?

Hi,
I have a hamburger button with the following HTML markup:

<button class="menu-toggle">
   <svg class="icon icon-hamburger" aria-hidden="true" role="img">
      <use href="#icon-hamburger" xlink:href="#icon-hamburger"></use>
   </svg>
   <svg class="icon icon-close" aria-hidden="true" role="img">
     <use href="#icon-close" xlink:href="#icon-close"></use>
   </svg> Menu
</button>

And these definitions added at the bottom of the HTML:

<svg style="position: absolute; width: 0; height: 0; overflow: hidden;" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <symbol id="icon-hamburger" viewBox="0 0 27 32">
      <path class="path1" d="M27.429 24v2.286q0 0.464-0.339 0.804t-0.804 0.339h-25.143q-0.464 0-0.804-0.339t-0.339-0.804v-2.286q0-0.464 0.339-0.804t0.804-0.339h25.143q0.464 0 0.804 0.339t0.339 0.804zM27.429 14.857v2.286q0 0.464-0.339 0.804t-0.804 0.339h-25.143q-0.464 0-0.804-0.339t-0.339-0.804v-2.286q0-0.464 0.339-0.804t0.804-0.339h25.143q0.464 0 0.804 0.339t0.339 0.804zM27.429 5.714v2.286q0 0.464-0.339 0.804t-0.804 0.339h-25.143q-0.464 0-0.804-0.339t-0.339-0.804v-2.286q0-0.464 0.339-0.804t0.804-0.339h25.143q0.464 0 0.804 0.339t0.339 0.804z"></path>
    </symbol>
    <symbol id="icon-close" viewBox="0 0 25 32">
      <path class="path1" d="M23.179 23.607q0 0.714-0.5 1.214l-2.429 2.429q-0.5 0.5-1.214 0.5t-1.214-0.5l-5.25-5.25-5.25 5.25q-0.5 0.5-1.214 0.5t-1.214-0.5l-2.429-2.429q-0.5-0.5-0.5-1.214t0.5-1.214l5.25-5.25-5.25-5.25q-0.5-0.5-0.5-1.214t0.5-1.214l2.429-2.429q0.5-0.5 1.214-0.5t1.214 0.5l5.25 5.25 5.25-5.25q0.5-0.5 1.214-0.5t1.214 0.5l2.429 2.429q0.5 0.5 0.5 1.214t-0.5 1.214l-5.25 5.25 5.25 5.25q0.5 0.5 0.5 1.214z"></path>
    </symbol>
    <symbol id="icon-angle-down" viewBox="0 0 21 32">
      <path class="path1" d="M19.196 13.143q0 0.232-0.179 0.411l-8.321 8.321q-0.179 0.179-0.411 0.179t-0.411-0.179l-8.321-8.321q-0.179-0.179-0.179-0.411t0.179-0.411l0.893-0.893q0.179-0.179 0.411-0.179t0.411 0.179l7.018 7.018 7.018-7.018q0.179-0.179 0.411-0.179t0.411 0.179l0.893 0.893q0.179 0.179 0.179 0.411z"></path>
    </symbol>
</defs>

The full codepen:

I was wondering if this approach is okay. In the past, I used to create an empty div with ::before and ::after pseudo-classes to build the hamburger icon, but I think using a button is better for accessibility. Do you see any issues with my method?

There are instances where using <defs> and <use> SVG elements can be useful, particularly when removing repetition from your code when SVG is in-lined in the HTML.
The first question to ask is: Do I need to in-line the SVG content?
It may be preferable to reference SVG from an external file via img and src, or as CSS background, in order to reduce code clutter and maintain separation of concerns. But if you plan on using CSS to manipulate the SVG in an interactive way, such as hover or click effects, the SVG needs to be in-line.

The next consideration for <defs> and <use> is repetition. If an SVG image is used multiple times in a page, such as a icon which reoccurres, you can reduce code repetition by defining the geometry only once (in <defs>), then use multiple times in a less verbose way with <use>.
The <defs> and <use> can also be utilised within an SVG image, for example a ā€œhamburgerā€ icon may have three identical horizontal bars. You could define the bar shape once, then use three times, altering only the position.

In your use case, I donā€™t see CSS being applied to the SVG in a way that would require in-lining. Also I donā€™t the SVG geometry being reused.
Though on that second point it could be argued that <defs> and <use> does aid separation of concerns by removing the untidy bulk of geometry definition from the main content mark-up and putting it to one side, while only the more minimal <use> appears among the content.

So in summary, this can be a useful method to trim down your code, but it needs to be considered on a case by case basis to asess whether it is the best method to achieve what you need.
In your case, I would probably just use external SVG files, unless I intended to add things like CSS hover effects to the icons.

2 Likes

I would prefer this: :slight_smile:

<button class="toggle"></button>

Then just style it with css and not have any extra html or links to images or svgs,

Or:

Obviously the svg may look a little nicer but with a little more effort the css version could be embellished a bit and has a transition from one state to the other baked in also.

1 Like

Thank you, Paul. I appreciate your time.
Do you think it would be okay to add ARIA labels to the button, like this?

<button class="menu-toggle"
        aria-label="Toggle navigation" 
        aria-expanded="false">
</button>

and in JS:

const menuToggle = document.querySelector('.menu-toggle');
const nav = document.querySelector('.nav');

menuToggle.addEventListener('click', () => {
  const isOpen = nav.classList.toggle('open');
  menuToggle.setAttribute('aria-expanded', isOpen);
});

Yes thatā€™s fine if your button has no logical content such as Menu (as in my second example) or Open/close menu etcā€¦

I would actually prefer to have text in there that says toggle menu or changes from open menu to close menu or something similar and then thereā€™s no need for aria labels even if you hide the text off screen.

In some ways you can consider aria labels as a failure of your html in that you have to explain to someone what your html is doing. :slight_smile:

Do you mean this?

<button class="menu-toggle">
  <span class="screen-readers">Menu</span>
</button>

css:

.screen-readers {
  position: absolute;
  border: 0;
  padding: 0;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
}

this hides the text but still available for screen readers.

As for your second example, I tried it, and I like it, but I need to use:

.toggle b{
  display:flex;
  transform:translate(180%, -6px);
..

instead of:

transform:translate(160%, -4px)

for the text to be centered and pushed a bit to the right, to have a little space between the hamburger icon and the text. Instead of the <b> for the text, is it also possible to use just an empty span element?

1 Like

Yes that is perfectly clear what the button is for without aria labels etc. A button element means that an action will take place when clicked and the text tells you that a menu will result from that action.

Yes a span is perfectly fine and probably the correct element to use there.

I used the b element because its less characters and these days basically means that the text is brought to the readers attention.

Sometimes semantics can be argued back and forth so you make a choice based on what you think best as its not always so clear cut. :slight_smile:

I was wondering if itā€™s possible to add 5px padding on each side of the hamburger icon, making that padding clickable as well? This would help in cases where users might not click precisely on the hamburger icon. In your first example of codepen.

The code for those SVGs is ridiculously long.

Here is how it can be done using SVGs with much less code:

Iā€™ve added 5px padding.

1 Like

Thank you! How do you edit these svgs? Can they be imported into Inkscape? I was wondering if itā€™s possible to make the lines just a bit longer, about 3-4px.

You could apply all the styling to the inner span and then just add some padding (or transparent border) to the button to enlarge the click area.

Hereā€™s the example revamped.

Those SVGs are simply using <line> elements:

I do not have Inkscape but it seems it can import .svg files.

I have now changed the SVGā€™s viewbox in the Codepen above so it is now 12 units wide by 10 units high. The coordinates of the lines have been changed accordingly. In the CSS I have increased the width accordingly so the button is now rectangular.

EDIT: I do not understand why the SVG is not central vertically within the button. Anyway we can adjust the position by adjusting padding,

1 Like

You could alternatively use one <path> element with ā€˜dā€™ attribute and a combination of ā€œMove toā€ (M) and ā€œLine toā€ (L) commands:

Even less code :grinning:

1 Like

I rewrote your CSS using nesting. Do you think there is anything wrong with this approach?

1 Like

No thatā€™s fine if thatā€™s what suits you :slight_smile:

Iā€™m not a fan of nesting as it its just something else that can go wrong. You canā€™t look at a long css file and see where the nested rule applies unless you track all the way back up the stylesheet to see where the nesting started. It also encourages longer selectors than could be achieved with a single class.

However Iā€™m in the minority as others love it :slight_smile:

In the end these types of questions are down to what suits your way of working the best.

1 Like