<header class="page">
  <h2>Warcraft Tooltips</h2>
  <h3>with css, handlebars and some jQuery</h3>
</header>

<div class="bag">
  
  <header>Backpack</header> 
  
  <i class="wow-icon"
     data-item-id="hearthstone">
  </i>
  
  <i class="wow-icon" 
     data-item-id="shiny-red-apple">
  </i>
  
  <i class="wow-icon" 
     data-item-id="melon-juice">
  </i>
  
  <i class="wow-icon" 
     data-item-id="red-linen-shirt">
  </i>

  <i class="wow-icon" 
     data-item-id="medicine-staff-of-the-monkey">
  </i>

  <i class="wow-icon" 
     data-item-id="hoggers-trousers">
  </i>

  <i class="wow-icon" 
     data-item-id="deepdive-helmet">
  </i>

  <i class="wow-icon" 
     data-item-id="hanzo-sword">
  </i>

  <i class="wow-icon" 
     data-item-id="boots-of-the-petrified-forest">
  </i>

  <i class="wow-icon" 
     data-item-id="the-2-ring">
  </i>

  <i class="wow-icon" 
     data-item-id="dragonwrath-tarecgosas-rest">
  </i>

  <i class="wow-icon" 
     data-item-id="green-hills-of-stranglethorn-11">
  </i>

  <i class="wow-icon" 
     data-item-id="hopeglow-spaulders">
  </i>
  
</div>









