I have a div that has background:transparent, along with border. Underneath this div, I have more elements.
Currently, I'm able to click the underlying elements when I click outside of the overlay div. However, I'm unable to click the underlying elements when clicking directly on the overlay div.
I want to be able to click through this div so that I can click on the underlying elements.
Yes, you CAN do this.
Using pointer-events: none along with CSS conditional statements for IE11 (does not work in IE10 or below), you can get a cross browser compatible solution for this problem.
Using AlphaImageLoader, you can even put transparent .PNG/.GIFs in the overlay div and have clicks flow through to elements underneath.
CSS:
pointer-events: none;
background: url('your_transparent.png');
IE11 conditional:
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='your_transparent.png', sizingMethod='scale');
background: none !important;
Here is a basic example page with all the code.
Yes, you CAN force overlapping layers to pass through (ignore) click events.
PLUS you CAN have specific children excluded from this behavior...
You can do this, using pointer-events
pointer-events influences the reaction to click-, tap-, scroll- und hover events.
In a layer that should ignore / pass-through mentioned events you set
pointer-events: none;
Children of that unresponsive layer that need to react mouse / tap events again need:
pointer-events: auto;
That second part is very helpful if you work with multiple overlapping div layers (probably some parents being transparent), where you need to be able to click on child elements and only that child elements.
Example usage:
.parent {
pointer-events:none;
}
.child {
pointer-events:auto;
}
<div class="parent">
I'm unresponsive
I'm clickable again, wohoo !
</div>
Allowing the user to click through a div to the underlying element depends on the browser. All modern browsers, including Firefox, Chrome, Safari, and Opera, understand pointer-events:none.
For IE, it depends on the background. If the background is transparent, clickthrough works without you needing to do anything. On the other hand, for something like background:white; opacity:0; filter:Alpha(opacity=0);, IE needs manual event forwarding.
See a JSFiddle test and CanIUse pointer events.
I'm adding this answer because I didn’t see it here in full. I was able to do this using elementFromPoint. So basically:
attach a click to the div you want to be clicked through
hide it
determine what element the pointer is on
fire the click on the element there.
var range-selector= $("")
.css("position", "absolute").addClass("range-selector")
.appendTo("")
.click(function(e) {
_range-selector.hide();
$(document.elementFromPoint(e.clientX,e.clientY)).trigger("click");
});
In my case the overlaying div is absolutely positioned—I am not sure if this makes a difference. This works on IE8/9, Safari Chrome and Firefox at least.
Hide overlaying the element
Determine cursor coordinates
Get element on those coordinates
Trigger click on element
Show overlaying element again
$('#elementontop').click(e => {
$('#elementontop').hide();
$(document.elementFromPoint(e.clientX, e.clientY)).trigger("click");
$('#elementontop').show();
});
I needed to do this and decided to take this route:
$('.overlay').click(function(e){
var left = $(window).scrollLeft();
var top = $(window).scrollTop();
//hide the overlay for now so the document can find the underlying elements
$(this).css('display','none');
//use the current scroll position to deduct from the click position
$(document.elementFromPoint(e.pageX-left, e.pageY-top)).click();
//show the overlay again
$(this).css('display','block');
});
I currently work with canvas speech balloons. But because the balloon with the pointer is wrapped in a div, some links under it aren't click able anymore. I cant use extjs in this case.
See basic example for my speech balloon tutorial requires HTML5
So I decided to collect all link coordinates from inside the balloons in an array.
var clickarray=[];
function getcoo(thatdiv){
thatdiv.find(".link").each(function(){
var offset=$(this).offset();
clickarray.unshift([(offset.left),
(offset.top),
(offset.left+$(this).width()),
(offset.top+$(this).height()),
($(this).attr('name')),
1]);
});
}
I call this function on each (new) balloon. It grabs the coordinates of the left/top and right/down corners of a link.class - additionally the name attribute for what to do if someone clicks in that coordinates and I loved to set a 1 which means that it wasn't clicked jet. And unshift this array to the clickarray. You could use push too.
To work with that array:
$("body").click(function(event){
event.preventDefault();//if it is a a-tag
var x=event.pageX;
var y=event.pageY;
var job="";
for(var i in clickarray){
if(x>=clickarray[i][0] && x<=clickarray[i][2] && y>=clickarray[i][1] && y<=clickarray[i][3] && clickarray[i][5]==1){
job=clickarray[i][4];
clickarray[i][5]=0;//set to allready clicked
break;
}
}
if(job.length>0){
// --do some thing with the job --
}
});
This function proofs the coordinates of a body click event or whether it was already clicked and returns the name attribute. I think it is not necessary to go deeper, but you see it is not that complicate.
Hope in was enlish...
Another idea to try (situationally) would be to:
Put the content you want in a div;
Put the non-clicking overlay over the entire page with a z-index higher,
make another cropped copy of the original div
overlay and abs position the copy div in the same place as the original content you want to be clickable with an even higher z-index?
Any thoughts?
I think the event.stopPropagation(); should be mentioned here as well. Add this to the Click function of your button.
Prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event.
Just wrap a tag around all the HTML extract, for example
<a href="/categories/1">
<img alt="test1" class="img-responsive" src="/assets/photo.jpg" />
<div class="caption bg-orange">
<h2>
test1
</h2>
</div>
</a>
in my example my caption class has hover effects, that with pointer-events:none; you just will lose
wrapping the content will keep your hover effects and you can click in all the picture, div included, regards!
An easier way would be to inline the transparent background image using Data URIs as follows:
.click-through {
pointer-events: none;
background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
}
I think that you can consider changing your markup. If I am not wrong, you'd like to put an invisible layer above the document and your invisible markup may be preceding your document image (is this correct?).
Instead, I propose that you put the invisible right after the document image but changing the position to absolute.
Notice that you need a parent element to have position: relative and then you will be able to use this idea. Otherwise your absolute layer will be placed just in the top left corner.
An absolute position element is positioned relative to the first parent
element that has a position other than static.
If no such element is found, the containing block is html
Hope this helps. See here for more information about CSS positioning.
You can place an AP overlay like...
#overlay {
position: absolute;
top: -79px;
left: -60px;
height: 80px;
width: 380px;
z-index: 2;
background: url(fake.gif);
}
<div id="overlay"></div>
just put it over where you dont want ie cliked. Works in all.
This is not a precise answer for the question but may help in finding a workaround for it.
I had an image I was hiding on page load and displaying when waiting on an AJAX call then hiding again however...
I found the only way to display my image when loading the page then make it disappear and be able to click things where the image was located before hiding it was to put the image into a DIV, make the size of the DIV 10x10 pixels or small enough to prevent it causing an issue then hiding the containing div. This allowed the image to overflow the div while visible and when the div was hidden, only the divs area was affected by inability to click objects beneath and not the whole size of the image the DIV contained and was displaying.
I tried all the methods to hide the image including CSS display=none/block, opacity=0, hiding the image with hidden=true. All of them resulted in my image being hidden but the area where it was displayed to act like there was a cover over the stuff underneath so clicks and so on wouldn't act on the underlying objects. Once the image was inside a tiny DIV and I hid the tiny DIV, the entire area occupied by the image was clear and only the tiny area under the DIV I hid was affected but as I made it small enough (10x10 pixels), the issue was fixed (sort of).
I found this to be a dirty workaround for what should be a simple issue but I was not able to find any way to hide the object in its native format without a container. My object was in the form of etc. If anyone has a better way, please let me know.
I couldn't always use pointer-events: none in my scenario, because I wanted both the overlay and the underlying element(s) to be clickable / selectable.
The DOM structure looked like this:
<div id="outerElement">
<div id="canvas-wrapper">
<canvas id="overlay"></canvas>
</div>
<!-- Omitted: element(s) behind canvas that should still be selectable -->
</div>
(The outerElement, canvas-wrapper and canvas elements have the same size.)
To make the elements behind the canvas act normally (e.g. selectable, editable), I used the following code:
canvasWrapper.style.pointerEvents = 'none';
outerElement.addEventListener('mousedown', event => {
const clickedOnElementInCanvas = yourCheck // TODO: check if the event *would* click a canvas element.
if (!clickedOnElementInCanvas) {
// if necessary, add logic to deselect your canvas elements ...
wrapper.style.pointerEvents = 'none';
return true;
}
// Check if we emitted the event ourselves (avoid endless loop)
if (event.isTrusted) {
// Manually forward element to the canvas
const mouseEvent = new MouseEvent(event.type, event);
canvas.dispatchEvent(mouseEvent);
mouseEvent.stopPropagation();
}
return true;
});
Some canvas objects also came with input fields, so I had to allow keyboard events, too.
To do this, I had to update the pointerEvents property based on whether a canvas input field was currently focused or not:
onCanvasModified(canvas, () => {
const inputFieldInCanvasActive = // TODO: Check if an input field of the canvas is active.
wrapper.style.pointerEvents = inputFieldInCanvasActive ? 'auto' : 'none';
});
it doesn't work that way. the work around is to manually check the coordinates of the mouse click against the area occupied by each element.
area occupied by an element can found found by 1. getting the location of the element with respect to the top left of the page, and 2. the width and the height. a library like jQuery makes this pretty simple, although it can be done in plain js. adding an event handler for mousemove on the document object will provide continuous updates of the mouse position from the top and left of the page. deciding if the mouse is over any given object consists of checking if the mouse position is between the left, right, top and bottom edges of an element.
Nope, you can't click ‘through’ an element. You can get the co-ordinates of the click and try to work out what element was underneath the clicked element, but this is really tedious for browsers that don't have document.elementFromPoint. Then you still have to emulate the default action of clicking, which isn't necessarily trivial depending on what elements you have under there.
Since you've got a fully-transparent window area, you'll probably be better off implementing it as separate border elements around the outside, leaving the centre area free of obstruction so you can really just click straight through.
I'd like to replace the mouse cursor on my website with a custom one, composed of two elements:
a cursor;
a trail that follows the cursor and lags behind it.
Doing that with jquery is extremely easy.
1) You hide the default cursor in CSS:
html, body {cursor:none;}
2) You create two different divs (one for the cursor itself and one for the trail) and style them:
<div id="mouse_cursor" class="mouse_cursor"></div>
<div id="mouse_trail" class="mouse_trail"></div>
3) You create the logic for each one of them:
function moveCursor(e) {
$('#mouse_cursor').css({'left' : e.pageX,'top' : e.pageY });
}
$(window).on('mousemove', moveCursor);
function moveTrail(e) {
TweenMax.to('#mouse_trail', 0.35, {
css: {left: e.pageX,top: e.pageY},
ease:SlowMo.easeIn
}
)};
$(window).on('mousemove', moveTrail);
(In my case the trail effect is made using Greensock's GSAP).
Now... this works perfectly as long as the cursor style isn't changed. Here's a fiddle, for your reference: https://jsfiddle.net/collederfomento/jvy1zfg8/27/
I'd like to change the style of the cursor once it hovers specific elements, however, and that's where I am encountering a few issues.
The way I have attempted to do that is the following:
1) Create a function bound to the mouseenter \ mouseover events that adds a class to the cursor if it's hovering the element:
$(".hover").bind( "mouseenter mouseover", function() {
$("#mouse_cursor").addClass("mouse_cursor_hover");
});
2) ... and then a second function that removes the class once the cursor is not hovering the element anymore:
$(".hover").mouseleave(function() {
$("#mouse_cursor").removeClass("mouse_cursor_hover");
});
3) Lastly, of course, I added the style for the "hover" cursor:
.mouse_cursor_hover {width:300px;height:300px;}
As you can see in this fiddle ( https://jsfiddle.net/collederfomento/z4e1qjbc/13/ ) the hover event is not firing properly, and the mouse cursor flickers.
I have tried several other approaches (using Javascript event listener rather than the above mentioned functions, using the css property rather than toggling a class, etc.) but they all behave in the same way.
What's curious is that if I remove the functions that make the cursors move, then the hover event is handled flawlessly. I believe the combination of the two functions is causing the issue, but I have no clue why (or how to solve it).
I think the cursor and the trail elements are interfering with the hover events. Even though they are at a high z-index, the browser still has to take them into account to figure out which element is actually getting hovered. The mouse cursor is still going over them after all, since they are not a “real” cursor, but actual elements positioned in that place.
Adding pointer-events none to both of them seems to fix the issue for the most part (checked in Chrome and Firefox, in both it seemed to significantly improve), so please give that a try:
.mouse_cursor,
.mouse_trail {
pointer-events:none;
}
https://jsfiddle.net/aur39py4/1/
I am assuming that you are not going to need any sort of hover effect on the cursor and trail themselves, so setting pointer-events:none should not have any adverse effects on the rest of what you’re doing on the page.
Here is a jsfiddle of the problem:
http://jsfiddle.net/MEJgb/
I want it so when you hover over anywhere in the footer the toggledown will become active and will remain active until you move the mouse from the footer.
Your problem is the following line:
jQuery('html,body').animate({
scrollTop: jQuery("#footer_copy_right").offset().top
}, 'slow');
This causes the whole page to move adn thus the item you were hovering over is no longer being hovered over so it triggers your event again and hides your text. When I was testing this was causing the hover content to move back under my mouse and thus trigger again...
I would personally not use hover in this situation and let the user click to expand and then click again to collapse.
If you want to keep using the hover option then you need to decide what the event to trigger the collapse should be. Clearly the current choice (mouse no longer over the arrow) is insufficient.
Often what I will do is attach the hover to a block containing the visible triggering block as well as the contents that are going to be displayed. This way your content won't collapse until you have moved off the newly displayed content.
http://jsfiddle.net/AjHwM/ is an example of such a thing.
Even if I'm not sure what your actual goal is, maybe the document.elementFromPoint() method is what helps you out here.
It is invoked like
if( document.elementFromPoint( event.pageX, event.pageY ) === $('#footer')[0] ) { }
That code, within your hover aka mouseenter / mouseleave handlers, would compare the node which lays under the current absolute mouse cursor X/Y positions against the #footer node.
Ref.: MDN doc, W3C doc
I created a menu and I tried to use mouseover (mouseenter) and mouseout(mouseleave) but unfortunately if you move the mouse too fast some of the events are not fired and the hover images are not changed back to the original image.
I need to use mouseover and mouseout events instead of hover because I need to display the original image if the image is clicked.
Please check the demo at:
Demo link
I don't think that using two different image elements per icon is a good idea.
Single image element
You should use one element per icon and switch the class and image src when mouseover and mouseout are fired.
Like so (minimal example):
$(".side_left").mouseover(function() {
$(this).prop("src", "http://www.spiritualawakeningradio.com/yaha.jpg");
}).mouseout(function(){
$(this).prop("src", "http://img.creativemark.co.uk/uploads/images/461/13461/smallImg.png");
});
Working fiddle: DEMO
Update with CSS sprites
Here is a better example with CSS sprites. No need for JavaScript and most of the markup, only some CSS:
.side_left {
width: 60px;
height: 60px;
background: url('http://i.imm.io/mvRL.png');
}
.side_left:hover {
background-position: 60px;
}
Working fiddle: DEMO
You could try using hover for the initial change, then onclick change the class or image source.
This is happening because you are using mouse events on items that become hidden, so when you move fast enough the item isn't there to trigger the mouseout event.
I slightly modified your original code to make it work, however, you should consider scrapping the two image tags and swap between two image src attribute values or CSS using jQuery, or use pure CSS and the :hover selector.
http://jsfiddle.net/MATMD/
You could just use css and adding css-classes per JavaScript to do this.
I updated your fiddle to show you, this would reduce the needed JavaScript-Code significantly.
I kept your existing Markup, though I think this could be done with less markup too:
http://jsfiddle.net/3YBe4/12/
If you move the mouse to quickly, you're not giving the .side_left_hover element enough time to start listening to the mouse.
So how do you fix it? I would put all your mouse listeners in the .side_left/.side_left_hover container div. That will also make your code simpler and cleaner.
Here's the Fiddle: http://jsfiddle.net/rJK3R/1/
jsFiddle demo
I used the .on() method and list the mouse events needed.
You can than attach an event handler (e) and check for it's type inside the function.
.
$('img.side_left').parent('div').on('mouseenter mouseleave click', function(e){
if(e.type === 'mouseenter' || e.type==='mouseleave'){
$(this).find('img:not(.active)').toggle();
}else{ // IS CLICK
$('img.active').toggle().removeClass('active');
$(this).find('img').addClass('active');
}
});
So I'm trying to make a simple lightbox on a concert listings page. You click a listing (.performer), and then an info box (.lightboxinfo) gets overlaid while a semi-opaque white div lightens the rest of the screen (#whitepage). Then, you click anywhere on the screen, and the box and white div disappear.
Everything works fine except the final z-index changes. The box and white div become fully transparent, but the z-index clearly haven't been changed since I can't click on any links.
Anyone know what I'm doing wrong? Thanks so much!
The javascript is below:
$('.performer a').click(
function(){
$('.lightboxinfo').css('z-index','110').animate({opacity:'1'}, {queue:false,duration:500});
$('#whitepage').css('z-index','100').animate({opacity:'0.4'}, {queue:false,duration:500});
});
$(document).click(
function(){
$('#whitepage').css('z-index','-100').animate({opacity:'0'},{queue:false,duration:100});
$('.lightboxinfo').css('z-index','-110').animate({opacity:'0'},{queue:false,duration:100});
});
});
Why mess around with the z-index when you can set 'display:none' after your opacity becomes 0?
// when appearing
$('#whitepage').css('opacity','0').show().animate({opacity:'0.4'}, 500);
// when disappearing
$('#whitepage').animate({opacity:'0'}, 100, function () {
$('#whitepage').hide();
});
Also, each time you click on the performer link, you're adding another event handler to the document. You may want to do that only once, outside of the click and only if the whitepage is visible.
$('.performer a').click(function () {
});
$(document).click(function () {
$('#whitepage:visible').animate(...
});
This is a bit difficult to answer as you haven't given the HTML and CSS, but there are a few things you should probably look at.
I assume your lightbox divs are positioned absolutely. Any (container) elements that you want to appear over them must be positioned relatively or absolutely or z-index will have no effect and relatively / absolutely positioned elements will always be on top of them.
You're animating the opacity manually, rather than using jQuery's built in fadeOut animation. Apart from giving compatibility with browsers that don't support opacity, fadeOut also sets the hidden element to display: none. This allows you to click on stuff that would otherwise be underneath the lightbox, whereas just reducing the opacity to 0 still leaves the element there and able to accept and block clicks. (So using fadeOut also means you'd no longer have to toggle the z-index.)
This is not directly related to the problem you mentioned, but both of the events you've set up will fire when you click on a .performer a link. (I think this is why you've prevented the animations from being queued: both will run together and the one that sets the opacity to 1 wins as it finishes last.) This does, however, stop the lightbox getting the z-index you want. To prevent this happening, you either need to set the close lightbox click event to #whitepage or stop the event propagating.
$('.performer a').click(function(event)
{
$('.lightboxinfo, #whitepage').fadeIn(500);
event.stopPropagation();
});