Issue with Layering Canvases using z-index - html

I have reviewed many canvas z-index posts here, including:
HTML5 Canvas layer issue
Multi Layer Canvas HTML5
html5 - canvas element - Multiple layers
but I am not finding the answer to my issue.
I am trying to simply place one canvas directly behind another canvas. When a user clicks on the canvas, it will change the stacking order. But instead of the canvases being behind and in front of each other, they can both be seen, one on top, and one beneath it (not behind it) (see https://imgur.com/a/BcUNy).
HTML and CSS:
<div id="preview" style="visibility:hidden;">
<canvas id="cOriginal" width="2" height="1" onclick="clickCompare()" style="position:relative; z-index:2; border-style:solid; border-color: #C0C0C0 #C0C0C0 #606060 #606060;"></canvas>
<canvas id="cPreview" width="2" height="1" onclick="clickCompare()" style="position:relative; z-index:1; border-style:solid; border-color: #C0C0C0 #C0C0C0 #606060 #606060;"></canvas>
<canvas id="cSave" width="2" height="1" style="position:relative; z-index:0; border-style:solid; border-color: #C0C0C0 #C0C0C0 #606060 #606060;"></canvas>
</div>
Thank you very much!
EDIT: Updating my question to show the current problem.
HTML:
<div id="preview" style="visibility:hidden; position:relative;">
<canvas id="cOriginal" width="2" height="1" onclick="clickCompare()" style="position:absolute; z-index:2; border-style:solid; border-color: #C0C0C0 #C0C0C0 #606060 #606060;"></canvas>
<canvas id="cPreview" width="2" height="1" onclick="clickCompare()" style="position:absolute; z-index:1; border-style:solid; border-color: #C0C0C0 #C0C0C0 #606060 #606060;"></canvas>
<canvas id="cSave" width="2" height="1" style="position:absolute; z-index:0; border-style:solid; border-color: #C0C0C0 #C0C0C0 #606060 #606060;"></canvas>
</div>
CSS (centering code):
<style>
#cOriginal, #cPreview, #cSave { max-width: 100%; display: block; margin: auto; left: 0; right: 0; margin-left: auto; margin-right: auto; }
</style>
The canvases are now layered and centered. But everything following the canvases has broken. See https://imgur.com/AHG59zd. Thank you!

First time answering on SO, but I believe I have the answer to your question.
I redid the HTML and JavaScript to be as simplistic as possible, since your question seems to be at the root of it all, asking for help on changing canvas layering, so I did it as simply as I could think of, here is the code, followed by a link to the codepen:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Canvas Layering</title>
</head>
<body>
<div style="position: relative;">
<canvas id="layer1" width="100" height="100"
style="position: absolute; left: 0; top: 0; z-index: 0; background-image: url(https://static.pexels.com/photos/158780/leaf-nature-green-spring-158780.jpeg);" onclick="ChangePicture(1)"></canvas>
<canvas id="layer2" width="100" height="100"
style="position: absolute; left: 0; top: 0; z-index: 1; background-image: url(https://static.pexels.com/photos/54320/rose-roses-flowers-red-54320.jpeg);" onclick="ChangePicture(2)"></canvas>
<canvas id="layer3" width="100" height="100"
style="position: absolute; left: 0; top: 0; z-index: 2; background-image: url(https://static.pexels.com/photos/5412/water-blue-ocean.jpg);" onclick="ChangePicture(3)"></canvas>
</div>
</body>
<script>
function ChangePicture(layerNumber) {
if (layerNumber === 1) {
document.getElementById("layer1").style.zIndex = "0";
document.getElementById("layer2").style.zIndex = "2";
document.getElementById("layer3").style.zIndex = "1";
} else if (layerNumber === 2) {
document.getElementById("layer1").style.zIndex = "1";
document.getElementById("layer2").style.zIndex = "0";
document.getElementById("layer3").style.zIndex = "2";
} else if (layerNumber === 3) {
document.getElementById("layer1").style.zIndex = "2";
document.getElementById("layer2").style.zIndex = "1";
document.getElementById("layer3").style.zIndex = "0";
} else {
console.log("Failed.");
}
}
</script>
</html>
https://codepen.io/levi_blodgett/pen/KQyWoR
If you want to change what picture starts as the default, simply change the z-index for the styling inside the html.

Related

How can I create a create a hole within a DIV? [duplicate]

This question already has answers here:
Creating a hole in a <div> element
(10 answers)
Closed 7 years ago.
So say I have the following HTML structure:
<canvas></canvas>
<div class="overLay">
<button>Click me!</button>
</div>
The canvas is absolutely positioned with a negative z index, so the overlay is positioned over it (I have that much working). The issue is that I want the overlay div to have a white background, but the button to have a transparent background and show through to the canvas/body background color.
background-color:rgba(0,0,0,0);
doesn't work because it just shows the white background behind it. Any ideas on how to accomplish this effect?
The question this may have been marked as a potential duplicate of fails to account for the fact that buttons can have properties such as border-radius and offers no suitable solutions.
There's no way to create a hole inside an HTML element. A Transparent background can only be applied to an element that does not descend from a parent that has a non-transparent background.
What you could do, thought it's a little bit more complicate, is to create divs around your button, at it's same level, as siblings. Give those divs a white background, and then your transparent button should work.
I've created a sample using a table layout, where the button remains in the middle row, in the center cell. See that the button reveals the canvas background color:
canvas {
width: 200px;
height: 200px;
background: purple;
position: absolute;
z-index: -1;
}
.overLay {
width: 200px;
height: 200px;
display: table;
}
.overLay button {
background-color: Transparent;
white-space: nowrap;
}
.overLay > div {
display: table-row;
}
.overLay > .middle {
height: 1px;
}
.overLay > div > div {
display: table-cell;
text-align: center;
}
.overLay > .middle > div:nth-child(2) {
width: 1px;
}
/* Now, set the background on the divs around the button */
.top, .left, .right, .bottom {
background: white;
}
<canvas></canvas>
<div class="overLay">
<div class="top">
<div></div>
<div></div>
<div></div>
</div>
<div class="middle">
<div class="left"></div>
<div>
<button>Click me!</button>
</div>
<div class="right"></div>
</div>
<div class="bottom">
<div></div>
<div></div>
<div></div>
</div>
</div>
Since in my original answer, you pointed the intention of using a border radius. So there's another approach to make this possible.
Based on this asnwer
Make the overlay with a gradient radius background, that creates the gradient color center in the position where you want the button to be, at the button's size. Make the outer color as white, and the inner color as Transparent;.
Then, set your button's position. (I did this by centering it in a table layout):
canvas {
width: 200px;
height: 200px;
background: purple;
position: absolute;
z-index: -1;
}
.overLay {
width: 200px;
height: 200px;
display: table;
background-color: white;
background: -webkit-radial-gradient(50% 50%, circle, transparent 25px, white 0px);
background: radial-gradient(50% 50%, circle, transparent 25px, white 0px);
}
.overLay > div {
display: table-cell;
text-align: center;
vertical-align: middle;
}
button {
background-color: transparent;
border-radius: 50%;
width: 50px;
height: 50px;
position: relative;
}
<canvas></canvas>
<div class="overLay">
<div>
<button>Click me!</button>
</div>
</div>
Mmm..., have you thought about using an SVG element with a mask. That should do the trick. Take a look at the snippet.
body {
padding: 0;
margin: 0;
}
.your-canvas {
position: absolute;
top: 0;
left: 0;
z-index: -1;
}
button {
width: 150px;
height: 100px;
background-color: transparent;
color: white;
cursor: pointer;
}
<div class="your-canvas">
<img width="512" alt="Weingarten Kuppel 8" src="//upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Weingarten_Kuppel_8.jpg/512px-Weingarten_Kuppel_8.jpg"/>
</div>
<svg height="324" width="512">
<defs>
<mask id="mask">
<rect width="512" height="324" fill="white"/>
<rect x="181" y="112" width="150" height="100" fill="black"/>
</mask>
</defs>
<rect width="512" height="324" style="fill:rgba(255,0,0,.6);" mask="url(#mask)"/>
<foreignObject class="node" x="181" y="112" width="150" height="100">
<body xmlns="http://www.w3.org/1999/xhtml">
<button>Click Me</button>
</body>
</foreignObject>
</svg>
As far as i know it is even possible to use masking in pure css, but haven't had the time to look it up. Here is some information on using masks with svg Clipping and masking.
Have fun.
You could...
Reduce a canvas element to button size (== a button-canvas!),
Use CSS to position the button-canvas as desired over the div,
Add a click event listener on the canvas,
Draw whatever design you need on the button-canvas.
This way you have complete flexibility using the amazing drawing tools available with the canvas element.
Here's example code and a (fanciful) Demo.
While this demo is just for fun, you can easily restyle this example & turn it into a reusable widget:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var width=80;
var height=40;
var borderwidth=4;
var x=0;
var y=0;
x+=borderwidth;
y+=borderwidth/2;
var w=width-borderwidth-borderwidth;
var h=height-borderwidth;
var depth=5;
//
var stopCount=8;
var angle=0;
var angleDelta=360;
//
var labelColor='black';
canvas.width=width;
canvas.height=height;
requestAnimationFrame(animate);
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseUp(e);});
function makeGradient(){
var g=ctx.createLinearGradient(0,0,cw,0);
for(var i=0;i<stopCount;i++){
var stop=i/stopCount;
var hslDegrees=(angle+angleDelta*stop)%360;
var hsl="hsl(" + hslDegrees + ",100%, 50%)"
g.addColorStop(stop,hsl);
}
return(g);
}
function animate(){
ctx.clearRect(0,0,cw,ch);
gradientBorder();
ctx.font='12px verdana';
ctx.fillStyle=labelColor;
ctx.fillText('Click Me',x+10,y+25);
angle++;
requestAnimationFrame(animate);
}
//
function gradientBorder(){
var lw=ctx.lineWidth
var ss=ctx.strokeStyle;
ctx.lineWidth=borderwidth;
ctx.strokeStyle=makeGradient();
//
ctx.beginPath();
ctx.moveTo(x+w-depth,y);
ctx.lineTo(x+depth,y);
ctx.bezierCurveTo( x-depth/2,y+h*1/6, x+depth*2,y+h*2/6, x,y+h/2);
ctx.bezierCurveTo( x+depth*2,y+h*4/6, x-depth/2,y+h*5/6, x+depth,y+h);
ctx.lineTo(x+w-depth,y+h);
ctx.bezierCurveTo( x+w+depth/2,y+h*5/6, x+w-depth*2,y+h*4/6, x+w,y+h/2);
ctx.bezierCurveTo( x+w-depth*2,y+h*2/6, x+w+depth/2,y+h*1/6, x+w-depth,y);
ctx.closePath();
ctx.stroke();
//
var b2=borderwidth/2;
ctx.beginPath();
ctx.moveTo(x+w-depth-1,y+b2);
ctx.lineTo(x+depth+2,y+b2);
ctx.bezierCurveTo( x-depth/2+b2+2,y+h*1/6+1, x+depth*2+b2,y+h*2/6, x+b2+1,y+h/2);
ctx.bezierCurveTo( x+depth*2+b2,y+h*4/6+1, x-depth/2+b2+1,y+h*5/6, x+depth+b2-2,y+h-b2);
ctx.strokeStyle='#666';
ctx.lineWidth=0.50;
ctx.moveTo(x+depth+b2-2,y+h-b2);
ctx.lineTo(x+w-depth-2,y+h-b2);
ctx.bezierCurveTo( x+w+depth/2-b2-2,y+h*5/6, x+w-depth*2-b2+1,y+h*4/6, x+w-b2-2,y+h/2);
ctx.bezierCurveTo( x+w-depth*2-b2+1,y+h*2/6, x+w+depth/2-b2-2,y+h*1/6, x+w-depth-b2+3,y+b2);
ctx.strokeStyle='#666';
ctx.lineWidth=0.50;
ctx.stroke();
//
ctx.strokeStyle=ss;
ctx.lineWidth=lw;
ctx.fillStyle='gainsboro';
ctx.fill();
}
function handleMouseDown(e){ labelColor='red'; }
function handleMouseUp(e){ labelColor='black'; }
body{ background-color:white; }
.demo{
width:200px;
height:100px;
border:1px solid red;
position:relative;
}
#canvas{
position:absolute;
left:10px;
top:10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class='demo'>
<canvas id="canvas"></canvas>
</div>

