Changing the order in which <div>'s overlap each other with jQuery mouse-click events - javascript

I'm trying to make specified div's on my page interactive and thus, change focus (come to the foreground if you will) when clicked. Essentially, I would like the div's to act much like the windows do on a computer running Microsoft Windows.
This is what I've come up with so far using z-index and it does work, sort of. The problem is that the div's appear to have their own "order" so to speak when it comes to overlapping each other based on where they are placed in the HTML.
For instance, if you click "Div2" then "Div1", you can see that "Div2" ends up actually going back behind "Div3" rather than staying in front of it as it previously was. I'd like order to be retained as clicked. If you click Div2, it should be in the front, then you click Div1 and it would then be in front of Div2, etc.
Any ideas on a way around this would be greatly appreciated. Thank you in advance!
// Global vars
var lastFocused;
// When left mousedown on a ".window" element, remove the ".window-focus" class from id
// specified in the global var "lastFocused". Next, update the global var "lastFocused"
// with the most recently clicked element id. Lastly, add the ".window-focus" class to
// the id specified in global var "lastFocused".
$('.window').mousedown(function () {
$(lastFocused).removeClass('window-focus');
lastFocused = "#" + $(this).attr("id");
$(lastFocused).addClass('window-focus');
});
// Make all ".window" elements resizable and draggable.
$('.window').draggable({containment: '#container'}).resizable({containment: '#container'});
html, body, #container {
height: 100%;
width: 100%;
font-family: Roboto;
background-color: #333;
color: #c9c9c9;
font-size: 1em;
overflow: hidden;
}
.window {
position: absolute !important;
border: 1px solid #999;
background-color: #222;
height: 100px;
width: 100px;
z-index: 1;
}
#div1 { top: 20px; left: 20px; }
#div2 { top: 60px; left: 60px; }
#div3 { top: 100px; left: 100px; }
.window-focus { z-index: 2; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<div class="window" id="div1">ONE</div>
<div class="window" id="div2">TWO</div>
<div class="window" id="div3">THREE</div>

Your issue is that you are always giving the the currently clicked div a z-index of 2, which does bring it to the front, but then when you remove that class from an element it simply goes back to it's original z-index. You need that last-applied z-index not to change and have the next-clicked element get a z-index that is one higher than the previous one.
Just keep track of the last z-index assigned to the last-clicked div element and increment it by one after each assignment so that the next clicked element will get a higher z-index assigned to it.
NOTES:
There is no need for the lastFocused variable, the .window-focus
CSS selector, or to assign a z-index:1 to the .window elements.
You were exactly right about elements having an implicit z-index
based on where they are in the HTML. For sibling elements, the z-index is simply based on the sequence. The earlier in the sequence, the lower the z-index. But, it's more complex when you start working with elements that don't share the same parent. See the stacking context for details.
JQuery recommends using the element.on("eventName", callback)
method rather than event-specific methods (i.e.
element.mousedown(callback)).
It's probably not a good idea to use a class name of .window for
elements that are not the window object. It will cause confusion. For something like this, a class name of stackable or draggable seems appropriate.
var highestZ = 3; // There are 3 divs, so highest z-index in use is initially 3
// When any of the div.stackable elements get clicked...
$('.stackable').on("mousedown", function () {
$(this).css('z-index', ++highestZ); // Clicked div gets a z-index one higher than prevous highest
});
// Make all ".stackable" elements resizable and draggable.
$('.stackable').draggable({containment: '#container'}).resizable({containment: '#container'});
html, body, #container {
height: 100%;
width: 100%;
font-family: Roboto;
background-color: #333;
color: #c9c9c9;
font-size: 1em;
overflow: hidden;
}
.stackable {
position: absolute !important;
border: 1px solid #999;
background-color: #222;
height: 100px;
width: 100px;
user-select:none;
cursor:pointer;
}
#div1 { top: 20px; left: 20px; }
#div2 { top: 60px; left: 60px; }
#div3 { top: 100px; left: 100px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<div class="stackable" id="div1">ONE</div>
<div class="stackable" id="div2">TWO</div>
<div class="stackable" id="div3">THREE</div>

