Pass click through to fixed element - javascript

I have a static element that is above a fixed element. When the upper static element is clicked, I want to pass this click through to the fixed element. How can I do this? Here is a working example (I wasn't able to get this to work in JSFiddle).
<body>
<div class="lower" onclick="lowerClick()"></div>
<div class="upper" onclick="upperClick()"></div>
</body>
<script>
function lowerClick() {
alert("LOWER CLICK");
};
function upperClick() {
alert("UPPER CLICK");
};
</script>
//CSS file
.lower {
height: 100px;
width: 100%;
z-index: -1;
position: fixed;
background-color:blue;
}
.upper {
height: 50px;
width: 100%;
z-index: 1;
position: static;
background-color:red;
pointer-events: none;
}
I thought that adding pointer-events:none to my upper element would make this work, but when I click the top element, nothing happens.

In fact pointer-events:none works expectedly. But what prevents you from clicking on the lower is the body element. Because of setting z-index:-1 on your lower, it will be sent to behind of its parent (which is the body). So you can set the z-index of the body to a more negative number, of course the postion should be some value other than static (default):
body {
z-index:-1000;
position:relative;
}
Demo

You can use the following css for the upper div
.upper {
pointer-events:none;
}
...also avoid negative z-index, and instead use 1 for lower and 2 for upper. Also why put static and not absolute element at the top?

Related

How to remove a div but prevent the scroll position to be changed?

What do i want to achive?
I want to remove a div which isnt visible(for the user not the css atribute) anymore on the screen because i let the html and body scroll to a div with jquery(scrollTop). Now i want to remove the div which was visible beforr i scrolled down with jquery.
Edit: After removing the .header div, the #begining should be the top of the page and the .header div should be removed forever.
What is the problem?
After i scrolled down and removed the div with the following line of code: $('.header').css('display','none'); the scroll position changes.
Code to scroll down and remove the div.
function scrollToBegining(){
$('html, body').animate({
scrollTop: $("#begining").offset().top
}, 750);
setTimeout(function(){
$('.header').css('display','none');
},750);
}
Problem visualized:
GIF of the problem (Watch to understand better)
This is odd, but I think a better choice is to slideUp the div instead of scrolling:
function scrollToBegining(){
$('.header').slideUp(750);
}
Obviously, rename the function since it's no longer scrolling.
You can use visibility: hidden to hide the div but reserve its space. Also, sometimes the scroll position has to be changed when you use display: none.
visibility: hidden
is what you are looking for, but another solution I use with this kind of issue is instead of scrolling down to your second div, have the initial div shrink its height in a uniform animation until it is 0. This prevents the weird shuddering scroll issue you are experiencing
document.querySelector('#header h1').addEventListener('click', closeHeader)
function closeHeader(){
document.querySelector('#header').classList.add("hidden");
}
#header {
height: 300px;
width: 100%;
background: red;
text-align: center;
}
#content {
height: 1000px;
width: 100%;
background: yellow;
text-align: center;
}
.hidden {
display: none !important;
margin: 0 !important;
padding: 0 !important;
}
<div id="header">
<h1>
HEADER
</h1>
</div>
<div id="content">
CONTENT
</div>

Change image on click of mouse by passing class name from one element to the next

