Here is my goal:
When the user hovers a div of class "item" another div of class "menu" should appear overlaying the "item" div.
The position of the "menu" div should be relative to the "item" div.
When the user unhovers the item "div" the menu div should disappear.
When the user mouses over the "menu" div the "menu" div the "menu" div should not disappear so that user can click a button in it.
I am looking for a JavaScript and CSS solution. If you can help but you can only post a JQuery solution I will still appreciate it but I will have to translate it to straight JavaScript.
So far I have tried:
To make the "hover" div an absolutely positioned child of the document.body. This works for positioning, but hovering the "hover" div unhovers the "item" div and I don't know how to figure out that the new hovered div is the "hover" div.
To make the "hover" div a absolutely or fixed positioned child of the "item" div. This places the "hover" div underneath the "item" div and style.top seems to have no effect on the "hover" div".
To make the "hover" div a relatively positioned child of the "item" div. This places the "hover" div within the "item" div and increases the size of the "hover" div, which I don't want.
Thank you for your help with this!
Here is a JSFiddle that is a starting point for a solution https://jsfiddle.net/ypn5f1ng/
HTML
<div id=content>
content
<div class=item>item 1</div>
<div class=item>item 2</div>
more content
</div>
CSS
body { background:green; }
#content { z-index:100; width:500px; position:absolute; left:0px; right:0px; margin-left:auto; margin-right:auto; background:white; margin-top:10px; background:lightblue; padding:5px; }
div.item { background:pink; margin:5px}
div.hover { background:yellow; height:15px; width:100px; z-index:101; position:fixed }
JavaScript
function getElem(event) {
if (!event) {
event = window.event;
}
var elem = null;
if (event.target) {
elem = event.target;
} else if (event.srcElement) {
elem = event.srcElement;
}
if (elem && elem.nodeType == 3) {
elem = elem.parentNode;
}
return elem;
}
var hoverDiv = null;
function onItemMouseOver(event) {
var elem = getElem(event);
if (!hoverDiv) {
hoverDiv = document.createElement('DIV');
hoverDiv.className = "hover";
document.body.appendChild(hoverDiv);
//elem.appendChild(hoverDiv);
hoverDiv.style.right=100;
hoverDiv.style.top=-100;
}
}
function onItemMouseOut(event) {
if(hoverDiv) {
hoverDiv.parentNode.removeChild(hoverDiv);
hoverDiv = null;
}
}
var items = document.getElementsByClassName("item");
for(var i = 0; i < items.length; ++i) {
var item = items[i];
item.onmouseover = onItemMouseOver;
item.onmouseout = onItemMouseOut;
}
fiddle
HTML
<div class='a'>
<div class="b">
asfdwa
</div>
</div>
CSS
.a {
position: relative;
width: 300px;
height: 300px;
background: lightgray;
}
.b {
position: absolute;
top: 0;
left: 0;
width: 300px;
height: 80px;
background: pink;
opacity: 0;
transition: .2s opacity ease-in-out;
}
.b a {
display: block;
margin: 1rem;
}
.a:hover .b {
opacity: 1;
}
The best approach is to use CSS only if possible (no JS).
In this situation, I would recommend to put the div you would like to display on hover into the div that is the trigger.
<div class="parent">
<div class="child">
...
</div>
...
</div>
Than the CSS would look like this:
div.child {
display: none;
}
div.parent:hover div.child {
display: block;
}
With this technique you can position the child even to get outside the parent and it will not disappear if you get out of the parent if you are still on the child since the child is technically (not visually) in the parent. You just need to make sure that the parent at least touches the displayed child since the child will disappear if you travel over the gap between them with your cursor (the cursor won't be on the parent nor on the child)
Related
Is there an easy way to get the height of a parent div which has a hidden child div inside? If not, what could be the hard way to achieve such a result?
PS: I know that this topic might be repetitive, but the other topics I have found were all with negative scored best answers.
var getHeight = $(".parent").height();
console.log(getHeight);
.parent{
position:absolute;
top:0;
left:0;
}
.visibleChild{
position:relative;
height:20px;
background-color:red;
}
.hiddenChild{
display:none;
height:20px;
background-color:green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent">
<div class="visibleChild">
This div is visible.
</div>
<div class="hiddenChild">
This div is hidden.
</div>
</div>
You can certainly get the height of the parent when a child element is not displayed, but it sounds like you want to get the height of the parent when all of the children's heights are accounted. In this case, you can make the child(s) hidden but displayed, grab the height, and revert:
/* parentSelector: selector we wish to know its height
* childSelector: children to display when measuring parent
*/
function getHeight(parentSelector, childSelector) {
var parent = $(parentSelector);
var children = parent.children(childSelector);
var styleState = [];
//set state
children.each(function (i) {
let c = $(this);
styleState[i] = c.css(['display', 'visibility']);
c.css({ display: '', visibility: 'hidden' });
});
var height = parent.css('height');
//revert state
children.each(function (i) {
let { display, visibility } = styleState[i];
$(this).css({ display, visibility });
});
return height;
}
$('#test > div').hide();
console.log(getHeight('#test', 'div'));
#test { background: brown; padding: 1em }
#test > div { height: 50px; background: yellow; margin: 1em 0 }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="test">
<span>span</span>
<div>div</div>
<div>div</div>
</div>
I hope this helps!
I am loading html page inside a div with jquery. It does work fine.
var loginBtn = $("#loginBtn");
var loginPage = $("#login");
var submitBtn = $("#submitBtn");
var submitPage = $("#submit");
var checkBtn = $("#checkBtn");
var checkPage = $("#check");
loginPage.load( "login.html" );
submitPage.load( "submitPoints.html" );
checkPage.load( "checkPoints.html" );
body {
margin: 0 !important;
padding: 0 !important;
background-color: white;
}
#mainFrame {
width: 100%;
height: 300px;
background-color:cadetblue;
padding-top: 0;
margin-top: 0px;
position: relative;
}
<div id="mainFrame">
<div id="login"></div>
<div id="check"></div>
<div id="submit"></div>
</div>
My issue is that if the loaded html has no content, the margin between the parent document body (white) and the top of the loaded html (green) is none (that's what I want, it's ok).
However as soon as I add content to the loaded html, a gap is generated at the top of the page :\
I thought it was all about setting some line-height prop in the css but it seems helpless.
Any ideas what I am doing wrong ?
What you are seeing is the top margin of the first piece of content overflowing its container (also known more commonly as margin collapsing):
body {
background:yellow;
}
#container {
background:green;
height:300px;
}
<div id="container">
<h1>I have a top margin of 1em by default that is overflowing into the body.</h1>
</div>
If you give your container element a padding of that same amount, the margin space of the body won't be used and the element will be pushed down in the green area.
body {
background:yellow;
}
#container {
background:green;
height:300px;
padding:1em;
}
<div id="container">
<h1>I have a top margin of 1em by default that is now contained within my parent.</h1>
</div>
Or, you could set the top margin of the first piece of content to zero:
body {
background:yellow;
}
#container {
background:green;
height:300px;
}
#container > h1:first-child { margin-top:0; }
<div id="container">
<h1>My top margin has been set to zero.</h1>
</div>
Finally, you could set the overflow of the content area to auto but (although this seems to be the popular answer), I don't prefer this approach as you run the risk of unintended fitting of the content as the content changes and/or the container size changes. You give up a bit of sizing control:
body {
background:yellow;
}
#container {
background:green;
height:300px;
overflow:auto;
}
<div id="container">
<h1>The content area has had its overflow set to auto.</h1>
</div>
When you load new content it gets rendered in the document and those new elements might have properties. In this case, most probably the Login has a margin value. Another option is that it has a class or some selector that is being picked up by a CSS file which appends the margin to it.
Easiet way would be to right-click on the Login element, choose inspect, and analyze the style of the element with web-dev / style.
If you want to keep the margin on the inner content, you should set an overflow. Look what happens when we remove the overflow: auto line from .content > div (try clicking the box after running the code sample below).
This is because of margin collapsing. The margin on the inner content is combined with the margin on the outer element and applied on the outer element, i.e. two margins of the two elements are collapsed into a single margin.
document.querySelector('.content').addEventListener('click', (e) => {
e.target.classList.toggle('overflow');
});
html,
body {
margin: 0;
padding: 0;
}
.outer {
width: 200px;
background: red;
}
.content > div {
width: 100%;
height: 300px;
background: cadetblue;
cursor: pointer;
}
.content > div.overflow {
overflow: auto;
}
.test {
margin: 10px;
display: block;
}
<div class="outer">
<div class="content">
<div><span class="test">Test</span></div>
</div>
</div>
I'm using superfish menu and I have a problem.
In the header, I have a logo holder div with the logo badge div and logo name div inside. When the user hovers over a top level link the sf-mega drop menu is show and a class of .sfHover is applied to the parent li.
My issue is that I need the logo badge to show on top of the drop down menu BUT not the logo name div.
Using z-indexes are out I think so (I have tried) so I wanted to hide the logo name div when the .sfHover class is active on the menu li so I have this code but it is not hiding it.
if ($('#mainMenu.sf-menu ul li').hover().hasClass('sfHover') == true) {
$('.logoHolder .kingsworthName').hide();
}
Any help is appreciated.
Your usage of hover() is wrong here. It expects handler functions as argument. You should use it like this :
$('#mainMenu.sf-menu ul li').hover(
function() { // when the mouse pointer enters the element.
if ($(this).hasClass('sfHover')) {
$('.logoHolder .kingsworthName').hide();
}
},
function () {} // when the mouse pointer leaves the element.
);
You can use pure css. here's the link.
//css FILE
.box {
height: 300px;
width: 300px;
background: red;
}
.hidden {
height: 100px;
width: 100px;
background: white;
display:none;
}
.box:hover .hidden {
display: block;
}
//HTML
<html>
<body>
<div class="box">
<div class="hidden">
Hello there
</div>
</div>
</body>
</html>
https://jsfiddle.net/8Ldwm10p/
Working on creating functionality where when the user clicks on one of the products (each of the elements have the same assigned ID card-reveal) it adds a CSS class to the container specifically clicked (active state) to show information for that specific item and then finally, when the user clicks the cancel button the CSS class is removed (activate state gone).
Unfortunately I have run to a few hiccups where when I click on the 1st element it adds the class to that element but the other elements I click do not add the class, as well the close button does not function at all. I would like to finish the solution in Pure Javascript. Also if you see a few classie() methods, I am using Classie.js to help with CSS class toggling.
Any help will be appreciated! Thank You!
Html
<a id="card-reveal" class="card-view" href="javascript:void(0)"><h3 class='hover-title'>View More</h3></a>
<div class="card-cover">
<span class="card-exit"></span>
<a class="card-follow" href="javascript:void(0)">Follow {{object.product_website_name}}.com</a>
<a class="card-buy" target="_blank" href="{{object.product_slug_url}}">Buy {{object.product_name }}</a>
<a id="card-close" class="card-info" href="javascript:void(0)"><span class="icon-indie_web-03"></span></a>
<ul class="card-social">
<label>Share</label>
<li><span class="icon-indie_web-04"></span></li>
<li><span class="icon-indie_web-05"></span></li>
</ul>
</div>
CSS
.card-cover {
width:100%;
height: 100%;
background: none repeat scroll 0% 0% rgba(255, 91, 36, 0.9);
color: #FFF;
display: block;
position: absolute;
opacity: 0;
z-index:200;
overflow: hidden;
-webkit-transform:translate3d(0, 400px, 0);
transform:translate3d(0, 400px, 0);
-webkit-backface-visibility:hidden;
backface-visibility: hidden;
-webkit-transition-property:opacity, transform;
transition-property:opacity, transform;
-webkit-transition-duration:0.2s;
transition-duration:0.2s;
-webkit-transition-timing-function:cubic-bezier(0.165, 0.84, 0.44, 1);
transition-timing-function:cubic-bezier(0.165, 0.84, 0.44, 1);
-webkit-transition-delay: 0s;
transition-delay: 0s;
}
.card-cover.card--active {
opacity: 1;
-webkit-transform:translate3d(0, 0, 0);
transform:translate3d(0, 0px, 0);
}
JS below:
var cardContainer = document.querySelector('.card-cover'),
cardTargets = Array.prototype.slice.call( document.querySelectorAll( '#card-reveal' ) ),
eventType = mobilecheck() ? 'touchstart' : 'click',
cardClose = document.getElementById('card-close'),
resetMenu = function() {
classie.remove( cardContainer, 'card--active' );
},
resetMenuClick = function( ) {
cardCloseaddEventListener(globalMenuEventType, function() {
resetMenu();
document.removeEventListener(eventType, resetMenuClick);
}, false);
};
cardTargets.forEach(function (element, index) {
if( element.target ) {
element.addEventListener(eventType, function( event ) {
event.preventDefault();
event.stopPropagation();
classie.add(cardContainer, 'card--active');
document.addEventListener(eventType, resetMenuClick);
} ,false);
}
});
There are two simple ways I can think of doing something like this.
First, if you can't designate ID's for each card (which it sounds like you can't), you're going to have to go by class names. Like it was mentioned in the comments, you really don't want to use the same ID for multiple elements.
Part of the reason for this is, as you can see from my examples below, that the .getElementById() method is only meant to return one element, where the other methods like .getElementsByClassName() will return an array of elements.
The problem we're trying to solve is that the sub-content you want to display/hide has to be attached to the element you click somehow. Since we're not using ID's and you can't really rely on class names to be unique between elements, I'm putting the div with the information inside a container with the element that toggles it.
Inside a container div, are two divs for content. One is the main content that's always visible, the other is the sub-content that only becomes visible if the main content is clicked (and becomes invisible when clicked again).
The benefit of this method is that since there are no ID's to worry about, you can copy/paste the cards and they'll each show the same behaviour.
var maincontent = document.getElementsByClassName("main-content");
// Note: getElemenstByClassName will return an array of elements (even if there's only one).
for (var i = 0; i < maincontent.length; i++) {
//For each element in the maincontent array, add an onclick event.
maincontent[i].onclick = function(event) {
//What this does is gets the first item, from an array of elements that have the class 'sub-content', from the parent node of the element that was clicked:
var info = event.target.parentNode.getElementsByClassName("sub-content")[0];
if (info.className.indexOf("show") > -1) { // If the 'sub-content' also contains the class 'show', remove the class.
info.className = info.className.replace(/(?:^|\s)show(?!\S)/g, '');
} else { // Otherwise add the class.
info.className = info.className + " show";
}
}
}
.container {
border: 1px solid black;
width: 200px;
margin: 5px;
}
.main-content {
margin: 5px;
cursor: pointer;
}
.sub-content {
display: none;
margin: 5px;
}
.show {
/* The class to toggle */
display: block;
background: #ccc;
}
<div class="container">
<div class="main-content">Here is the main content that's always visible.</div>
<div class="sub-content">Here is the sub content that's only visible when the main content is clicked.</div>
</div>
<div class="container">
<div class="main-content">Here is the main content that's always visible.</div>
<div class="sub-content">Here is the sub content that's only visible when the main content is clicked.</div>
</div>
<div class="container">
<div class="main-content">Here is the main content that's always visible.</div>
<div class="sub-content">Here is the sub content that's only visible when the main content is clicked.</div>
</div>
The second method, would be to use one div for the content that you want to show/hide, and clicking on an element will toggle both its visibility and it's content.
I'll use the previous example as a base, but ideally you would have some kind of MVVM framework like react, knockout, or angular to help you with filling in the content. For the sake of this example, I'm just going to use the text from the div of sub-content.
var info = document.getElementById("Info");
var maincontent = document.getElementsByClassName("main-content");
for (var i = 0; i < maincontent.length; i++) { //getElemenstByClassName will return an array of elements (even if there's only one).
maincontent[i].onclick = function(event) { //For each element in the maincontent array, add an onclick event.
//This does the same as before, but I'm getting the text to insert into the info card.
var text = event.target.parentNode.getElementsByClassName("sub-content")[0].innerHTML;
info.innerHTML = text; // Set the text of the info card.
info.style.display = "block"; //Make the info card visible.
}
}
info.onclick = function(event) {
info.style.display = "none"; // If the info card is ever clicked, hide it.
}
.container {
border: 1px solid black;
width: 200px;
margin: 5px;
padding: 5px;
}
.main-content {
margin: 5px;
cursor: pointer;
}
.sub-content {
display: none;
margin: 5px;
}
#Info {
cursor: pointer;
display: none;
}
<div id="Info" class="container">Here is some test information.</div>
<div class="container">
<div class="main-content">Link 1.</div>
<div class="sub-content">You clicked link 1.</div>
</div>
<div class="container">
<div class="main-content">Link 2.</div>
<div class="sub-content">You clicked link 2.</div>
</div>
<div class="container">
<div class="main-content">Link 3.</div>
<div class="sub-content">You clicked link 3.</div>
</div>
Is there any way how to add a child div into parent divs. The child div is still same (without changes) but content of parent div is variable. Parent div contains child div automatically like CSS div::before but with whole div in it not just text.
Basically for each parent automatically generate same child.
See figure
sample of parent and child divs
How can I make it via CSS ? (or JS)
CSS cannot generate content (as such) it can only style it.
If the element is not present in the HTML nothing will happen.
It is possible to add "pseudo content" with a pseudo element but the primary purpose of these pseudo-elements is enhancement not addition of "content". Also they cannot contain HTML.
It would be possible to use a pseudo element with a bg image in this instance as this is essentially styling.
JSfiddle Demo
div {
height:250px;
width:250px;
display: inline-block;
margin: 25px;
position: relative; /* required */
}
div:after {
content:"";
/* required */
position: absolute;
bottom:25px;
right:25px;
background-image: url(http://www.webdevelopersnotes.com/how-do-i/thumbs/shortcut-arrow.jpg);
height:75px;
width:75px;
background-size:cover;
}
.one {
background: red;
width:300px;
}
.two {
background: lightblue;
height:300px;
}
<div class="one"></div>
<div class="two"></div>
Not sure I understood your question so I will just give you a solution and then you comment your requirements.
You can have a div that contains another child div which is positioned inside the parent but does not change when you add more content to the parent.
Here is a fiddle:
http://jsfiddle.net/1fohx3qf/
.parent {
border:2px solid black;
padding:5px;
position:relative;
width:124px;
height:120px;
}
.child {
border:2px solid red;
padding:30px;
position:absolute;
bottom:5px;
right:10px;
}
It's not completely clear to me what the problem/issue is, but it sounds like you are looking for JS code like this:
var child = document.createElement('div');
child.innerHTML = '<p>Child!</p>';
var parent = document.createElement('div');
parent.innerHTML = '<p>Parent 1</p>';
parent.appendChild(child);