Javascript knocks out CSS:hover? - javascript

Hi im trying to make the Product Categories menu work on this page:
http://www.jaybrand.co.uk/p1.html
at the moment the page loads and CSS hover works to set the background position so that the graphic behind makes a roll over effect.
i put some javascript to set the background position to the roll over on click, but this knocks out the CSS hover:
onclick="setStyle('c1','backgroundPosition','0px 0px');
it means that c1:hover no longer works.. i tried putting !important in the CSS c1:hover background position and this fixed it in Firefox but not IE.
How can i write something in Javascript to also say:
onclick="setStyle('c1:hover','backgroundPosition','-276px 0px');
......... i know Javascript does not do hyphens and the way to get for example "background-position" in CSS is to ditch the hyphen and make "P"osition capitol. perhaps something can be done also to get to the CSS hover attribute?

When you set an element's style.backgroundPosition, it's the same as setting an inline style="background-position: ..." attribute. Since inline style attributes override stylesheet rules, the hover/non-hover rules can never again affect the background position.
You could remove the backgroundPosition rule for elements being unselected so that the stylesheet rules can shine through. But really, your code needs a serious refactoring: manually setting every background position in the onclick is ugly and unmaintainable.
Instead, switch a class around to flag the selected link, eg. styled like this:
.c { background: url(...); }
#c1.selected, #c1:hover { background-position: -276px 0; }
#c2.selected, #c2:hover { background-position: -276px -61px; }
...
markup:
<h2><a class="c selected" id="c1" href="#productcats">Products</a></h2>
<a class="c" id="c2" href="#rice">Rice</a>
...
(a-inside-h2 because the other way around is invalid.)
script:
var selected= $('#c1');
$('.c').click(function() {
// Move the 'selected' class to the new element
//
selected.removeClass('selected');
selected= $(this);
$(this).addClass('selected');
// Scroll target element into view
//
var y= $(this.hash).offset().top-$('#slide').offset().top;
$('#slide').animate({top: -y+'px'}, {duration: 450, queue: false});
return false;
});
Note this uses the href of the links to point to where they go, which will improve accessibility on non-visual browsers. You should also add some code to look at the location.hash on page load and if you see something there, scroll that page into view. Otherwise, it will be impossible to bookmark one of your subpages, or to middle-click-new-tab the links or anything like that.

I was doing something similar the other day, not 100% sure but this might help push you in the right direction..
onclick="document.getElementById('c1:hover').style.cssText='backgroundPosition: -276px 0px;';"

Related

Event listener does not work when image element blocks it [duplicate]

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.

jQuery Add & Remove Class Div Width

How can i add/remove class according as div width ? I tried some codes but I have no idea about jquery codes. I'd like add div class according as antoher div width. Just i need add class like that. If container is smaller than 600px "add class" to content div else "remove class" from content div. These are my codes;
<div class="container">
<div class="content"></div>
</div>
$(window).resizeboxes(function() {
if ($(".container").width < 600){
$( ".content" ).addClass( ".content_600" );
}
});
else{
removeClass('.content_600')
}
$(window).trigger('resizeboxes');
This works, though the code is changed slightly. There were some problems with the syntax also, so I've corrected those (for instance the else statement was slightly misplaced). Here is a working example:
https://jsfiddle.net/vt0nbx36/3/
Here is the code:
var resizeboxes = function() {
if ($(".container").width() < 600)
{
$(".content").addClass("content_600");
}
else
{
$(".content").removeClass("content_600")
}
};
resizeboxes();
$(window).resize(function(){
resizeboxes();
});
For this need exactly, you have jQuery's .toggleClass() function. It takes the class name as a first parameter, and optional second boolean parameter that states wether the class name should be added or removed. You can find the documentation here
$(".content").toggleClass("content_600", ($(".container").width() < 600));
Even tho your question is a JS related question, CSS as a matter of fact can handle this like no other beast can (mostly)!
CSS allows you to use media-queries to resize your content based on the width of the viewport.
The upside of this is that the browser will handle this for you within the rendering engine rather than having JS between your change and the rendering engine.
The major downside is that you can't define the width of element A based on element B but are unfortunately locked to using the viewport as an indicator.
Before I explain why you'd want to use CSS I'd like to point out why you don't want to use JS for this if possible.
The jQuery.resize eventhandler fires inconsistently across browsers and it fires alot of times usually.
This causes your scrolling to clog up and make your webpage feel laggy.
If there's anything your users will dislike it's the fact that scrolling is controlled by something they don't even know of which is slowing you down.
As for a CSS solution, a media query looks like this:
.my-selector {
width: 900px;
}
#media all and (max-width: 600px) {
.my-selector {
width: 600px;
...
}
}
You wrap your code in a sort-of conditional that allows you to be very flexible with manipulating elements on the page.
What happens in the above piece of code is that when the parser reads the CSS it sees the first selector not in a media query so it applies width: 900px; then it sees a media query and sees the other rule for my-selector however it will only apply that rule when the screen is at that width we defined in the #media ... rule. When you resize CSS handles things differently behind the scenes so it's much faster than JS in that case.
I'm not sure if it actually applies to your situation but if your container is sized by the viewport rather than parent elements this should be possible and I thought it'd be nice atleast to show you a good way of playing with element dimensions.
Also, you can use #media to for instance make a webpage print friendly by changing the all to print for example and setting the background-color: transparent for an element - saves ink ^.^ which is an additional extra on top of the general awesomeness of media queries.
Hope it helps, good luck if you wish to make your webpage 5 times faster ;)