I have a situation where I want to change the background image when I click the mouse. I want to remove the class from one element and add the same class to the next element. Then based on that particular class name, I want to perform fadeIn and fadeOut using jquery. However, only the first image is changed when I use the class. When I click the second image, it wont change. But when I replace the class with div, background image changes on each click until it reaches the last image. Can anyone help me understand what I am missing. Thank you.
$(function(){
$("div").not(".active").hide();
$(".active").click(function(){ //When I change .active to div, it works.
$(this).fadeOut(function(){
$(this).removeClass("active");
$(this).next().addClass("active");
$(this).next().fadeIn()
})
})
})
body, html{
height: 100%;
width:100%;
background-color: yellow;
}
#one{
background:url("../Images/one.jpg") fixed center no-repeat;
width:100%;
height: 100%;
}
#two{
background:url("../Images/two.jpg");
width:100%;
height: 100%;
}
#three{
background:url("../Images/three.jpg");
width:100%;
height: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div id="one" class="active"></div>
<div id="two"></div>
<div id="three"></div>
</body>
You need to use on() instead of click() because you are adding the class dynamically.
$(function(){
$("div").not(".active").hide();
$("body").on('click', '.active', function(){ //When I change .active to div, it works.
$(this).fadeOut(function(){
$(this).removeClass("active");
$(this).next().addClass("active");
$(this).next().fadeIn()
})
})
})
Maybe you need to use .delegate
change your code like this:
$('body').delegate('.active', 'click', function() {
$(this).fadeOut(function() {
$(this).removeClass("active");
$(this).next().addClass("active");
$(this).next().fadeIn()
})
})
or you change bind the click on body to judge the e.target
see the details here delegate
You may do it like this:
first add specific class .bg-div to these divs because targeting ALL divs with this $("div") is so generic and it'll hide everything other than the active one, in case you have other divs they'll be hidden.
hide all divs with class .bg-div except the one which has .active.
on click event, you can still target bg-div div because there's only one which has .active class, since all other bgDivs are hidden already from the previous step. fadeOut() this one.
increase the counter index by one.
now if the value of index equals the length -number - of bgDivs, then reset the coutner to 0, this is for when you're showing the last bg-div.
fadeIn() the next div.
jsFiddle 1
$(function() {
var bgDivs = $(".bg-div"),
index = 0;
bgDivs.not(".active").hide();
bgDivs.on('click', function() {
$(this).fadeOut('fast');
index += 1;
// if the counter value is less than the number of bgDivs, keep this value
// else, set it to 0 and start over because we're on the last div
index = (index < bgDivs.length) ? index : 0;
$(bgDivs[index]).fadeIn('fast');
});
})
body,
html {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
background-color: yellow;
}
.bg-div {
width: 100%;
height: 100%;
}
#one {
background: url("//dummyimage.com/1000x700?text=one") fixed center no-repeat;
background-size: cover;
}
#two {
background: url("//dummyimage.com/1000x700?text=two") fixed center no-repeat;
background-size: cover;
}
#three {
background: url("//dummyimage.com/1000x700?text=three") fixed center no-repeat;
background-size: cover;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<body>
<div id="one" class="bg-div active"></div>
<div id="two" class="bg-div"></div>
<div id="three" class="bg-div"></div>
</body>
Update 1:
You'd notice there's a moment where the horizontal scrollbar appears when while switching the background div, this is because these divs are stacked under each others but when hidden there's no problem, the problem only appears the moment you switch the background div, to fix this add these lines to your .bg-div CSS:
position:absolute;
top:0;
left:0;
jsFiddle 2
Update 2:
You can totally get rid of .active class and don't rely on it if you add generic display:none; to your .bg-div CSS, then in the #one rule add display:block. by doing this you no more need this line:
bgDivs.not(".active").hide();
jsFiddle 3
This is useful not only because of less code, but also the background divs other than the first one will be hidden when the page first load from the beginning since it's in the CSS and not wait until your js script to hide them

expanding an inline-block jumps to above row

I have a series of articles
<section>
<article>1</article>
<article>2</article>
<article>3</article>
....
<article>999</article>
<section>
arranged in a grid of three per row
section {
position: relative
}
article {
display: inline-block;
width: 33%;
}
and I want that they expand horizontally to fully occupy its row when clicked.
so I create an expanded class
.expanded {
position:absolute;
left:0px;
width: 100%;
}
and apply it on click
$("article").click(function(){
$(this).toggleClass("expanded");
});
I am almost there, as you can see in the fiddle here http://jsfiddle.net/aqw339r0/1/
When I click on any of the articles they expand to the full width of the row; but the problem is that when I click the first article of a row (except the first row) it "jumps" to the row immediately above.
I have tried changing the position and display attributes of both article and .expanded but I cannot get the behavior I need. For example: When I change the position:absolute of .expanded, the blocks 5 and 6, "jump" to the row below. Similar when I remove display:inline-block and change to float:left.
Do you have any ideas of why this happens and how to correct it?
Using the solution from #Rick (minus the css top edit) and then toggling an additional element to keep other elements in place, this should do what is needed: Fiddle
$("article").click(function() {
$(this).toggleClass("expanded");
if ($(this).hasClass("expanded"))
{
$(this).before("<article class='blank'> </article>");
}
else
{
$(this).prevAll('.blank').first().remove();
}
});
To explain further, when the element is clicked:
if ADDING the class 'expanded', then this will also add a blank article element (before) as a placeholder to keep the flow consistent. This is important because when the element with class 'expanded' becomes position: absolute it is removed from the normal flow of the content.
if REMOVING the class 'expanded', then this will also remove the blank article placeholder element. The prevAll function looks through all previous elements with the class 'blank' and then takes the first() one and removes it. Because it was inserted 'before', this is guaranteed to remove the correct blank article placeholder.
When position:absolute is set on an <article> element, that takes it out of the normal content flow, and causes the offset. We can correct it by adding an empty <article> as a placeholder when the click triggers, and removing it when click again.
var open = false;
jQuery("article").click(function () {
open = !open;
if (open) {
$(this).addClass("expanded");
$(this).before("<article class='holder'> </article>");
} else {
$("article").removeClass("expanded");
$(".holder").remove();
}
});
p.s. I'm not that good at jQuery, any suggestions are welcome.
jsfiddle
I can't think of a pure CSS solution, but since you're using jQuery anyway, simply hard-code the expanded element's top:
$("article").click(function() {
$(this).css('top', $(this).position().top);
$(this).toggleClass("expanded");
});
Fiddle
The top style will be ignored once the expanded class is removed.
Try this
<section>
<article>1</article>
<article>2</article>
<article>3</article>
</section>
<section>
<article>4</article>
<article>5</article>
<article>6</article>
<section>
<section>
<article>7</article>
<article>8</article>
<article>9</article>
</section>
section {
position:relative;
}
article {
width: 30%;
min-width: 200px;
min-height: 200px;
display: inline-block;
border: 1px solid black;
}
.expanded {
width: 100%;
background-color:#eef;
left:0px;
top:0;
position:absolute;
transition: 0.2s linear;
}
// if you want others to close while expanding
$("article").click(function(){
$('article').removeClass("expanded");
$(this).toggleClass("expanded");
});
// esle if you want everything to be expanded
$("article").click(function(){
$(this).toggleClass("expanded");
});

