Making child element disappear on it's parent's `mouseleave` - css

I have a red div with green child, the green one moves when mouse hovers over it's parent. Pretty simple.
HTML:
<div class="big">
<div class="small"></div>
</div>
CSS:
.big {
position: relative;
width: 200px; height: 200px;
margin: 20px auto;
background: red;
}
.big:hover .small {
opacity: 1;
}
.small {
position: absolute;
top: 0; left: 0;
width: 50px; height: 50px;
background: green;
opacity: 0;
}
JavaScript:
$('.big').on('mousemove', function (e) {
var $this = $(this),
small = $this.find('.small'),
offset = $this.offset(),
cursorX = e.pageX - offset.left,
cursorY = e.pageY - offset.top,
smallX = cursorX - small.width() / 2,
smallY = cursorY - small.height() / 2;
$('.small').css({
top: smallY,
left: smallX
});
});
How to make the green box to disappear when it leaves the red one? :hover in css doesn't work because green div is part of the red one (I quess), so cursor never actually leaves it. Only when you move themouse really quickly the green div can't keep up with the cursor and disappers. Perhaps adding some wrapper elements with specific positioning will do the trick? Or something like jQuery stopPropagation()?
Here's my Fiddle
UPDATE: Here's updated code, based on suggestions from user nevermind. I added a transition, it disappears as I wanted it to, but now there's other problem. When cursor is moved outside the red box quickly, the green box stays at the border of it's parent.

I think this is what you want:
http://jsbin.com/obewaz/1/
http://jsbin.com/obewaz/1/edit
Same html/css, few additions in jquery:
$(document).ready(function() {
$('.big').on('mousemove', function (e) {
var $this = $(this),
smalle = $this.find('.small'),
offset = $this.offset(),
position=smalle.position(),
cursorX = e.pageX - offset.left,
cursorY = e.pageY - offset.top,
smallX = cursorX - smalle.width() / 2,
smallY = cursorY - smalle.height() / 2;
$('.small').css({
top: smallY,
left: smallX
});
console.log(position);
if(position.left<0 || position.left>150 || position.top<0 || position.top>150) {
$('.small').css('display','none');
}
else {
$('.small').css('display','block');
}
});
});
Of course, you can change/tweak values in last condition a little to fit your needs. Idea is: track position of small box, and when it is 'outside' of big box - hide it.

instead of mousemove try mouseover
DEMO

Related

How to run more than one css transition with a click on a button?

I am building an animated hamburger menu with html css js. I now know how to start a css transition with javascript. See https://jsfiddle.net/ralphsmit/byaLfox5/. My problem now is that I need to run more than one transition with a click on my button. I've put my code here https://jsfiddle.net/ralphsmit/v980ouwj/16/.
A short explanation of my code. I have made a button (for the sake of clarity I made it green with a low opacity) and when that button is clicked, the background .dsgn-header-background will appear. Now I also want the two rectangle for the menu to animate into a cross and that the the .dsgn-header-menu-opened-menuitems also fade in.
My question is, how do I modify this js code, so that more than one transition will be started? So all transitions are a different element. You'll find the full code in the JS fiddle above (feel free to edit this).
Javascript:
const background = document.querySelector('.dsgn-header-background');
const button = document.querySelector('.dsgn-header-button');
let open = false;
button.addEventListener('click', onClickPlay);
function onClickPlay(){
if(background.classList.contains('on')){
background.classList.remove('on');
}else{
background.classList.add('on');
}
}
Check this out.
function onClickPlay(){
if(background.classList.contains('on')){
background.classList.remove('on');
element.classList.remove('anotherClassWithDifferentTransitions');
}else{
background.classList.add('on');
element.classList.add('anotherClassWithDifferentTransitions');
}
}
Cheers!
You can try this , The changes is i have added 2 more constant variable which adding on class when menu open and remove on class when menu closes.
const background = document.querySelector('.dsgn-header-background');
const button = document.querySelector('.dsgn-header-button');
const menu_up = document.querySelector('.dsgn-header-rectangle-up');
const menu_down = document.querySelector('.dsgn-header-rectangle-down');
let open = false;
button.addEventListener('click', onClickPlay);
function onClickPlay(){
if(background.classList.contains('on')){
background.classList.remove('on');
menu_up.classList.remove('on');
menu_down.classList.remove('on');
}else{
background.classList.add('on');
menu_up.classList.add('on');
menu_down.classList.add('on');
}
}
hope this will help you .
const content = document.querySelector('.content');
const button = document.querySelector('.dsgn-header-button');
function onClickPlay() {content.classList.toggle('on');}
button.addEventListener('click', onClickPlay);
fiddle: https://jsfiddle.net/s24mbakf/
Add the other elements to your onClickPlay function as you did with demo.
const demo = document.querySelector('.demo');
const demo2 = document.querySelector('.demo2');
const buttondemo = document.querySelector('.buttondemo');
let open = false;
buttondemo.addEventListener('click', onClickPlay);
function onClickPlay(){
if(demo.classList.contains('on')){
demo.classList.remove('on');
demo2.classList.remove('on');
} else {
demo.classList.add('on');
demo2.classList.add('on');
}
}
.demo {
width: 0;
height: 100vh;
background-color: black;
position: absolute;
right: 0;
transition: width 4s;
}
.demo.on {
width: 100vw;
}
.demo2 {
width: 0;
height: 50vh;
background-color: red;
position: absolute;
right: 0;
transition: width 8s;
}
.demo2.on {
width: 100vw;
background-color: yellow;
}
.buttondemo {
position: absolute;
top: 0px;
right: 0px;
width: 100px;
height: 100px;
background-color: green;
}
<div class="demo"><div>
<div class="demo2"><div>
<div class="buttondemo"><div>

