Search code examples
htmlcssiconsspritecss-sprites

CSS Sprite menu icons with bare minimum one element HTML using :before pseudo-element


Summary / Nutshell

Is it possible to have a full width (display: block) clickable hyperlink HTML element that has a unique, positioned sprite background image class, all in just one HTML <a> element?

enter image description here




Background

Currently I have a working elaborate HTML menu, whereby each hyperlink has its own unique icon sprite background position.

The sprite icons each have their own unique class, which is added on top of the default menu class that holds the background url and general layout. All icons are exaclty the same size, 13 x 13 px. Each hyperlink has a full with using display:block. The mouse hover must be activated as soon as the block width is hovered, sothat short text or long text hyperlinks get a equal full width hover color.

SPRITES CSS

.home  {background-position:0 -13px}
.about {background-position:0 -1638px}
.ethos {background-position:0 -2944px}
.etcet {background-position:0 -5611px}

GENERAL CSS

li a{
    display: block;
    line-height: 2em;
    color: black;
    padding: 10px 1em 10px 2em;
    }

.menu{
    display: inline-block;
    background: url(icons.png) no-repeat;
    width: 13px; height: 13px;
    vertical-align: middle;
    margin: -2px 15px 0px -29px;
}

Currently the following undesired bloated HTML markup works...

Undesired: Bloated HTML

<li>
   <a href="/home">
      <p class="menu home"></p> Home
   </a>
</li>

... but I wonder if it would be possible to reduce that (without losing any of the essential functionality) to the absolute bare minimum HTML:

Desired: Minimal HTML

<a href="/home" class="home">Home</a>

New CSS

a{
    position: relative;
    padding: 0 0 0 1em;
}

a:before{
    content:'';
    position: absolute;
    background-image: url(icons.png);
    background-repeat: no-repeat;   
    top: .75em;
    left: 2px;
    height: 13px;
    width: 13px;
}

Stuck setting the unique background-position

I tried the a:before{} workaround and while the background icon boxes are positioned nicely relative to the hyperlinks, and the full width mouse hover works too, the sprites themselves are all from the initial starting pivot of x=0 y=0 of the background image!

enter image description here

In other words all the sprite icons are take from the first block of the sprite background png file. The unique individual class names do not seem to have been used for the background-position when using a:before{}.

If I move the background-image from a:before{} to a{}, then the layout breaks completely beyond repair.

In summary, is there a way to make a one-element HTML work with sprites on hyperlinks, using just a:before{} without necessitating any extra meaningless html elements such as <spans> or <p>, and achieve all the essentials of sprites positioning and full with block hoverability?

Any and all help is greatly appreciated!


Solution

  • You need to add pseudo-class to your customization classes. I've added an image how it works. It's explains more better, than hundreds of words. sprite image

    .home::before {
      background-position: 0 0px;
    }
    .about::before {
      background-position: 0 -13px;
    }
    .ethos::before {
      background-position: 0 -26px;
    }
    

    Also, if you have a simple menu, remove ul, li tags and wrap all links in a nav tag.

    <nav role="menu" aria-labelledby="navigation menu">
      <a href="/home" class="home">Home</a>
      <a href="/about" class="about">About</a>
      <a href="/ethos" class="ethos">Ethos</a>
    </nav>
    

    nav {
      display: inline-flex;
      flex-flow: column;
    }
    
    a {
      position: relative;
      padding: 0 1.3rem;
      text-decoration: none;
      transition: all 0.3s ease-in-out;
    }
    
    a:before {
      content: '';
      position: absolute;
      background-image: url('https://i.ibb.co/M7008LV/sprite.png');
      background-repeat: no-repeat;
      top: 50%;
      left: 2px;
      height: 13px;
      width: 15px;
      transform: translateY(-50%);
    }
    
    .home::before {
      background-position: 0 0px;
    }
    
    .about::before {
      background-position: 0 -13px;
    }
    
    .ethos::before {
      background-position: 0 -26px;
    }
    
    a:hover {
      background-color: #ffd73d;
    }
    <nav role="menu" aria-labelledby="navigation menu">
      <a href="/home" class="home">Home</a>
      <a href="/about" class="about">About</a>
      <a href="/ethos" class="ethos">Ethos</a>
    </nav>