How to set canvas on top of image in html

Say I have a index.html with a canvas in it:
<html>
<head>
</head>
<body style="text-align: center;background: #f2f6f8;">
<div style="display:inline-block;width:auto; margin: 0 auto; background: black; position:relative; border:5px solid black; border-radius: 10px; box-shadow: 0 5px 50px #333">
<canvas id="gameCanvas" width="320" height="480"></canvas>
</div>
</body>
</html>
and the canvas is showing ok this way ~~~
Now I want to put a image as background behind the canvas and I tried to add a img tag in the body:
<html>
<head>
</head>
<body style="text-align: center;background: #f2f6f8;">
<img src="xxx.png" alt="" />
<div style="display:inline-block;width:auto; margin: 0 auto; background: black; position:relative; border:5px solid black; border-radius: 10px; box-shadow: 0 5px 50px #333">
<canvas id="gameCanvas" width="320" height="480"></canvas>
</div>
</body>
</html>
but then the canvas appeared to show after the image not on top of it ...
I really know nothing about html I think it should not be that hard to get this done, hope someone can give a hand here, thanks :)
Live Demo
You just need to use z-index. I put the image and the canvas element in a container, and position them so the canvas will always be over the image.
Also another note, you shouldn't size your canvas using CSS, you should always do it via the properties directly. In my fiddle I did it via JS.
Markup
<div id="container">
<img class='img' src="http://lorempixel.com/320/480/" alt="" />
<canvas id="gameCanvas" width="320" height="480"></canvas>
</div>
CSS
body{text-align: center;background: #f2f6f8;}
.img{position:absolute;z-index:1;}
#container{
display:inline-block;
width:320px;
height:480px;
margin: 0 auto;
background: black;
position:relative;
border:5px solid black;
border-radius: 10px;
box-shadow: 0 5px 50px #333}
#gameCanvas{
position:relative;
z-index:20;
}
you can draw image in canvas like this , rather than putting canvas on image
var topMap = new Image();
topMap.src = "myiamge.jpeg";
function drawMap() {
context.clearRect(0, 0, WIDTH, HEIGHT);
context.drawImage(topMap, 0, 0);
}
function init() {
drawMap();
}
topMap.onload = function() {
init();
}
You can set a background image for the canvas with background-image: url('xxx.png'); but the background won't be displayed if the user presses View image in the browser.
<canvas style="background-image: url('xxx.png');"id="gameCanvas" width="320" height="480"></canvas>
Or use JavaScript like Pranay Rana said (it's better if you have other levels or if you have to change the background later) :)

How do I place an image behind another, and then slide it up?

I currently have two images "IMAGE A" and "IMAGE B". As of right now my intention is to fade in IMAGE A and then fade in IMAGE B behind it (all while remaining centered on the page). However, instead IMAGE B seems to be pushing up IMAGE A as it appears. I'm using z-index, but I might be doing it incorrectly because it isn't quite working out.
After fading in IMAGE B, correctly I also want to slide it right above IMAGE A. Thanks for your help!
I attached a jsfiddle to better demonstrate what is going on: http://jsfiddle.net/YQwZ6/
HTML:
<style type="text/css">
</style>
<script src="http://code.jquery.com/jquery-1.4.4.min.js" type="text/javascript">
</script>
<script type="text/javascript">
$(document).ready(function() {
$('#pocket').hide().delay(1000).fadeIn(3000).delay(2000);
$('#pop').hide().delay(1000).fadeIn(8000).delay(2000);
});
</script>
<body>
<center>
<div id="pics" align="center">
<table width="100%" height="100%" cellpadding="0" cellspacing="0" border="0">
<tr>
<td valign="middle" align="center">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td height="200">
<center>
<div id="pocket" style="z-index:5000"><a><img src="http://www.cjboco.com/assets/page-extras/cj-flashy-slideshow/image_a.jpg"/></a>
</div>
<div id="pop" style="z-index:100"><a><img src="http://www.cjboco.com/assets/page-extras/cj-flashy-slideshow/image_b.jpg"/></a>
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</div>
CSS:
body {
margin-left: 0px;
margin-top: 0px;
margin-right: 0px;
margin-bottom: 0px;
background-color: #FFFFFF;
background-repeat: repeat;
color: #333366;
}
#pocket, #pop {
position:relative;
display: none;
float:center;
}
#pics {
}
Change this
$('#pocket').hide().delay(1000).fadeIn(3000).delay(2000);
$('#pop').hide().delay(1000).fadeIn(8000).delay(2000);
To this
$('#pocket').hide().delay(1000).fadeIn(8000).delay(2000);
$('#pop').hide().delay(1000).fadeIn(3000).delay(2000);
And this
#pocket, #pop {
position:relative;
To this
#pocket, #pop {
position:absolute;
left: 0;
top: 0;
Now, just position the images where you want them to appear. If they need to be centered, use them inside a DIV that is relatively positioned, so you can use margin: 0 auto; to center it.
Working a bit into your HTML, I cleaned it to this:
HTML
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-1.4.4.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#pocket').hide().delay(1000).fadeIn(8000).delay(2000);
$('#pop').hide().delay(1000).fadeIn(3000).delay(2000);
});
</script>
</head>
<body>
<div id="pics" align="center">
<div id="pocket" style="z-index:5000"><a><img src="http://www.cjboco.com/assets/page-extras/cj-flashy-slideshow/image_a.jpg"/></a></div>
<div id="pop" style="z-index:100"><a><img src="http://www.cjboco.com/assets/page-extras/cj-flashy-slideshow/image_b.jpg"/></a></div>
</div>
</body>
</html>
CSS
#pics {
position: relative;
width: 200px;
margin: 10px auto;
}
#pocket, #pop {
position:absolute;
left: 0;
top: 0;
display: none;
float:center;
}
EDITED:
See this example now:
SEE DEMO
If yes, then some changes given below:
CSS:
#pocket, #pop {
display: none;
float:center;
}
#pocket {
position:relative;
z-index: 2;
top: 0px;
}
#pop {
position:absolute;
z-index: 1;
top: 180px;
}
Remove z-index values from the HTML code given below:
<div id="pocket" style="z-index:5000">
and
<div id="pop" style="z-index:100">
Use jQuery:
$('#pocket').hide().delay(1000).fadeIn(1000).delay(500);
$('#pop').hide().delay(1000).fadeIn(4000).delay(500).fadeOut(500).animate({
'z-index' : 3
}, 500).fadeIn(500);