Zooming in overflow: scroll

I am trying to implement correctly scaling and zooming in css way. I created an example with scaled view. When click, the view should be zoomed and then to be able to scroll.
https://jsfiddle.net/opb5tcy8/4/
I have several issues with it:
Can I somehow get rid of the margin-left and margin-top on the .zoomed class? I did not manage to scale it without necessity to shift it with these margins.
When clicked, I can get the click position by clientX. I would like to use it to fluently scroll to the clicked position during zooming. However I can't manage the scroll to be fluent and when removing the margin-left it is kind of jumpy and not nice.
When you zoom in and move the scroll to the center and then zoom out, you can see the zoom is not nice as it first scrolls to the right. Is there a way to prevent it?
When you scroll to corners in Chrome on OSX it tends do navigate back/forward in browser. Is there a way to prevent this behaviour?
UPDATE:
The first part can be solved with transform-origin: 0 0. The other issues stays mostly the same as it is demonstrated.
Hm... I could say it is impossible to satisfy point 2 your condition with current browsers' support. The other are possible, as in this demo:
$(document).ready(function() {
var windowHalfWidth = $("#window").width() / 2;
var scalingFactor = 0.55;
var throtte = false;
$("#slider").click(function(event) {
//Simple event throtte to prevent click spamming breaking stuff up
if (throtte) return false;
throtte = true;
setTimeout(function() {
throtte = false;
}, 1000);
var xSelf = event.pageX - $("#window").offset().left + $("#window").scrollLeft();
if ($(this).hasClass("zoomed")) {
$("#window").animate({
scrollLeft: (xSelf / scalingFactor - windowHalfWidth)
}, 1000, "linear");
} else {
$("#window").animate({
scrollLeft: (xSelf * scalingFactor - windowHalfWidth)
}, 1000, "linear");
}
$("#slider").toggleClass("zoomed");
});
});
body {
background-color: #eee;
margin-top: 10px; /*reduced margin for easier view in SO */
}
#window {
width: 500px;
height: 200px;
margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;
border: 1px solid #999;
position: relative;
background-color: white;
}
#slider {
width: 900px;
height: 600px;
background-color: #fff;
position: absolute;
transition: 1s linear;
top: 0;
left: 0;
transform-origin: 0 0;
}
#slider.zoomed {
transform: scale(0.55);
}
#slider div {
width: 50px;
height: 50px;
line-height: 50px;
position: absolute;
top: 75px;
background-color: #eee;
text-align: center;
}
#obj1 {
left: 10px;
}
#obj2 {
left: 210px;
}
#obj3 {
left: 410px;
}
#obj4 {
left: 610px;
}
#obj5 {
left: 810px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="window">
<div id="slider" class="zoomed">
<div id="obj1">1</div>
<div id="obj2">2</div>
<div id="obj3">3</div>
<div id="obj4">4</div>
<div id="obj5">5</div>
</div>
</div>
As you can see, the zooming & scrolling is quite laggy, especially when the far right size is zoomed in.
The reason is simple, because jQuery and css both have their own animation loop, and they are not in sync. In order to solve this we'll need to somehow manage to do both scrolling & scaling animations with only one system, either jQuery or CSS.
Problem is: jQuery don't have a scaling feature, and css can't scroll elements. Wonderful.
If your scaling can be done with width/height though, it would be possible, using jquery width&height animate(). But if the #slider consists of many components I guess it can't be done.
So um writing an answer just to say it's impossible is kind of a let down, so I think maybe I can suggest an alternative, using dragging to scroll content (similar to the way Google map work):
var windowHalfWidth, startX, startLeft, minLeft, dragging = false,
zooming = false;
var zoomElement = function(event) {
var xSelf = event.pageX - $("#window").offset().left - parseFloat($("#slider").css("left"));
if ($("#slider").hasClass("zoomed")) {
minLeft = windowHalfWidth * 2 - 900;
var newLeft = Math.min(Math.max((-(xSelf / 0.55 - windowHalfWidth)), minLeft), 0);
$("#slider").css("left", newLeft + "px");
} else {
minLeft = windowHalfWidth * 2 - 900 * 0.55;
var newLeft = Math.min(Math.max((-(xSelf * 0.55 - windowHalfWidth)), minLeft), 0);
$("#slider").css("left", newLeft + "px");
}
$("#slider").toggleClass("zoomed");
}
$(document).ready(function() {
windowHalfWidth = $("#window").width() / 2;
minLeft = windowHalfWidth * 2 - 900 * 0.55;
$("#slider").on({
mousedown: function(event) {
dragging = true;
startX = event.pageX;
startLeft = parseFloat($(this).css("left"));
},
mousemove: function(event) {
if (dragging && !zooming) {
var newLeft = Math.min(Math.max((startLeft + event.pageX - startX), minLeft), 0);
$("#slider").css("left", newLeft + "px");
}
},
mouseup: function(event) {
dragging = false;
if (Math.abs(startX - event.pageX) < 30 && !zooming) {
// Simple event throtte to prevent click spamming
zooming = true;
$("#slider").css("transition", "1s");
setTimeout(function() {
zooming = false;
$("#slider").css("transition", "initial");
}, 1000);
zoomElement(event);
}
},
mouseleave: function() {
dragging = false;
}
});
});
body {
background-color: #eee;
margin-top: 10px; /*reduced margin for easier view in SO */
}
#window {
width: 500px;
height: 200px;
margin: 0 auto;
overflow: hidden;
border: 1px solid #999;
position: relative;
background-color: white;
}
#slider {
width: 900px;
height: 600px;
background-color: #fff;
position: absolute;
top: 0;
left: 0;
transform-origin: 0 0;
}
#slider.zoomed {
transform: scale(0.55);
}
#slider div {
width: 50px;
height: 50px;
line-height: 50px;
position: absolute;
top: 75px;
background-color: #eee;
text-align: center;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#obj1 {
left: 10px;
}
#obj2 {
left: 210px;
}
#obj3 {
left: 410px;
}
#obj4 {
left: 610px;
}
#obj5 {
left: 810px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="window">
<div id="slider" class="zoomed">
<div id="obj1">1</div>
<div id="obj2">2</div>
<div id="obj3">3</div>
<div id="obj4">4</div>
<div id="obj5">5</div>
</div>
</div>
This variation manages to get CSS to do both animation, by sacrificing the scrollbar (which is pretty ugly imo, who needs it?) and use css left instead.
So I hope if in the end you can't find a good solution, at least you have this to consider as fall back version.
I'll address the points individually and then give an example at the end.
When clicked, I can get the click position by clientX. I would like to
use it to fluently scroll to the clicked position during zooming.
In my opinion scroll animations during transitions can be a bit choppy in webkit browsers. Try balancing the animation time of the jQuery effect with the animation time of the css transition.
When you zoom in and move the scroll to the centre and then zoom out, you can see the zoom is not nice as it first scrolls to the right. Is there a way to prevent it?
Bring the scrollLeft property of the div#window back to 0px. Again, tweaking the animation times will make this less jerky.
When you scroll to corners in Chrome on OSX it tends do navigate back/forward in browser. Is there a way to prevent this behaviour?
You could use the mouseover and mouseout events to toggle a overflow:hidden css on the body.
Here's an example change to your code:
var slider = $("#slider").on('click', function(event) {
if (!slider.hasClass('zoomed')) {
// zoom back to left position
$('#window').animate({scrollLeft:'0px'});
}else{
// zoom to click position within slider
$('#window').animate({scrollLeft:event.clientX + 'px'}, 2000);
}
slider.toggleClass("zoomed");
});
/* stop window scrolling when using slider */
slider
.on('mouseover', function () {
$(document.body).css({overflow:'hidden'});
})
.on('mouseout', function () {
$(document.body).css({overflow:'auto'});
});
And an updated fiddle.

