html, body width: 100% height: 100% .container width: 100% height: 100% position: relative background-image: url(http://www.wildlife-photography-tips.com/images/black-and-white-nature-photography-stag.jpg) background-size: cover background-repeat: no-repeat background-position: center .hot-spot width: 20px height: 20px background-color: #D29A4E border-radius: 50% position: absolute top: 50% left: 50% transform: translate(-50%, -50%) z-index: 1 opacity: 0.8 z-index: 1 &:after content: '' position: absolute top: 50% left: 50% transform: translate(-50%, -50%) border: 2px solid #D29A4E width: 20px height: 20px border-radius: 50% opacity: 0 transition: 0.2s all &:hover cursor: pointer opacity: 1 &:after width: 25px height: 25px opacity: 1 .speech-bubble position: absolute width: 150px background-color: white border-radius: 4px text-align: center display: none z-index: 2 h1 font-size: 20px margin-top: 12px color: #333333 p margin-top: 4px margin-bottom: 12px font-style: italic color: #888888 &:after top: 100% left: 50% border: solid transparent content: " " height: 0 width: 0 position: absolute pointer-events: none border-color: rgba(255, 255, 255, 0) border-top-color: #ffffff border-width: 10px margin-left: -10px var imageWidth = 2048, imageHeight = 1364, imageAspectRatio = imageWidth / imageHeight, $window = $(window); var hotSpots = [{ 'title': 'Mouth', 'description': 'scream.', 'x': -600, 'y': -180 }, { 'title': 'Body', 'description': 'Look at it.', 'x': 108, 'y': 20 }, { 'title': 'Antlers', 'description': 'They crazy.', 'x': 40, 'y': -170 }, { 'title': 'This Ear', 'description': 'It can hear things.', 'x': -265, 'y': -145 }]; function appendHotSpots() { for (var i = 0; i < hotSpots.length; i++) { var $hotSpot = $('
').addClass('hot-spot'); $('.container').append($hotSpot); } positionHotSpots(); } function appendSpeechBubble() { var $speechBubble = $('
').addClass('speech-bubble'); $('.container').append($speechBubble); } function handleHotSpotMouseover(e) { var $currentHotSpot = $(e.currentTarget), currentIndex = $currentHotSpot.index(), $speechBubble = $('.speech-bubble'), title = hotSpots[currentIndex]['title'], description = hotSpots[currentIndex]['description'], hotSpotTop = $currentHotSpot.offset().top, hotSpotLeft = $currentHotSpot.offset().left, hotSpotHalfSize = $currentHotSpot.width() / 2, speechBubbleHalfSize = $speechBubble.width() / 2, topTarget = hotSpotTop - $speechBubble.height(), leftTarget = (hotSpotLeft - (speechBubbleHalfSize)) + hotSpotHalfSize; $speechBubble.empty(); $speechBubble.append($('

').text(title)); $speechBubble.append($('

').text(description)); $speechBubble.css({ 'top': topTarget - 20, 'left': leftTarget, 'display': 'block' }).stop().animate({ opacity: 1 }, 200); } function handleHotSpotMouseout(){ var $speechBubble = $('.speech-bubble'); $speechBubble.stop().animate({ opacity: 0 }, 200, function(){ $speechBubble.hide(); }); } function positionHotSpots() { var windowWidth = $window.width(), windowHeight = $window.height(), windowAspectRatio = windowWidth / windowHeight, $hotSpot = $('.hot-spot'); $hotSpot.each(function(index) { var xPos = hotSpots[index]['x'], yPos = hotSpots[index]['y'], desiredLeft = 0, desiredTop = 0; if (windowAspectRatio > imageAspectRatio) { yPos = (yPos / imageHeight) * 100; xPos = (xPos / imageWidth) * 100; } else { yPos = ((yPos / (windowAspectRatio / imageAspectRatio)) / imageHeight) * 100; xPos = ((xPos / (windowAspectRatio / imageAspectRatio)) / imageWidth) * 100; } $(this).css({ 'margin-top': yPos + '%', 'margin-left': xPos + '%' }); }); } appendHotSpots(); appendSpeechBubble(); $(window).resize(positionHotSpots); $('.hot-spot').on('mouseover', handleHotSpotMouseover); $('.hot-spot').on('mouseout', handleHotSpotMouseout);