Is it possible to style a mouseover on an image map using CSS?

I have an image on a web page that also requires links. I am using an image map to create the links and I am wondering if there is a way to style the area shape on mouseover for a minor touch of interactivity. Is this possible?
I tried this without success:
html
<img src="{main_photo}" alt="locations map" usemap="#location-map" />
<map name="location-map">
<area shape="rect" coords="208,230,290,245" href="{site_url}locations/grand_bay_al" />
<area shape="rect" coords="307,214,364,226" href="{site_url}locations/mobile_al" />
<area shape="rect" coords="317,276,375,290" href="{site_url}locations/loxley_al" />
</map>
css
area { border: 1px solid #d5d5d5; }
Any suggestions?
CSS Only:
Thinking about it on my way to the supermarket, you could of course also skip the entire image map idea, and make use of :hover on the elements on top of the image (changed the divs to a-blocks). Which makes things hell of a lot simpler, no jQuery needed...
Short explanation:
Image is in the bottom
2 x a with display:block and absolute positioning + opacity:0
Set opacity to 0.2 on hover
Example:
.area {
background:#fff;
display:block;
height:475px;
opacity:0;
position:absolute;
width:320px;
}
#area2 {
left:320px;
}
#area1:hover, #area2:hover {
opacity:0.2;
}
<a id="area1" class="area" href="#"></a>
<a id="area2" class="area" href="#"></a>
<img src="http://upload.wikimedia.org/wikipedia/commons/thumb/2/20/Saimiri_sciureus-1_Luc_Viatour.jpg/640px-Saimiri_sciureus-1_Luc_Viatour.jpg" width="640" height="475" />
Original Answer using jQuery
I just created something similar with jQuery, I don't think it can be done with CSS only.
Short explanation:
Image is in the bottom
Divs with rollover (image or color) with absolute positioning + display:none
Transparent gif with the actual #map is on top (absolute position) (to prevent call to mouseout when the rollovers appear)
jQuery is used to show/hide the divs
$(document).ready(function() {
if ($('#location-map')) {
$('#location-map area').each(function() {
var id = $(this).attr('id');
$(this).mouseover(function() {
$('#overlay' + id).show();
});
$(this).mouseout(function() {
var id = $(this).attr('id');
$('#overlay' + id).hide();
});
});
}
});
body,
html {
margin: 0;
}
#emptygif {
position: absolute;
z-index: 200;
}
#overlayr1 {
position: absolute;
background: #fff;
opacity: 0.2;
width: 300px;
height: 160px;
z-index: 100;
display: none;
}
#overlayr2 {
position: absolute;
background: #fff;
opacity: 0.2;
width: 300px;
height: 160px;
top: 160px;
z-index: 100;
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<img src="http://www.tfo.be/jobs/axa/premiumplus/img/empty.gif" width="300" height="350" border="0" usemap="#location-map" id="emptygif" />
<div id="overlayr1"> </div>
<div id="overlayr2"> </div>
<img src="http://2.bp.blogspot.com/_nP6ESfPiKIw/SlOGugKqaoI/AAAAAAAAACs/6jnPl85TYDg/s1600-R/monkey300.jpg" width="300" height="350" border="0" />
<map name="location-map" id="location-map">
<area shape="rect" coords="0,0,300,160" href="#" id="r1" />
<area shape="rect" coords="0,161,300,350" href="#" id="r2"/>
</map>
Hope it helps..
With pseudo elements.
HTML:
<div class="image-map-container">
<img src="https://upload.wikimedia.org/wikipedia/commons/8/83/FibonacciBlocks.png" alt="" usemap="#image-map" />
<div class="map-selector"></div>
</div>
<map name="image-map" id="image-map">
<area alt="" title="" href="#" shape="rect" coords="54,36,66,49" />
<area alt="" title="" href="#" shape="rect" coords="72,38,83,48" />
<area alt="" title="" href="#" shape="rect" coords="56,4,80,28" />
<area alt="" title="" href="#" shape="rect" coords="7,7,45,46" />
<area alt="" title="" href="#" shape="rect" coords="10,59,76,125" />
<area alt="" title="" href="#" shape="rect" coords="93,9,199,122" />
</map>
some CSS:
.image-map-container {
position: relative;
display:inline-block;
}
.image-map-container img {
display:block;
}
.image-map-container .map-selector {
left:0;top:0;right:0;bottom:0;
color:#546E7A00;
transition-duration: .3s;
transition-timing-function: ease-out;
transition-property: top, left, right, bottom, color;
}
.image-map-container .map-selector.hover {
color:#546E7A80;
}
.map-selector:after {
content: '';
position: absolute;
top: inherit;right: inherit;bottom: inherit;left: inherit;
background: currentColor;
transition-duration: .3s;
transition-timing-function: ease-out;
transition-property: top, left, right, bottom, background;
pointer-events: none;
}
JS:
$('#image-map area').hover(
function () {
var coords = $(this).attr('coords').split(','),
width = $('.image-map-container').width(),
height = $('.image-map-container').height();
$('.image-map-container .map-selector').addClass('hover').css({
'left': coords[0]+'px',
'top': coords[1] + 'px',
'right': width - coords[2],
'bottom': height - coords[3]
})
},
function () {
$('.image-map-container .map-selector').removeClass('hover').attr('style','');
}
)
https://jsfiddle.net/79ebt32x/1/
I don't think this is possible just using CSS (not cross browser at least) but the jQuery plugin ImageMapster will do what you're after. You can outline, colour in or use an alternative image for hover/active states on an image map.
http://www.outsharked.com/imagemapster/examples/usa.html
Here's one that is pure css that uses the + next sibling selector, :hover, and pointer-events. It doesn't use an imagemap, technically, but the rect concept totally carries over:
.hotspot {
position: absolute;
border: 1px solid blue;
}
.hotspot + * {
pointer-events: none;
opacity: 0;
}
.hotspot:hover + * {
opacity: 1.0;
}
.wash {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: rgba(255, 255, 255, 0.6);
}
<div style="position: relative; height: 188px; width: 300px;">
<img src="http://demo.cloudimg.io/s/width/300/sample.li/boat.jpg">
<div class="hotspot" style="top: 50px; left: 50px; height: 30px; width: 30px;"></div>
<div>
<div class="wash"></div>
<div style="position: absolute; top: 0; left: 0;">A</div>
</div>
<div class="hotspot" style="top: 100px; left: 120px; height: 30px; width: 30px;"></div>
<div>
<div class="wash"></div>
<div style="position: absolute; top: 0; left: 0;">B</div>
</div>
</div>
You can do this by just changing the html. Here's an example:
<hmtl>
<head>
<title>Some title</title>
</head>
<body>
<map name="navigatemap">
<area shape="rect"
coords="166,4,319,41"
href="WII.htm"
onMouseOut="navbar.src='Assets/NavigationBar(OnHome).png'"
onMouseOver="navbar.src='Assets/NavigationBar(OnHome,MouseOverWII).png'"
/>
<area shape="rect"
coords="330,4,483,41"
href="OT.htm"
onMouseOut="navbar.src='Assets/NavigationBar(OnHome).png'"
onMouseOver="navbar.src='Assets/NavigationBar(OnHome,MouseOverOT).png'"
/>
<area shape="rect"
coords="491,3,645,41"
href="OP.htm"
onMouseOut="navbar.src='Assets/NavigationBar(OnHome).png'"
onMouseOver="navbar.src='Assets/NavigationBar(OnHome,MouseOverOP).png'"
/>
</map>
<img src="Assets/NavigationBar(OnHome).png"
name="navbar"
usemap="#navigatemap" />
</body>
</html>
In some browsers (chrome, edge) Area::hover::after css is supported.
Something like this should work:
<style>
#a1::hover::after {
position:absolute;
display:block;
content: ' ';
border: 2px solid red;
top: 10px;
left: 10px;
width: 20px;
height: 20px;
}
</style>
<map name="image-map" id="image-map">
<area id="a1" alt="" title="" href="#" shape="rect" coords="10,10,20,20">
</map>
<img src="foo.png" usemap="#image-map" />
See this fiddle:
https://jsfiddle.net/6z2w9trL/4/
Sorry to jump on this question late in the game but I have an answer for irregular (non-rectangular) shapes. I solved it using SVGs to generate masks of where I want to have the event attached.
The idea is to attach events to inlined SVGs, super cheap and even user friendly because there are plenty of programs for generating SVGs. The SVG can have a layer of the image as a background.
http://jcrogel.com/code/2015/03/18/mapping-images-using-javascript-events/
You could use Canvas
in HTML, simply add a canva
<canvas id="locations" width="400" height="300" style="border:1px solid #d3d3d3;">
Your browser can't read canvas</canvas>
And in Javascript (only an example, that will draw a rectangle on the picture)
var c = document.getElementById("locations");
var ctx = c.getContext("2d");
var img = new Image();
img.src = '{main_photo}';
img.onload = function() { // after the pic is loaded
ctx.drawImage(this,0,0); // add the picture
ctx.beginPath(); // start the rectangle
ctx.moveTo(50,50);
ctx.lineTo(200,50);
ctx.lineTo(200,200);
ctx.lineTo(50,200);
ctx.lineTo(50,50);
ctx.strokeStyle = "sienna"; // set color
ctx.stroke(); // apply color
ctx.lineWidth = 5;
// ctx.closePath();
};