Semantic UI calendar, drop down menu overflow full width

I made a calendar where I can click on each day.
When I put my mouse on the last column div, it overflows the screen width.
<div class="menu">EEEEEEE</div>
https://jsfiddle.net/c0oh7kby/
You can apply transformation on last <td>, to pull tooltip to the left:
td.ui:last-child .ui.simple.dropdown:hover > .menu {
transform: translate(calc(-100% + 16px), 0);
}
Or put it to the right:
td.ui:last-child .ui.simple.dropdown:hover > .menu {
left: auto;
right: 0;
}
updated fiddle
Edit
Before that count all menu items, that overflows viewport:
$('.ui .menu').each(function(){
var $this = $(this);
if ($this.width() + $this.parent().position().left > $(window).width()) {
$this.addClass('transformed');
}
});
And then apply needed css:
.ui.simple.dropdown:hover > .menu.transformed {
left: auto;
right: 0;
}
fiddle
However it doesn't compensate if tooltip is overflowing in both sides. for that You can check twice:
$('.ui .menu').each(function(){
var $this = $(this);
if ($this.width() + $this.parent().position().left > $(window).width()) {
$this.addClass('transformed');
if ($this.parent().position().left - $this.width() < 0) {
$this.addClass('center');
}
}
});
And apply transformation:
.ui.simple.dropdown:hover > .menu.transformed.center {
transform: translate(50%, 0);
}
fiddle