How to make a partially hidden div?

I want to make a half shown div in a page, like a footer. When I click it I want it to slide up. The div will contain information on it.
I achieved this somehow, but my problem is that the div does not get really hidden it just changes the position.
You can find the demo here: http://jsfiddle.net/8ZFMJ/394/
var clicked=false;
$(".two").on('click', function(){
if(clicked)
{
clicked=false;
$(".two").css({"bottom": -430});
}
else
{
clicked=true;
$(".two").css({"bottom": "-200px"});
}
});
I had a similar problem a while ago, in fact I think it was my first stackoverflow question. Unfortunately it got poorly received.
Anyway, the problem is currently that you are just changing the position of the div - that's what .bottom does. I think what you want to do is change the height, see this JSFiddle in which I managed to switch the div between states (no animation yet).
It makes simple use of css's overflow-y: hidden; to hide the div's contents when it is small, and all the JS does is toggle between heights:
if(clicked)
{
$(".two").css("height", 10);
}
else
{
$(".two").css("height", 250);
}
clicked = !clicked;
clicked = !clicked just flips the boolean state of the variable.
Now, to add the animation, we can use jQuery's .animate and produce this beautiful Fiddle
Basically, all we had to do in between is use animate instead of css. Simple, really.
TL;DR
final JSFiddle
.two must be absolute positioned inside .container that must be relative positioned. Then you just change the bottom with a negative value and that will hide the footer.
CSS:
html, body { height: 100%; }
.container {
position: relative;
height: 100%;
overflow: hidden;
}
.two {
position: absolute;
background-color: yellow;
width: 100%;
height:250px;
bottom: -200px;
transition: bottom 1s;
}
jQuery:
var clicked=false;
$(".two").on('click', function(){
if(clicked)
{
clicked=false;
$(".two").css({"bottom": "-200px"});
}
else
{
clicked=true;
$(".two").css({"bottom": 0});
}
});
http://jsfiddle.net/8ZFMJ/398/

scrollTop & scrollLeft do not work on display:none elements

I'm trying to scroll an hidden element before I show it. This is the code i'm working with:
<div class="main">
<div class="bg">
</div>
</div>
.main {
display:none;
position:abolsute;
width:250px;height:250px;
overflow:scroll;
}
.bg {
background: blue url(http://defaulttester.com/img/bg-landing-mario.jpg);
width:1200px;
height:800px;
}
$(".main").scrollTop($(".bg").height()/2);
$(".main").scrollLeft($(".bg").width()/2);
IT works fine if its showing but if its display:hidden it will simple not work. Is there anyway to avoid this and make it work?
JSFiddle: http://jsfiddle.net/dpjzJ/
Use visibility: hidden; or some class like this instead:
.hide {
position: absolute !important;
top: -9999px !important;
left: -9999px !important;
}
Or this (from Boilerplate):
.visuallyhidden {
position: absolute;
overflow: hidden;
clip: rect(0 0 0 0);
height: 1px; width: 1px;
margin: -1px; padding: 0; border: 0;
}
Something with display: none; has no location on the page, as you probably knew.
Check out this article on the subject.
If your goal is to just set scrollLeft and scrollTop to 0(since that was my goal), one very hacky solution is to follow these steps:
Get a reference to the element you want to reset.
Get a reference to the element's parent.
Remove the element from the parent.
Append the element back to the parent.
scrollTop and scrollLeft will now be set back to 0 even though they are invisible.
function resetScroll(element) {
element.parentElement.replaceChild(element,element)
}
This will set both scrollTop and scrollLeft to 0 even if display none.
Example use:
resetScroll(document.getElementById("my_scroll"))
It's not ideal, but the way I solved this is to add a one-time IntersectionObserver that triggers the first time the element becomes visible. Here's a function to add a callback for when an element first becomes visible:
function onVisible(element, callback) {
new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if(entry.intersectionRatio > 0) {
callback(element);
observer.disconnect();
}
});
}).observe(element);
}
And use it like this:
let myElement = document.querySelector("#myElement");
// When the element first becomes visible, scroll it to 500px:
onVisible(myElement, el=>el.scrollTop=500);
Example: https://jsbin.com/gigumewemo/edit?html,output

Categories

Resources