Related

Target upper div with lower div

I want the background of upperdiv to become red when lowerdiv has the .active class:
<div id="upperdiv">Text case</div>
<div id="lowerdiv" class="active">IMAGE CAROUSEL</div>
.active is being added by JavaScript. Example image.
I tried:
#upperdiv + #lowediv .active {
background: red;
}
but it's not working.
Is this possible with CSS or jQuery?
If I understand the question correctly you are trying to select the previous sibling. There is no way to do this using CSS. However, using JavaScript you can achieve the desired result. When you add the active class to the lower div, use your script to change the background color of the upper div.
See Is there a "previous sibling" CSS selector? for more information.
First I'd like to warn that OP doesn't ask to hack impossible CSS thing like previous sibling styling. So I'd ask people to read carefully question before downvote or abuse this answer.
There are two ways to get it with CSS, but you can use these ways for specific cases only. Common requirement is that both divs should come one by one.
First way is to swap divs using position attributes. I mean that lower div should come first in your HTML:
<div id="lowerdiv" class="active">IMAGE CAROUSEL</div>
<div id="upperdiv">Text case</div>
div {
position: absolute;
width: 100%;
height: 50px;
margin: 0;
left: 0;
background: orange;
}
#upperdiv {
margin-top: 0px;
}
#lowerdiv{
margin-top: 50px;
}
#lowerdiv.active + #upperdiv {
background: red;
}
<div id="lowerdiv" class="active">IMAGE CAROUSEL</div>
<div id="upperdiv">Text case</div>
And second way is to use ::before pseudo-element to put it under upperdiv as a background:
div {
position: relative;
width: 100%;
height: 50px;
margin: 0;
left: 0;
background: transparent;
}
#lowerdiv{
background: orange;
}
#lowerdiv.active:before {
content: " ";
display: block;
position: absolute;
height: 100%;
width: 100%;
bottom: 100%;
background: red;
z-index: -1;
}
<div id="upperdiv">Text case</div>
<div id="lowerdiv" class="active">IMAGE CAROUSEL</div>
Third way really exists but this is beyond conditions of the question.

Div dissappears when Dragging from one div to another with scroll overflow using jquery

I have two "DIV"s, one on the left and one on the right. The right one has draggable elements and the left one has a droppable container. Both DIV's have the CSS attribute overflow: auto, which is essential in my implementation because I need a scroll to appear in each div when either DIV overflows.
The issue is, when I drag the element in the right DIV, and move it to the left, it disappears after the edge of the DIV.
This is a sample of what I'm trying to do.
<!DOCTYPE html>
<html>
<head>
<title>Practice</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script>
$(function() {
for (var i = 1; i <= 20; i++) {
$('#right').append($('<div></div>')
.addClass('item')
.html(i));
}
$(".item").draggable({
cursor: "move",
revert: "invalid"
});
$("#bin").droppable({
drop: function(event, ui) {
var mydiv = $(ui.draggable);
$("#bin").html("Dropped");
}
});
});
</script>
<style>
#left {
border: 2px solid black;
position: fixed;
width: 49%;
height: 98%;
overflow: auto;
}
#right {
border: 2px solid black;
position: fixed;
left: 52%;
top: 2%;
width: 46%;
height: 98%;
overflow: auto;
}
#bin {
border: 2px solid black;
position: relative;
left: 12%;
top: 5%;
width: 75%;
height: 75%;
}
.item {
border: 2px solid black;
left: 12%;
top: 5%;
width: 15%;
height: 5%;
}
</style>
</head>
<body>
<div id="left">
<div id="bin">
</div>
</div>
<div id="right">
</div>
</body>
</html>
You need to remove the overflow:auto in your CSS. You will then see the item will be visible when dragging between the divs then.
In order to accomplish the functionality you'd like, you need an outer div wrapping the two container boxes. You'd set an fixed height on the outer div, then use overflow-y:scroll to get your functionality.
You can do as others have suggested, but I've always found the best way to accomplish this is to set the draggable item to position:fixed
see for example:
https://jsfiddle.net/gregborbonus/tzz0927p/1/
For me personally, this allowed a lot more flexibility, but I also did a lot of work with responsive designs and such to make it work right.
I've edited to include overlapping div's. Added a few functions to make it more visible, like random Color, and an on hover and hover out event to make it possible to see and click each box.
https://jsfiddle.net/gregborbonus/tzz0927p/3/
With 100 and added a scroll function to make the scroll smooth. Also added a quick snippet so that the elements would only appear within the containing box.
This is different from your code, it uses 2 containers, rightc for the main container(the one that scrolls) and right for the container of all the elements. The rest is commented in the code.
https://jsfiddle.net/gregborbonus/tzz0927p/13/
so, something I realized was that the elements would still overlap the page on page load.
So, to show this working with an even shorter div and changed to compensate for onload:
https://jsfiddle.net/gregborbonus/tzz0927p/15/