How to let an HTML image overlap another

<div class="mainRunner">
<img src="../App_Themes/Default/images/a.gif" />
<img src="../App_Themes/Default/images/b.gif" />
</div>
I want b.gif to overlap a.gif rather than go on a new line - how can I achieve this?
You would have to use positioning and z-index to get this to work, with changing the images to block level elements and adding a class:
.mainRunner {
border: 1px solid #000;
}
.img1 {
border: 1px solid #f00;
position: relative;
z-index: 2;
}
.img2 {
border: 1px solid #0f0;
position: relative;
z-index: 1;
top: -12px;
left: -12px;
}
<div class="mainRunner">
<img class="img1" src="http://t0.gstatic.com/images?q=tbn:ANd9GcTG4mTuuZmylqn_qqviXFh5EPLD_DTsXMIjXT-4XJM0QPtJxw7lXw&t=1" />
<img class="img2" src="http://t0.gstatic.com/images?q=tbn:ANd9GcTG4mTuuZmylqn_qqviXFh5EPLD_DTsXMIjXT-4XJM0QPtJxw7lXw&t=1" />
</div>
Make sure the the containing element (wrapping div) has relative positioning applied.
div.mainRunner { position:relative;}
After this you can do one of the following.
Apply a class name to each image so you can map to it with absolute positioning.
div.mainRunner img.classname { position:absolute; top:__; left:__;}
Lastly apply z-index to the image class.
div.mainRunner img.classname { position:absolute; top:__; left:__; z-index:50;}
And for the second image;
div.mainRunner img.classname { position:absolute; top:__; left:__; z-index:51;}
If you have no control over applying classes to the images then do this (on the assumption that only 2 images will be in this div;
div.mainRunner img.classname:first-child { position:absolute; top:__; left:__; z-index:50;}
div.mainRunner img.classname { position:absolute; top:__; left:__; z-index:51;}
You could use absolute positioning (please don't), or negative margins with display:inline.
<div style="float:right">
<svg width="338" height="104">
<clipPath id="myContainer">
<rect width="338" height="104"></rect>
</clipPath>
<image width="338" height="104" xlink:href="https://www.edoardovignati.it/wp-content/uploads/2021/06/overlap-sunset.png" clip-path="url(#myContainer)"></image>
<image width="338" height="104" xlink:href="https://www.edoardovignati.it/wp-content/uploads/2021/06/overlap-mountain.png" clip-path="url(#myContainer)"></image>
</svg>
</div>
References: https://www.edoardovignati.it/solved-overlap-images-in-html/