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
Related
Background
I have an HTML div which contains a ‘tooltip’-like feature (i.e., a text box pops up when a certain element is clicked or hovered over); this tooltip has decorative pseudo-elements to make it look like a ‘speech bubble,’ added in css as :before and :after .
I have a JS script, which is intended to show and hide the tooltip and decoration, in response to click events (i.e., toggle them between ‘show’ and ‘hide’ states).
Problem
I can’t get the decorative pseudo-elements to hide when the tooltip is hidden; as pseudo-elements, they are not part of the DOM and so I can’t use normal selectors to manipulate them.
When the tooltip is hidden on click, the decorative pseudo-elements persist, which is not a usable result.
I can’t do away with the decorative elements, they are part of the work specification.
Approach tried so far
Based on this question, my thought was to add an empty span with its own class, to which I’d prepend and append these pseudo-elements. Then, add or remove the class on click based on whether it exists already, or not.
I have also tried setting the class to which the pseudo-elements are pre/appended to display:none on click, but this also seems not to work
However, I cannot convince the pseudo-elements to hide on click.
I’ve included a screenshot of what these remnant pseudo-elements look like in the live environment.
Note: I tried to work up a running simulation for the purpose of this question, but I wasn’t able to and the original css file is massive; the code included below is for reference only.
All guidance is much appreciated!
const barContainer = document.querySelector(".bar-container");
const decorationElement = document.querySelector("#decoration");
document.addEventListener('click', function(event) {
console.log('click event listener triggered');
if (event.target.closest('.link') || event.target.classList.contains('link')) {
if (barContainer.classList.contains('open')) {
barContainer.classList.remove('open')
decorationElement.classList.remove('decoration')
document.querySelector('.tooltip-container').setAttribute('style', 'display:none');
} else {
barContainer.classList.add('open')
decorationElement.classList.add('decoration')
document.querySelector('.tooltip-container').setAttribute('style', 'display:block');
}
} else {
barContainer.classList.remove('open')
decorationElement.classList.remove('decoration')
document.querySelector('.tooltip-container').setAttribute('style', 'display:none');
}
});
.foo-container {
height: auto;
position: relative;
}
.bar-container {
height: auto;
position: relative;
text-align: center;
}
.bar-container:hover .tooltip-container,
.tooltip-container:hover,
.bar-container.open .tooltip-container {
position: absolute;
display: block;
text-align: left;
background-color: #ffffff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
bottom: 50px;
right: 5%;
border-radius: 4%;
font-weight: 300;
max-width: 90%;
font-size: 14px;
padding: 20px 0;
}
/*the below two rule sets create the rotated 'decoration' */
.bar-container:hover .tooltip-container:before,
.tooltip-container:hover:before,
.bar-container.open .tooltip-container:before,
.foo-container .bar-container:hover .decoration:before {
content: "";
width: 65px;
height: 35px;
position: absolute;
overflow: hidden;
transform: rotate(-180deg);
z-index: 10;
bottom: 0;
left: 170px;
background-color: white;
}
.foo-container .bar-container.open .decoration:before,
.foo-container .bar-container:hover .decoration:before {
content: "";
position: absolute;
width: 30px;
height: 30px;
background: #fff;
transform: rotate(45deg);
left: 30px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
z-index: 2;
top: -42px;
}
/* end 'deocration' */
<div class="foo-container">
<div class="bar-container">
<p>text <span class='link'>the-link<span id='decoration' class='decoration'></span></span>
</p>
<div class='tooltip-container'>
<p>lorem </p>
</div>
</div>
</div>
Screenshot of the undesirable 'persistent pseudo-elements' behavior -->
So I have a list with a position: fixed button in the bottom of the viewport. Because this button is position: fixed the last element of the list and part of the second last appear beneath the button, so the user can't see them properly.
What I tried so far:
adding a padding-bottom to the container with the height of the button. Issue with this approach: in different languages the height of the button is different, so it's good in only a couple of scenarios.
making the button position: sticky instead of fixed. Issue with this approach: the list is in a overflow-y: scroll container, so this approach does not work in iOS. Again, only good in a couple of scenarios.
adding a div after the list and controlling its height with javascript. Issue with this approach: does the job, but it's not very elegant.
Does anyone know of a better approach other than my third one? When I started with this I thought I might have to use JS for it, but position: sticky gave me hope that it would be possible with only CSS.
Since your list is fixed, this is an example of what I do for buttons on the bottom of my screen. Although it would be nice if you showed an example of your problem, cause it's hard to tell.
Obviously, you'll have to edit the text's positioning if you wanted, but the principle is what matters, and everything is responsive. Each individual <li> element is 10% high and 20% wide no matter the size of the screen.
CSS:
<style>
ul { position: fixed; width: 100%; height: 10%; bottom: 0%; left: 0%; background-color: deepskyblue; list-style-type: none; margin: 0; }
li { position: absolute; }
.a { width: 20%; height: 100%; background-color: red; left: 0%; }
.b { width: 20%; height: 100%; background-color: orange; left: 20%; }
.c { width: 20%; height: 100%; background-color: yellow; left: 40%; }
</style>
HTML:
<ul>
<li class="a">AAA</li>
<li class="b">BBB</li>
<li class="c">CCC</li>
</ul>
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>
I have the following structure:
<div id="hold">
<div id="hold-left">content</div>
<div id="hold-right">content</div>
</div>
hold-left floats to the left and hold-right floats to the right. The widths are 40% and 55% when the page is loaded. The thing is, hold-right is a sort of preview of something and the user needs to be able to resize it.
This is easily done using JavaScript (the user selects a zoom level radio button), however the issue I am now facing is that, if it is enlarged, it drops down beneath hold-left. What I'd like it to do is float over freely to the outside of the parent div.
How do I go about this? Can it be done through CSS at all, or do I need to dynamically resize the parent every time I resize hold-right?
Have you considered using a left margin on .hold-right?
.hold-left{
float:left;
width:40%;
}
.hold-right{
margin-left:45%;
}
Also, generally you should use classes, not IDs.
You can try with display: table, and table-cell.
The table will need to be 100% width and no width specified for table-cell. Then the content will "resize" the cells.
Otherwise, you will need to use javascript to update both cells.
Use position property in css. Checkout this
position: relative; in the parent.
position: absolute; in the each child.
#hold {
position: relative;
}
#hold-left {
position: absolute;
left: 0;
width: 100px;
height: 100px;
background: red;
}
#hold-right {
position: absolute;
right: 0;
width: 100px;
height: 200px;
background: yellow;
}
#zoomLevelSelector {
position: absolute;
top: 0;
left: 0;
z-index: 0;
}
I am using Bootstrap 3 dropdown-menu inside a dynamically generated container. The dropdown-menu appears behind the newly generated elements. See image reference.
container item position: relative; z-index: 1;
dropdown-menu position: absolute; z-index: 10000;
I also did test btn-group with a higher z-index and it did not work.
Here is a working fiddle http://jsfiddle.net/sGem8/
You don't need to add z-index property.. Simply remove it and it will work..
i.e.
#container > li {
display: block;
border-radius: 3px;
position: relative;
padding: 15px;
background: #ecf0f1;
margin-bottom: 15px;
}
Working Fiddle
I have faced the same issue.
Inside the main container which had all the nav-items, I had every outermost div items as position: relative
Only the dropdown menu had position: absolute
To make the dropdown appear above all items, add
.dropdown{
position: absolute;
z-index : 999; //some high value
}
and other items in the container have
.outer-divs{
position: relative;
z-index: 1; //some low value
}
If you still find your dropdown to behave not as expected,
try setting the div item that opens the dropdown when clicked to
.dropdown-container{
position :static;
}
Most people will find the last trick to be the most valuable.
Hope this helps.
Modify the below css in your styles
#container > li {
display: block;
border-radius: 3px;
position: relative;
/* z-index: 0; */
padding: 15px;
background: #ecf0f1;
margin-bottom: 15px;
}