Making flip effect on hover, on blur go fade with CSS + jQuery

I have to do something like pexeso. When you hover element, it will flip front to back side (they have different texts) and when your mouse is out, it will fade from back to front side. This is example HTML, how it looks like:
<div class="pexeso">
<div class="pad">
<div class="front">1</div>
<div class="back">ONE</div>
</div>
etc...
There is some CSS, to look it well (it is in the jsFiddle source, attached bellow). Then Handling mouse enter and leave with jQuery:
$('.pexeso .pad').each(function() {
var el = $(this);
var back = el.find('.back');
el.on('mouseenter', function() {
back.removeAttr('style');
el.removeClass('before-fade').addClass('do-flip');
});
el.on('mouseleave', function() {
el.removeClass('do-flip').addClass('before-fade');
back.stop(true, true).fadeOut(250, function() {
el.removeClass('before-fade');
});
});
});
Here is full example in jsFiddle: DEMO
Try to hover any element from left or right side of your screen, it will works great. But now try to hover from top or bottom, it will do weird things to graphic and also, sometimes it stucks and remains invisible.
Probably know the problem: When you hover from top or bottom, it will start flipping, and when you are too slow, it also fires event mouseleave, because flipping is in progress and you are actually at empty space. Then it calls 1st function, then second, a lot of time and it got stuck. But I don't know how to fix it, can you help me?
Ok guys, don't try anymore, I already found a solution. Whoever is interested, how I fixed it, here is solution:
In CSS, make .back element always visible, so find this line &.do-flip { and add this style .back { display: block !important; }
In jQuery, there is no need to have back.removeAttr('style');, also this did mess with opacity style (fading effect)
Now wrap every "pad" with parent, for example .pad-container and give him exact sizes as .pads, now we will manipulate with him
Each function will take these wrappers, not "pads", so in jQuery $('.pexeso .pad-container').each(function() {...
Bind events mouseenter and mouseleave on this wrapper, but changing classes remain on "pads" and fadeOut effect on back element. Also, add function .show() to this back element before fadeOut.
That's all. Here is updated version: UPDATED DEMO

html5: link to the #id of a div at a certain point on the page

I have a responsive header that I'm working on for a site that turns into a fixed-position navbar as you scroll down. It takes up roughly the upper quarter of the page.
The content of the page is in a series of divs / cards that slide up as you scroll down.
I want to add <a href> links to the navbar that correspond to the ids of the divs. However, when I do so, the div content moves to the top of the page.
So I get something like the following when I navegate to /localhost#first_card
---- TOP OF PAGE
[<div id="first_card"> begins here]
---- bottom border of navbar
[<div id="first_card"> continues here]
when what I really want is this:
---- TOP OF PAGE
---- bottom border of navbar
[<div id="first_card"> begins here]
Is there a way to control where on the page the hash link might render the <div id="first_card"> after navigating to /localhost#first_card?
I've been trying to solve this for you in JSFiddle for a bit now, and from what I can find, the best way would be to box all the cards into a seperate element with overflow:auto
The result of this, and as proof of it working can be found at http://jsfiddle.net/Entoarox/TT2JN/
This may not work for your site, but the only alternative is using javascript to solve this and I cant recommend that because it would cause a massive load on the visitors PC due to most hash related javascript functionality being either static or very new, meaning that to support older browsers, you'd need to manually poll if the hash has changed, either taking up a lot of CPU time, or having a very slow response to when the hash has changed.
Try the jQuery scrollTop() command. This will give you the precise positioning that you need.
http://api.jquery.com/scrollTop/
You might have to change your links up a little. Example with jQuery and a wrapper div:
<a id="first-card-jump" href="#first_card">Jump to First Card</a>
<div id="wrapper">
NAVBAR
first div
second div
...
nth div
</div>
<script>
$('a#first-card-jump).on('click', function(event) {
event.preventDefault(); // Not sure if this is needed
$('div#wrapper).scrollTop(500); // you have to measure how far down you want to scroll
});
</script>
Note that this might mess up your in-page back button support. Not sure if that's an issue for you.
p.s. If you're in time trouble, the simplest fix is to add a top margin to each div equal to the height of the fixed navbar.
Hope this helps!
I made you a jsfiddle
it uses padding-top to create the offset to the top, then it uses margin-bottom to remove the offset between the elements.
the relevant css:
/*
add top padding and substract the same amount from bottom margin
*/
.card {
padding-top: 200px;
margin-bottom: -200px;
position: relative;
}
/*
we need to reverse the stacking for this solution, so the elements later in
the document don't cover the elements before
either you know how many cards you have, so you can solve this in a central
css file (like below)
or you must add the stacking upon creation (in your template)
or use the javascript
starts from 2 because nav is :nth-child(1) in this example
*/
.card:nth-child(2){
z-index: 0;
}
.card:nth-child(3){
z-index: -1;
}
.card:nth-child(4){
z-index: -2;
}
javascript to reverse the stacking, using jQuery
$(function(){ //on load
$('body>.card').each(function(i, elem){$(elem).css('z-index', -i)})
})
If I understand your question correctly, you want to make a div appear in the middle of the page, right? So, to do this, you can just direct the page to the div above it. You can also make another div above it with a fixed height.

jQuery sliding animation inside a word

I'm toying around with jQuery/jQuery-ui, and I'd like to do something : say we have a word, when I hover the first letter, I'd like to see a few letters slide in (and out when the mouse goes somewhere else) between the first letter and the rest of the word. So FSecond would become FirstSecond, with "irst" sliding.
I'm almost there, but there's a slight problem : the sliding letters are sliding below the word, and once the sliding is done, they are at the right place. Same thing for the sliding out : the animation itself is not taking place between the first letter and the rest of the word.
Here is the code, quite short : http://pastebin.com/FdTtmV7k. I checked the jquery-ui doc and there's a mention of an options hash to give to the toggle function, but I can't seem to find any doc on this one and what to put in it.
I also noticed a few similar questions left unanswered (see jQuery slideToggle() applies display:block while sliding and https://stackoverflow.com/questions/4090796/jquery-ui-show-moves-elements-during-animation).
Thanks for your time !
This demo should do what you require. The problem exists as jQuery assigns display:block to an element when animating it, which causes your <span> to be rendered as a block-level element.
This happens because the <span> containing the "irst" text will have the CSS display property changed to block when the sliding begins, while the other 2 <span> elements used for "F" and "Second" will keep their default, which is inline.
You can solve this by changing the <span> elements to <div> elements (these are block elements) and additionally apply float: left; CSS style to them.
The new HTML code:
<h3>
<div id="initial">F</div><div id="middle" style="display: none">irst</div><div id="name">Second</div>
</h3>
And the new CSS code:
#initial, #middle, #name { float: left; }
Adding this CSS fixed it for me. The reasoning is that jQuery wraps your span in a div while animating it, and that div has display:block by default. We take advantage of the fact that they did not set an inline display style on the element and set the class to have display:inline-block.
.ui-effects-wrapper {
display:inline-block;
}
EDIT: Something was messing up my span tags, no margin modifications are needed.

Categories