Moving a button with ng-class

So I have this button which, when clicked upon, should move 480px to the right and change icon. I am using Angular JS and the changing of the icon works, but the button does not move.
This my is my HTML:
<div id="menuButton" ng-click="toggleMenu()">
<div class="hamburgerMenuButton" ng-class="menu.shown ? 'menuOpen' : 'menuClosed'">
</div>
</div>
CSS:
#menuButton {
width:52px;
height: 50px;
padding: 10px;
z-index: 1000;
position: relative;
}
#menuButton:hover {
background-color: #02CDED;
border-color: #FFFFFF;
}
.hamburgerMenuButton {
width: 32px;
height: 30px;
}
.menuOpen {
left: 480px;
background-image: url('images/arrow.png');
}
.menuClosed {
background-image: url('images/hamburger.png');
}
When I look in the developers view in Chrome I can see that the class changes on the hamburgerMenuButton div, and the property left: 480px; is added, but it just does not move. The icon does change as expected.
Add position:relative;, or position:inherit;, to the .hamburgerMenuButton.
It's not moving because it has position set to static, per default. The left does not mean anything to the element.
Though you've set position:relative; on the parent div, it just so happens that position is not an inherited property;

Should I use CSS, javascript or both to make this fixed element expand the parent element?

I know that a an element with position:fixed acts like its parent element with position:relative (Or no position specified) doesn't exist, and that's my concern. I've seen the very same question being asked here on StackOverflow, but not the very same problem.
I have a wrapper, an element with relative position, and an element with a fixed position inside the relative element. The element with fixed position should expand the element with relative position as you scroll the page, but what's happening is that when you scroll the page, the element with fixed position will go out of the main container, instead of expanding. How can I make the main element push the container element bellow, instead of getting an offset?
Fiddle
http://jsfiddle.net/T2PL5/515/
Here my code:
CSS
body {
background: #ccc;
}
.wrapper {
margin: 0 auto;
height: 600px;
width: 650px;
background: green;
}
.sidebar {
background-color: #ddd;
float: left;
width: 300px;
height: 350px;
position: relative;
}
.main {
background-color: yellow;
width: 200px;
height: 100px;
position: fixed;
margin: auto;
}
HTML
<div class="wrapper">wrapper
<div class="sidebar"> Sidebar
<div class="main">main</div>
</div>
</div>

Why isn't overlay working on all images?

