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'm currently making an addon for a site, but I stumbled upon a problem:
my addon needs to simulate clicking a div, but the div only appears if you're hovering over another div. I tried
$("#id-1").trigger("mouseover");
$("#id-2").click();
but it doesn't really work because the box instantly dissapears again.
is there any way I can do this?
thanks in advance!
edit: $("#id-2") isn't just made invisible, its no longer there in the elements, they're using some code to delete it and put it back in place when you hover over $("#id-1")
If you have access to the CSS file you can use a hover class to do this, assuming they are siblings (could be modified to work with parent-child relationship) and and that they use display:block and display:hidden to hide/show the hidden element
/* CSS */
elemOne:hover ~ div, .hover ~ div { display:block; } // Applies on hover or if
// hover class
/* jQuery */
$('elemOne').addClass('hover'); // Initialize the hover state
$('elemTwo').trigger('click'); // Click the now-showing element
$('elemOne').removeClass('hover'); // Remove the hover state
Demo
So, I have an element that has some "pre-existing" behavior attached to it. So, I found that just moving it (as required by some new requirements) retains the existing behaviors = good. But the issue is, when I move the element I need to give it "new styles".
So, if I have something like this:
<div id="existingStructure">
<div id="legacyElement"></div>
</div>
Now, that has pre-existing styles attached to both. I can rearrange these styles etc.. but I can't change them. The styles are attached to the "id's" rather than a class definition. I believe I can change that if needed.
Now, I need to move "legacyElement" when certain things happen to a "new div".
I just
jQuery('#newStructure').append('#legacyElement');
<div id="newStructure">
<div id="legacyElement"></div>
</div>
Unfortunetly, the styles I have on newStructure don't seem to be applying to *legacyElement" when it gets moved here dynamically.
I was thinking of moving all the styles to a class rather than associated to the ids, and when I move it.. I just jQuery().addClass / jQuery().removeClass etc...
Is there a better/easier more robust way that I can just have the legacyElement loose its styles when it sits under existingStructure and then get new ones when moved to "newStructure" etc.. and vice versa. That element "legacyElement" will be pinging back and forth.. so, I need it to have the styles under each parent div as it goes there.
so when an action happens on page, I move it back:
jQuery('#existingStructure').append('#legacyElement');
If I am not succinct enough, please let me know.
The EXISTING styles are in an external CSS file and are like so..
#existingStructure {
// bunch of css
}
#existingStructure .item1 input[type="text"] {
// bunch of css
}
#legacyElement{
// bunch of css
}
and new styles are sorta the same except 'additional styles' might be applied.
#newStructure {
// bunch of css
}
#newStructure .item1 input[type="text"] {
// bunch of css
}
You can certainly target your div styles by their parents:
#existingStructure #legacyElement {some styles}
#newStructure #legacyElement {some other styles}
To explain futher, this arrangement should result in greater specificity, overriding styles that are simply applied to either #existingStructure or #legacyElement. I'm hoping no one did anything foolish like using !important on them.
Short answer: It should.
Here's an example I quickly made in jsFiddle: http://jsfiddle.net/CCm4J/1/
So then why isn't yours? Most likely you have css rules that are embedded that apply only when in the existingStructure id/class perhaps? Without see more of your css I'm not sure how specific I can get. I would just verify that your css rules are allowed to apply outside of existingStructure (and even that existingStructure might have rules for its parent too!)
I created TinyMCE plugin for Wordpress editor to insert Youtube videos. Everything works fine except this button has no hover state (like the default buttons have). I explored the code and found a difference - default buttons are spans with background-image sprite, and my custom button is a plain image. There's no option in TinyMCE addButton() function to insert a span, only image:
ed.addButton('p2_youtube_button', {
title : 'Insert Youtube video',
cmd : 'mceYoutube',
image: url + '/shortcode-youtube.png'
});
Is there a way to solve this little problem?
To illustrate how it looks (the red Youtube icon should be gray and turn red on hover):
http://d.pr/aszC
I noticed that the Crayon Syntax Highlighter plugin has managed to do this. It is a bit of code to read through, I found the tinyMCE specific part in /wp-content/plugins/crayon-syntax-highlighter/util/tag-editor/crayon_tinymce.js . I hope this helps.
The style which causes the highlight is here:
.wp_themeSkin span.mce_crayon_tinymce {
background: url(images/crayon_tinymce.png);
}
.wp_themeSkin .mceButtonEnabled:hover span.mce_crayon_tinymce,
.wp_themeSkin .mceButtonActive span.mce_crayon_tinymce {
background-position: -20px 0;
}
The image uses the same size as the other TinyMCE icons:
There are additional parameters you can pass to the addButton method that give you some options for how you skin your button.
If you remove the image property and replace it with icon, you can use a font-ified icon instead. This is a multi-step process, which starts with actually building your icon font. Here's a good tutorial that walks you through the process. The tutorial author recommends IcoMoon as a reliable way to build your icon fonts. There are probably others.
The way that I use is similar to #feonix83's approach, using CSS instead. Following the way WordPress itself does it, you lay your icons out in a sprite sheet, with the "hover" state 20px above the "off" state. If you don't know what I'm talking about, take a look at the defalt WordPress icon sprite sheet: wp-includes/images/wpicons.png
If you remove the image property altogether, TinyMCE just puts a span of class mceIcon inside the button anchor block. It's quite easy then to style that element and use the background-image referencing your sprite sheet. You use background-position to set the offset for the appropriate icon.
There's one additional trick that you can use to help you target only your buttons. You can add a class property to the addButton call and pass any number of classes. You will need to manually specify a specific class that can be used to target that button in particular, but you can also pass in an additional class that can be used to style all your buttons at once, since they won't automatically inherit the styles that WordPress uses.
class: "my-buttons my-specific-button"
Here's the CSS that I use. Note that this approach works best when each button has its own individual sprite sheet, as opposed to the WordPress approach that loads all the icons at once, though that approach has some performance benefits that are not to be ignored:
.mceButtonEnabled:hover span.mceIcon.my-buttons { background-position: 0 0; }
span.mceIcon.my-buttons.my-specific-button { background: url( images/my_button.png ) no-repeat 0 -20px; }
I'm using the jQuery GalleryView plugin. I've use the plugin on one page and contained it in a div with the appropriate code which sends the div's id to the external GalleryView .js file.
I'm also using jQuery to hide the div on document ready, so the users can toggle the visibility, but for some reason when the div is hidden innitially, the gallery does not load correctly. I believe this may be because the script inside the code is not being called due to it's hidden status.
I hope I have explained this clearly enough. Does anyone have any ideas?
The plugin home page can be found here or I believ the jQuery page is more up to date but not as well documented.
Most likely, the gallery has issues calculating widths/height because the elemens are hidden ..
you should either hide the elements after the gallery has initialized, or move it off-screen by CSS (initially) and once the gallery initializes, hide it and bring it back to its position..
Update
(after comments and inspecting the plugin source code)
The issue is definitely the hiding of the containing div by you at document ready event.
The true problem is that the plugin executes its code at window load and not dom ready, meaning after the images have loaded..
If you hide it before it gets executed, the plugin fails to correctly identify some properties of the images like width/height etc..
If the space the gallery occupies is the same whether it is hidden or show, then i would suggest that instead of hiding the container, to set visibility:hidden. This does not skew the properties of the images like the display:none does (its is what .hide() uses)
so
$(document).ready(){
// hide container
$('#container').css('visibility','hidden');
// plugin init call here
$('#id').galleryView({...});
}
If you need the gallery to dissapear and also free its space when hidden, then you need to call the hiding, after the plugin has completed its initialization..
$(document).ready(){
// plugin init call here
$('#id').galleryView({...});
}
$(window).load(){
// your code to hide the container of the gallery
// we use timeout to give some time for the gallery code to execute first..
setTimeout(function(){ $('#containerid').hide(); }, 100 );
}
http://docs.jquery.com/Plugins/livequery
The problem is that js does not "see" the content of elements with display: none;
The easiest solution: use position hiding instead of display: none;
Html:
<div class="hidden">...</div>
Css:
.hidden {
position: absolute !important;
left: -9999px !important;
top: -9999px !important;
}
And in js .addClass('hidden') and .removeClass('hidden') to hide or show the element
In this case this element will be "visible" for js and images to load, but hidden from user.