screen resolution changing the CSS

I'm not very experienced in cross-browser issues, but I'm having this issue:
Scenerio : Let say i have div of width:800px, in that div i have 2 buttons ( left-araow--right-arrow ), onclick on any of the button I change image position in the div ( image move right or left,but stays in outer div )
Problem : When I re-size or reduce screen resolution then my CSS gets change; the image goes out of the div, and also the position of my buttons get change as well.
Any idea or solutions? Thanks.
EDIT : It is working fine in Firefox and in Opera, but not working in Google Chrome and IE.
Below is the html:
<div class="hand">
<div id="handinside"></div>
</div>
<div id="left" class="button"> left </div>
<div class="flip"></div>
<div id="right" class="button">right</div>
</div>
below is the CSS
.gameNavigation {
width: 220px;
margin: 0px auto 0px;
}
.button {
margin: 0 0 0 5px;
cursor: pointer;
width: 59px;
height: 29px;
float: left;
text-align: center;
background-color:red;
color: white;
}
.hand {
position:relative;
background-color:transparent;
left:0px;
width:140px;
height:210px;
}
Below is the jquery
$(".button").click(function() {
var $button = $(this);
var oldValue = $("#counter").val();
if ($button.text() == "right" ) {
//move right if the value is no more than 4
if(parseInt(oldValue) < 3){
var newVal = parseInt(oldValue) + 1;
$(".hand").animate({
"left": "+=222px"
}, "slow");
$(".coin").animate({
"left": "+=222px"
}, "slow");
//$(".block").stop();
}
}
else {
// move left and don't allow the value below zero
var test = 'test'
if (oldValue >= 1) {
var newVal = parseInt(oldValue) - 1;
}
if(parseInt(newVal) >= -1){
$(".hand").animate({
"left": "-=222px",
easing :'swing'
}, "slow");
$(".coin").animate({
"left": "-=222px",
easing : 'swing'
}, "slow");
}
}
$("#counter").val(newVal);
});
position your container div with relative positioning and then position your arrows with absolute positioning

Position fixed menu to top

I know how to use position:fixed; but I want, if the page scrolls over it, that it's on the top and on normal state lower.
.menu {
height: 30px;
width: 100%;
border-bottom: 1px solid black;
position: fixed;
top: 0px;
}
If I understand correctly, you want to make a menu fixed after it's scrolled past? If that's the case, see this question.
If that doesn't work for you, consider using code like this, assuming jQuery (actually Sprint but it's about the same for both):
var navigation = $('nav').item(0);
var navigationY = navigation.element.offsetTop;
var navClone = navigation.clone();
$(window).bind('scroll', function() {
var scrollY = (window.pageYOffset || (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop) >>> 0;
if(scrollY > navigationY) {
if(!navClone.element.parentNode || navClone.element.parentNode.nodeType !== 1) {
navigation.after(navClone);
navigation.addClass('fixed');
}
} else if(navClone.element.parentNode) {
navClone.remove();
navigation.removeClass('fixed');
}
});
which I used in a recent project, so just change $('nav') at the top to whatever you need to select your element, e.g. $('.menu').

Resources