I'm coding an image overlay w/ jQuery, and I got it working (somewhat). If you hover over the first image, it successfully appears; however, if you hover over the second one, it doesn't even work. I don't even know what the problem is! I think it has to do with unique IDs or whatever. I tried classes, and it didn't work.
Here is the fiddle :: http://jsfiddle.net/PFWcz/7/
$(document).ready(function () {
$('.overlay-link').mouseover(function () {
$(this).find('.overlay').fadeIn(200);
}).mouseleave(function () {
$(this).find('.overlay').fadeOut(200);
});
});
There are a few issues. As esqew pointed out, you're using the same IDs, which must be unique.
Addressing that, you'll still see the "same" overlay in your fiddle (http://jsfiddle.net/PFWcz/7/), but it's actually not - you're just now seeing a positioning issue.
Take a look at this fiddle:
http://jsfiddle.net/PFWcz/10/
You'll notice that when you hover over the first image, the red overlay is "1", and when you hover over the second image, the overlay is "2".
Previously (with the "helloooooo" text), the red overlays appeared the same (because of the content and positioning)...
Address the ID and position issues, and it should work.
Here's a fiddle demonstrating fixed position and ID:
http://jsfiddle.net/PFWcz/16/
The main changes is giving the container (<div>) positioning:
div {
float: left;
margin: 30px;
position: relative;
}
Also, I removed offsets (left, top) and floats, applying those to the parent container. A quick, simple fix.
You need to make your overlay-link elements your containers from which child elements inherit positions.
<a class="overlay-link">
<img src="https://d13yacurqjgara.cloudfront.net/users/67256/screenshots/1191507/shooot.png"/>
<span class="overlay"><i>hellllllllooooooo</i></span>
</a>
Your overlay-link class needs to have position: relative and will define the position and size of it and its children:
.overlay-link {
position: relative;
display: block;
width: 292px;
height: 219px;
margin: 30px;
}
Any child inside needs to have position: absolute and its width and height set to 100% of the container:
img {
position: absolute;
border-radius: 2px;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.overlay {
background-color: rgba(223, 71, 71,0.70);
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
border-radius: 2px;
display: none;
text-align:center;
}
Now when you hover over an element, it will create the overlay over that element and not the other one as you were experiencing earlier.
Jsfiddle: http://jsfiddle.net/PFWcz/14/
You're using the same id, which must be unique. Use the class attribute.
As some of the answered already said there is issue with the id's, I don't want to repeat. Since you have a multiple place where you want to show some text on rollover, using class would be a better solution/way to go ahead with.
Here is the change I did in the fiddle:
.overlay-link { /*This class is added. Since an absolute positioned element places itself relative to its parent who is either a relative positioned element or an absolute positioned element. I made the parent of the .overlay div relative.*/
position: relative;
background-color: #ff0;
}
.overlay {
position: absolute;
background-color: rgba(223, 71, 71,0.70);
left: -322px; /*Positioning the .overlay element based on its parents left*/
width: 292px;
height: 219px;
border-radius: 2px;
top: 30px;
display: none;
text-align:center;
}
.overlay i { /*There is no .shot element in the DOM. I replaced it by .overlay*/
background-color: #df4747;
border-radius: 999px;
padding: 10px;
width: 60px;
height: 60px;
color: #fff;
font-size: 30px;
top: 80px;
left: 116px;
position: absolute;
display: block;
}
This is based on my understanding. Let me know if it works.
Here, this is what you want
Fiddle: http://jsfiddle.net/D33Yk/
$(window).on('load',function () {
$('.overlay-link').mouseover(function(){
var overlay = $(this).children('.overlay');
var img = $(this).children('img');
$(overlay).css('left',$(img).offset().left);
$(overlay).css('top',$(img).offset().top);
$(overlay).css('width',$(img).width());
$(overlay).css('height',$(img).height());
$(overlay).fadeIn(200);
}).mouseleave(function(){
$(this).children('.overlay').fadeOut(200);
});
});
Because you had the overlay positioned absolutely in CSS, both overlays always covered the first image. I now set the left, top, width and height in JS, so the overlays cover their respective image.
I also changed this in CSS:
.overlay {
display: none;
position: absolute;
background-color: rgba(223, 71, 71,0.70);
border-radius: 2px;
text-align:center;
}
removed the top, left, width, height
...and this in HTML (I changed both, but I only show one since they are identical):
<div>
<a class="overlay-link">
<img src="https://d13yacurqjgara.cloudfront.net/users/67256/screenshots/1191507/shooot.png"/>
<span class="overlay"><i>hellllllllooooooo</i></span>
</a>
</div>
changed all the id's to classes, and removed id where it was not necessary

Categories