<script id="wow-item-template" type="text/x-handlebars-template">

  <aside class="wow-item hidden" data-quality="{{ quality }}">
    <header class="wow-item__header">
      <p class="header__title">{{ name }}</p>
      {{#if binds}}<p class="header__binds">Binds {{ binds }}</p>{{/if}}
      {{#if unique}}
        <p class="header__unique">Unique</p>
      {{/if}}
    </header>
    <section class="wow-item__type">
      <p class="type__slot">{{slot}}</p>
      <p class="type__item">{{type}}</p>
    </section>
    <section class="wow-item__stats">
      
      {{#if damage}}
      <p class="stats__damage-armor"><span class="value">{{ damage.min }} - {{damage.max}}</span> Damage</p>
      <p class="stats__speed">Speed <span class="value">{{ speed damage.speed }}</span></p>
      <p class="stats__dps">(<span class="value">{{ dps damage }}</span> damage per second)</p>
      {{/if}}
      
      {{#if armor}}
      <p class="stats__armor">{{ armor }} Armor</p>
      {{/if}}
      
      <div class="stats__list">
        {{#each stats}}
        <p class="stats__{{ type }} stats__list-item">+{{ value }} {{ stat }}</p>
        {{/each}}
      </div>
      
    </section>
    
    {{#if enchantments}}
    <section class="wow-item__enchantments">
      
      {{#each enchantments.enchants}}
      <p class="enchantments__enchant">{{ description }}</p>
      {{/each}}
      
      <div class="enchantments__sockets">
        
        {{#each enchantments.sockets }}
        <p class="enchantments__socket socket--{{ color }}">{{ color }} socket</p>
        {{/each}}

        {{#if enchantments.socketBonus}}
        <p class="enchantments__socket-bonus">Socket Bonus: {{ enchantments.socketBonus }}</p>
        {{/if}}
        
      </div>
      
    </section>
    {{/if}}
    
    <section class="wow-item__info">
      
      {{#if durability}}
      <p class="info__durability">Durability: {{ durability }} / {{ durability }}</p>
      {{/if}}
      
      {{#each chanceOnHit}}
      <p class="info__chance-on-hit">Chance on hit: {{ description }}</p>
      {{/each}}
      
      {{#if classes}}
      <p class="info__class-requirement">Classes: <span class="value">{{ classes classes }}</span></p>
      {{/if}}
      
      {{#if level}}
      <p class="info__level-requirement">Requires Level {{ level }}</p>
      {{/if}}
      
      {{#if ilevel}}
      <p class="info__item-level">Item Level {{ ilevel }}</p>
      {{/if}}
      
    </section>
    
    {{#if bonuses}}
    <section class="wow-item__bonuses">
      {{#each bonuses}}
      <p class="bonuses__bonus">{{ description }}</p>
      {{/each}}
    </section>
    {{/if}}
    
    <section class="wow-item__info">

      {{#if tradelevel }}
      <p class="info__trade-level">Requires {{ tradelevel.trade }} ({{ tradelevel.level }})</p>
      {{/if}}

      {{#if flavour }}
      <p class="info__flavour-text">"{{ flavour }}"</p>
      {{/if}}
      
    </section>
    
  </aside>
  
</script>


$border: #a7a7ad;
$bg: rgba(10,0,5,0.8);
$shadow: transparentize( $bg , 0.3 );

$gap: 3px;

$crafting: #f4d403;
$trash: #999;
$common: white;
$uncommon: #24ee10;
$rare: #0070DD;
$epic: #ad23ed;
$legendary: #fa7c18;
$heirloom: #e5d9c5;
$flavour: #FFD100;

@mixin socket( $color: "meta" ) {
  
  $srcUrl: "https://wowimg.zamimg.com/images/";
  $socket: $srcUrl + "icons/socket-#{$color}.gif";
  
  background-image: url( $socket );
  background-repeat: no-repeat;
  background-position: left top;
    
}



.wow-icon {
  
  width: 27px;
  height: 27px; 
  display: inline-block;
  background-image: url( https://wow.zamimg.com/images/wow/icons/medium/inv_misc_questionmark.jpg );
  background-repeat: no-repeat;
  background-position: center;
  border-width: 4px;
  
  position: relative;
  margin: 2px 2px;

  box-shadow:
    -1px -1px 1px $shadow,
    -1px 1px 1px $shadow,
    1px 1px 1px $shadow,
    1px -1px 1px $shadow;
  
  .stack {
    
    color: white;
    font-size: 13px;
    font-style: normal;
    text-align: right;
    
    text-shadow: 
      0 0 2px black, 
      0 0 2px black, 
      0 0 3px black,
      0 0 3px black, 
      0 0 1px black,
      0 0 1px black;
    
    position: absolute;
    right: -1px;
    bottom: -4px;
    
  }
  
  &:after {
    
    content: "";
    position: absolute;
    width: 36px;
    height: 36px;
    left: -4px;
    top: -4px;
    
    border-radius: 4px;
    box-shadow: inset 0 0 5px black;
    
    transition: all 0.1s ease;
    
  }
  
  &:hover {
    
   &:after {
     
     box-shadow: 
       inset 0 0 9px rgba(30,180,230,0.9),
       inset 0 0 5px rgba(30,180,230,0.6);
     
   } 
    
  }
  
}


.wow-icon,
.wow-item {
  

  border-style: solid;
  border-width: 5px;
  border-image: url(https://assets.codepen.io/13471/wow-tooltip-border-2.png) 5 repeat;
  border-radius: 4px;
  
}



.wow-item {
  
  position: absolute;
  
  color: white;
  background-color: $bg;
  
  font-family: "friz", serif;
  font-size: 12px;
  font-weight: normal;
  padding: 0.5em 0.6em;
  text-shadow: 0 1px 0 rgba(0,0,0,1);
  
  box-shadow:
    -1px -1px 1px $shadow,
    -1px 1px 1px $shadow,
    1px 1px 1px $shadow,
    1px -1px 1px $shadow;
  
  max-width: 24em;
  
  transition: 
    opacity 0.05s ease-out 0.05s,
    transform 0.1s ease-out 0.05s;
  
  &.hidden {
    
    visibility: hidden;
    opacity: 0;
    transform: scale(0.95);

    transition: 
      opacity 0.05s ease-out 0.05s,
      transform 0.1s ease-out 0.05s,
      visibility 0.01s linear 0.15s;
    
  }
  
  p {
    padding: 0;
    margin: 0;
  }
  
  &[data-quality=crafting] {
    .header__title {
      color: $crafting;
    }
  }
  &[data-quality=heirloom] {
    .header__title {
      color: $heirloom;
    }
  }
  &[data-quality=trash] {
    .header__title {
      color: $trash;
    }
  }
  &[data-quality=common] {
    .header__title {
      color: $common;
    }
  }
  &[data-quality=uncommon] {
    .header__title {
      color: $uncommon;
    }
  }
  &[data-quality=rare] {
    .header__title {
      color: $rare;
    }
  }
  &[data-quality=epic] {
    .header__title {
      color: $epic;
    }
  }
  &[data-quality=legendary] {
    .header__title {
      color: $legendary;
    }
  }
  
}


  
.wow-item__header {

  .header__title {

    margin-bottom: $gap;
    font-size: 1.12em;
    margin-right: 1em;

  }

}

.wow-item__type {
   
  overflow: hidden;
  margin-top: $gap;
  
  .type {

    &__slot,
    &__item {

      float: left;

    }
    
    &__item {

      float: right;
      text-align: right;

    }

  }
    
}

.wow-item__stats {
   
  overflow: hidden;
  
  .stats {
    
    &__damage-armor {
      float: left;
      margin-right: 5em;
    }

    &__speed {
      float: right;
      text-align: right;
    }
    
    &__list-item:first-child {
      margin-top: $gap;
    }

    &__dps {
      float: none;
      clear: both;
    }

    &__secondary {
      color: $uncommon;
    }
    
  }

}

.wow-item__enchantments {
  
  margin: $gap*2 0;
  
  .enchantments {
     
    &__enchant {
      
      color: $uncommon;
      
    }
    
    &__socket {
      
      @include socket();
      text-indent: 1.8em;
      text-transform: capitalize;
      
      &.socket--meta {
        @include socket( "meta" );
      }
      
      &.socket--blue {
        @include socket( "blue" );
      }
      
      &.socket--red {
        @include socket( "red" );
      }
      
      &.socket--yellow {
        @include socket( "yellow" );
      }
      
      &.socket--prismatic {
        @include socket( "prismatic" );
      }
      
    }
    
    &__sockets {
      
      margin: $gap 0;
      
    }
    
    &__socket,
    &__socket-bonus {
      
      color: $trash;
      
    }
    
  }
  
}


.wow-item__info {
  
  .info {
    
    &__chance-on-hit {
      
      color: $uncommon;
      
    }
    
    &__flavour-text {
      
      color: $flavour;
      margin-top: $gap;
      
    }
    
  }
  
}


.wow-item__bonuses {
  
  margin-top: $gap;
  
  .bonuses {
    
    &__bonus {
      
      color: $uncommon;
      margin: $gap 0 0;
      
    }
    
  }
  
}
















body,html {
  
  padding: 20px;
  background: url(https://1.bp.blogspot.com/_oda7QrZey8U/S-xfS7KHf_I/AAAAAAAAANo/Lr2dkZN6dpM/s1600/2010.05.13+Azuremyst+Isle.jpg);
  background-size: cover;
  background-position: center;
  cursor: url(http://files.simey.me/wow-cursor.png), auto;

}


.page {
  
  font-family: "friz", serif;
  font-size: 1.8em;
  font-weight: normal;
  text-align: center;
  color: white;
  text-shadow: 
     0 0 1px black,
     0 0 1px black,
     0 0 2px black,
     0 0 2px black,
     0 3px 3px black;
  margin: 0;
  
  h2 {
    margin: 0;
  }
  
  h3 {
    font-size: 0.9em;
    margin: 0 0 2em;
    opacity: 0.7;
  }
  
}


.bag {
  
  background: url(https://assets.codepen.io/13471/wow-backpack.png);
  background-color: rgba(0, 0, 0, 0.8);
  box-shadow: 0 0 62px 17px #000;
  
  width: 196px;
  height: 246px; 
  background-position: 0 0;
  
  box-sizing: border-box;
  padding: 12px 5px 5px 20px;
  margin: auto;
  
  user-select: none;
  
  header {
    
    font-family: "friz", serif;
    color: white;
    font-size: 12px;
    text-align: center;
    margin: 0 0 25px;
    
  }
  
  .wow-icon {
    
    display: inline-block;
    margin: 0px 2px 1px 0px;
    user-select: none;
    
    &:first-child {
      margin-left: 84px;
    }
    
  }
  
}
$font: "https://assets.codepen.io/13471/";
@font-face {
    font-family: 'friz';
    src: url('#{$font}friz_quadrata_regular-webfont.eot');
    src: url('#{$font}friz_quadrata_regular-webfont.eot?#iefix') format('embedded-opentype'),
         url('#{$font}friz_quadrata_regular-webfont.woff') format('woff'),
         url('#{$font}friz_quadrata_regular-webfont.ttf') format('truetype'),
         url('#{$font}friz_quadrata_regular-webfont.svg#friz_quadrataregular') format('svg');
    font-weight: normal;
    font-style: normal;
}

View Compiled
Handlebars.registerHelper("speed", function( speed ) {
  return speed.toFixed(2);
});

Handlebars.registerHelper("dps", function( damage ) {
  var damageTotal = damage.max + damage.min;
  if( damage.extras ) {
    for( var i = 0; i < damage.extras.min.length; i++ ) {
      damageTotal += damage.extras.min[i];
    }
    for( var i = 0; i < damage.extras.max.length; i++ ) {
      damageTotal += damage.extras.max[i];
    }
  }
  return ((damageTotal/2) / damage.speed).toFixed(1);
});

Handlebars.registerHelper("classes", function( array ) {
  var classes = array.toString().replace(/\s/g,"&nbsp;").replace(/,/g,", ");
  return new Handlebars.SafeString( classes );
});













var source = $("#wow-item-template").html();
var template = Handlebars.compile(source);
var $body = $("body");
var $wowIcons = $(".wow-icon");
var lastHovered;

$wowIcons.each(function(k,v) {
  
  var $this = $(this);
  var id = $this.data("item-id");
  obj = items[id];
  
  if( obj ) {
    
    if( obj.icon ) {

      $this.css({
        "background-image": "url(https://wow.zamimg.com/images/wow/icons/medium/"+ obj.icon +".jpg)"
      });
    }

    if( obj.stack ) {

      $this.append("<span class='stack'>"+obj.stack+"</span>"); 
      
    }
    
  }
  
});

$wowIcons.on("mouseover.wow", function(e) {
    
  var $this = $(this);
  var $html;
  
  if( !lastHovered || !lastHovered.is( $this ) ) {

    var id = $this.data("item-id");
    $html = $( template(items[id]) );

    $body.find(".wow-item").remove();
    $body.append( $html );

    $html.css({
      left: e.clientX + 20,
      top: e.clientY - 10
    });
    
    lastHovered = $this;
    
  } else {
    $html = $(".wow-item");
  }
  
  setTimeout(function() {
    $html.removeClass("hidden");
  },10);
  
  $this.on("mousemove.wow", function(e) {
    $html.css({
      left: e.clientX + 20,
      top: e.clientY - 30
    });
  });
  
});

$wowIcons.on("mouseout.wow",function(e) {
  $body.find(".wow-item").addClass("hidden");
  $(this).off("mousemove.wow");
});

$body.on("mouseover.wow", ".wow-item" , function(e) {
  //$(this).removeClass("hidden");
});

$body.on("mouseout.wow", ".wow-item" , function(e) {
  $(this).addClass("hidden");
});


External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. //cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js
  2. //cdnjs.cloudflare.com/ajax/libs/handlebars.js/2.0.0-alpha.4/handlebars.min.js
  3. //codepen.io/simeydotme/pen/EJfLw.js