Let’s refactor. HTML semantics and readability
In today’s example, I want to refactor a piece of HTML, specifically, the title menu of the site. I removed the duplicate elements and irrelevant attributes to keep the example clean.
Disclaimer. I take refactoring examples from real sources (websites, open-source projects, articles), changing the names of entities or other unique components. I don’t and cannot know the context, conditions, or time when the code was written, and therefore all my fixes are my personal subjective perception of what could be changed in the code. Therefore my fixes do not carry any negative assessment of the code source or its creators.
Source
<div class="nav-links">
<div class="UITabs -with-icons">
<a class="UITabs-tab" href="/map" data-tab="map">
<div class="UITabs-content">
<div class="UITabs-icon">
<svg
class="ico" width="20" height="20"
viewBox="0 0 20 20" fill="#9e9e9e"
xmlns="http://www.w3.org/2000/svg"
>
<path fill-rule="evenodd" clip-rule="evenodd" d="...">
</path>
</svg>
</div>
Map
</div>
</a> <a class="UITabs-tab" href="/discount" data-tab="discount">
<div class="UITabs-content">
<div class="UITabs-icon">
<svg
class="ico" width="20" height="20"
viewBox="0 0 20 20" fill="#9e9e9e"
xmlns="http://www.w3.org/2000/svg"
>
<path fill-rule="evenodd" clip-rule="evenodd" d="...">
</path>
</svg>
</div>
Discount
</div>
</a> <div class="UITabs-tab" data-tab="search">
<div class="UITabs-content">
<div class="UITabs-icon">
<svg
class="ico" fill="#9e9e9e" height="24"
viewBox="0 0 24 24" width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path d="..."></path>
<path d="M0 0h24v24H0z" fill="none"></path>
</svg>
</div>
Search
</div>
</div> <div class="UITabs-indicator" style="transform..."></div>
</div>
</div>
The first thing I noticed was the excess use of <div>
tags. Of course, there is nothing wrong with this tag, and therefore, like all good things, it is used too often.
The next is nesting depth, which clearly doesn’t carry any semantic meaning. Also, deep nesting bloats the size of the HTML file, slows down CSS parsing, and degrades readability in general.
Also — icons are defined in HTML. This is also not critical, moreover, it depends on the caching strategy, the presence of a CDN, the list of supported browsers, etc. In this case, the icons will not be loaded separately from the HTML file, which means they will be visible immediately, without content jumps, but they will also increase the file size, which will slow down its loading and parsing. Obviously, there is no unambiguously correct or wrong decision in this matter, but from the point of view of semantics, in my opinion, icons clog up the code. Moreover, unlike pictures, icons are important only from a visual point of view. Therefore, it is better to define the visual part of the page in CSS.
Let’s find other semantically correct tags, reduce the nesting depth, and clean this code from unnecessary elements. Let’s do it step by step.
Container
Since this is a menu, the <nav>
tag, which is used for navigation elements, would be more suitable for a container.
Now the question is — why do we need two <div>
tags nested inside each other? Apparently, .nav-links
contains positioning styles relative to its parent at the same time, .UITabs
is the real parent of navigation. I see no point in splitting styles into two different tags, so I suggest replacing them with one <nav>
tag with two classes.
<nav class="UITabs -with-icons nav-links">
<a .../> <a .../> <div .../>
<div .../>
</nav>
Menu items
I have no questions for link tags, but again there is extra nesting, the .UITabs-content
class. Again, this is the separation of tags based on their styles, but in this case, most likely, this is an attempt to follow a methodology, such as BEM, but I see no reason to separate the styles of the .UITabs-tab
block from its only direct child .UITabs-content
. Moreover, both classes set paddings, overriding each other. As in the container’s case, I propose combining these two tags into one.
<a class="UITabs-tab" href="/map" data-tab="map">
<div class="UITabs-icon">...</div>
Map
</a>
There is a <div>
menu item along with links, which is semantically incorrect since a menu item, by definition, is an element of user interaction, which means it must be either a link or a button. In our case, this is the search button, so let’s write it down.
<button class="UITabs-tab" data-tab="search">
<div class="UITabs-icon">...</div>
Search
</button>
Icons
As I already wrote above, I propose to remove icons from HTML, their place is in CSS, and since I don’t want to use any extra element in HTML, they will be defined in a pseudo-element.
<style>
.UITabs-tab.-map-icon::before {
content: url(/map-icon.svg); //first option
}
.UITabs-tab.-discount-icon::before {
content: url(data:image/svg+xml; utf8, <svg>...</svg>); //second
}
...
</style><a class="UITabs-tab -map-icon" href="/map" data-tab="map">
Map
</a>
Other elements
There remains the last point that begs the question — .UITabs-indicator
. Basically, this is an underline of the active menu item, which is styled using javascript. I think this is overhead because underlining is easy to implement using the CSS border
property. Or, if it looks more complicated than just a bar, you can use the ::after
pseudo-element or the box-shadow
property for styling.
<style>
.UITabs-tab.active {
border-bottom: 4px solid currentColor;
}
</style>
Result
<style>
.UITabs-tab.-map-icon::before {
content: url(/map-icon.svg);
}
.UITabs-tab.-discount-icon::before {
content: url(data:image/svg+xml; utf8, <svg>...</svg>);
}
.UITabs-tab.-search-icon::before {
content: url(data:image/svg+xml; utf8, <svg>...</svg>);
}
.UITabs-tab.active {
border-bottom: 3px solid currentColor;
}
...
</style><nav class="UITabs -with-icons nav-links">
<a class="UITabs-tab -map-icon" href="/map" data-tab="map">
Map
</a> <a class="UITabs-tab -discount-icon" href="/discount" data-tab="discount">
Discount
</a> <button class="UITabs-tab -search-icon" data-tab="search">
Search
</button>
</nav>
In my opinion, this HTML is more readable and semantically correct. By the way, I’ve never used <div>
, although there was no such goal, however, it often happens if you adhere to semantics.
Thanks for reading so far!
See you next time! 🤹🏻♀️