Fullscreen menu fade won't work with svg and image - javascript

I have been trying to make a fullscreen menu toggle with smooth fade in and out.
That works fine with all elements except for svg elements and picture.
Basically when you click on the menu burger you can clearly see the image and the svg icons not fading out, everything else does, but not these elements.
At first I thought it could be a z-index related problem and changed the numbers around but nothing worked.
I have been trying to find information about this for days but can't find anything on it.
I would highly appreciate your help on this, thank you.
Heres my fiddle
And code:
(function () {
"use strict";
var toggles = document.querySelectorAll(".c-hamburger");
for (var i = toggles.length - 1; i >= 0; i--) {
var toggle = toggles[i];
toggleHandler(toggle);
};
function toggleHandler(toggle) {
toggle.addEventListener("click", function (e) {
e.preventDefault();
(this.classList.contains("is-active") === true) ? this.classList.remove("is-active") || $("#testMenu").fadeOut(300) : this.classList.add("is-active") || $("#testMenu").fadeIn(300);
});
}
})();

It happens because menu container is listed before image in source so it has lower index in z axis. Make #testMenu on the top with z-index and position:relative
<nav id="testMenu" style="display: none; z-index: 1000; position: relative;">

To control the z-index, the element must have a stacking order, like declaring a position.
When you introduce the position property into the mix, any positioned elements (and their children) are displayed in front of any non-positioned elements.
Try for example, changing this:
#contact {
z-index: -1;
position: relative;
...
}
Here is the working fiddle

Related

How to make an element disappear after scrolling?

I have a custom icon element that is only displayed when its specific row in the table is hovered over, but when I scroll down without moving my mouse it doesn't update the hover and maintains the button on the screen and over my table's header. How can I make sure this doesn't happen?
export const StyleTr = styled.tr`
z-index: ${({ theme }) => theme.zIndex.userMenu};
&:hover {
background-color: ${({ theme, isData }) =>
isData ? theme.colors.primary.lighter : theme.colors.white};
div {
visibility: visible;
}
svg[icon] {
display: initial;
}
}
`;
I was just working on something similar to this for a web scraper recently.
Something like this should work:
function checkIfIconInViewport() {
// define current viewport (maximum browser compatability use both calls)
const viewportHeight =
window.innerHeight || document.documentElement.clientHeight;
//Get our Icon
let icon = document.getElementById('icon');
let iPos = icon.getBoundingClientRect();
//Show if any part of icon is visible:
if (viewportHeight - iPos.top > 0 && iPos.bottom > 0) {
icon.style.visibility = visibile;
}
else { icon.style.visibility = hidden; }
//Show only if all of icon is visible:
if (iPos.bottom > 0 && iPos.top >= 0) {
{
icon.style.visibility = visibile;
}
else { icon.style.visibility = hidden; }
//Add && iPos.bottom <= viewportHeight to the if check above for very large elements.
{
//Run function everytime that the window is scrolled.
document.addEventListener('scroll', checkIfIconInViewport);
Basically, every time a scroll event happens, we just check to see if the top & bottom of our element (the icon in your case) are within the bounds of the viewport.
Negative values, or values greater than the viewport's height mean that the respective portion of the element is outside the viewport's boundary.
Hopefully this helps! If you are dealing with a large quantity of objects, it may make sense to bundle the objects you are tracking together into an array and check each of them in a single function call to avoid saving function definitions for each individual object.
Edit: I just realized that I misunderstood your issue a bit. I think you can get by with just the bottom part of the code, and when a scroll event happens, set the icon's visibility to hidden. Assuming you want to hide it whenever the user scrolls?
Have you tried getting the scroll position of the DOM, then disabling (removing) the element once a certain scroll position is reached?

How to remove sticky class once div returns to its original point

I've got two navbars, the second becomes sticky once it hits the top of the viewport, the problem I'm having is getting it to 'unstick' when the div above which contains the original navbar comes back into the viewport so the first navbar can be seen again .
Sorry for the terrible explanation and vague title, had trouble trying to thing of how to describe it.
Here's a jsfiddle which will give you a much better idea of what I mean, any help would be appreciate as I'm pretty poor when it comes to javascript, thanks.
(HTML and CSS in jfiddle)
$('#nav2').attr("attop", false);
var lastScrollTop = 0;
$(window).on('scroll', function() {
var windowScrollTop = $(this).scrollTop();
if (windowScrollTop > lastScrollTop) {
var header = $('#nav2[attop="false"]:first');
if (header && header.length > 0) {
if (windowScrollTop >= header.offset().top) {
header.attr('attop', true);
$('#nav2').addClass('sticky');
}
}
}
lastScrollTop = windowScrollTop;
});
});
````
There is a nice solution in Bootstrap 4 and I use it on a few sites. The only thing you need to do is to add this class to the navbar. Check out the snippet below.
Notice that in order for position sticky to work correctly this class can't be added to an element inside a container, you must add this class to the container itself.
#supports ((position: -webkit-sticky) or (position: sticky)) {
.sticky-top {
position: -webkit-sticky;
position: sticky;
top: 0;
z-index: 1020;
}
}
/*DEMO PURPOSE*/
nav{background:red;padding-top:1rem;padding-bottom:1rem}
.section-1{height:300px}
.section-2{height:1000px}
<div class="section-1">Section 1</div>
<nav class="sticky-top">Lorem Ipsum</nav>
<div class="section-2">Section 1</div>

On scroll, logo color changes, but scrolling back up it stays the same

Im creating a fixed header where on load, the logo is flat white. On scroll, it changes to the full color logo.
However, when scrolling back to the top, it stays the same colored logo instead of going back to white.
Here's the code (and a pen)
$(function() {
$(window).scroll(function() {
var navlogo = $('.nav-logo-before');
var scroll = $(window).scrollTop();
if (scroll >= 1) {
navlogo.removeClass('.nav-logo-before').addClass('nav-logo-after');
} else {
navlogo.removeClass('.nav-logo-after').addClass('nav-logo-before');
}
});
});
http://codepen.io/bradpaulp/pen/gmXOjG
There's a couple of things here:
1) You start with a .nav-logo-before class but when the logo becomes black you remove that class and then try to get the same element using a class selector that doesn't exist anymore
2) removeClass('.nav-logo-before') is different than removeClass('nev-logo-before), notice the "." in the first selector.
3) You get the element using the $('.selector')in every scroll event, this can be a performance issue, it's better to cache them on page load and then use the element stored in memory
4) It's not a good practice to listen to scroll events as this can be too performance demanding, it's usually better to use the requestAnimationFrame and then check if the scroll position has changed. Using the scroll event it could happen that you scroll up really fast and the scroll event doesn't happen at 0, so your logo won't change. With requestAnimationFrame this can't happen
$(function() {
var navlogo = $('.nav-logo');
var $window = $(window);
var oldScroll = 0;
function loop() {
var scroll = $window.scrollTop();
if (oldScroll != scroll) {
oldScroll = scroll;
if (scroll >= 1) {
navlogo.removeClass('nav-logo-before').addClass('nav-logo-after');
} else {
navlogo.removeClass('nav-logo-after').addClass('nav-logo-before');
}
}
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
});
body {
background-color: rgba(0,0,0,.2);
}
.space {
padding: 300px;
}
.nav-logo-before {
content: url(https://image.ibb.co/kYANyv/logo_test_before.png)
}
.nav-logo-after {
content: url(https://image.ibb.co/jYzFJv/logo_test_after.png)
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<img class="nav-logo nav-logo-before">
</div>
<div class="space">
</div>
Dont need to add the dot . in front of the class name in removeClass and addClass:
Use this:
navlogo.removeClass('nav-logo-before')
Secondly, you are removing the class that you are using to get the element in the first place.
I have an updated codepen, see if this suits your needs: http://codepen.io/anon/pen/ZeaYRO
You are removing the class nav-logo-before, so the second time the function runs, it can't find any element with nav-logo-before.
Just give a second class to your navlogo element and use that on line 3.
Like this:
var navlogo = $('.second-class');
working example:
http://codepen.io/anon/pen/ryYajx
You are getting the navlogo variable using
var navlogo = $('.nav-logo-before');
but then you change the class to be 'nav-logo-after', so next time the function gets called you won't be able to select the logo using jquery as it won't have the '.nav-logo-before'class anymore.
You could add an id to the logo and use that to select it, for example.
Apart from that, removeClass('.nav-logo-before') should be removeClass('nav-logo-before') without the dot before the class name.
The problem is that you removes nav-logo-before and then you want to select element with such class but it doesn't exist.
I've rafactored you code to avert it.
Another problem is that you uses dot in removeClass('.before') while it should be removeClass('before') - without dot
$(function() {
var navlogo = $('.nav-logo');
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 1) {
navlogo.removeClass('before').addClass('after');
} else {
navlogo.removeClass('after').addClass('before');
}
});
});
body {
background-color: rgba(0,0,0,.2);
}
.space {
padding: 300px;
}
.before {
content: url(https://image.ibb.co/kYANyv/logo_test_before.png)
}
.after {
content: url(https://image.ibb.co/jYzFJv/logo_test_after.png)
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<img class="nav-logo before">
</div>
<div class="space">
</div>

How to add an element between 2 flex-styled rows and make the row below move down based on new element height?

Please take a look at this basic example:
http://tympanus.net/Blueprints/ResponsiveFullWidthGrid/
Now imagine that by clicking a cat box, I would need (especially on small to medium screens) to add a 100%-width text box (say a description of the clicked cat) below the clicked cat's row. That text box should push down the rest of the rows.
I am full css/js/frontend developer but I never faced a problem like this. It's also the first time I'm going to use a flexbox layout. With a fixed layout would be quite trivial, but in this case I cannot figure out a good way of doing it. One of the things to solve for example is: where should I put the box (relative to the clicked box?), and should I change position via javascript based on current items-per-row or maybe there a smarter css way?
Any idea is appreciated.
That was an interesting challenge :)
The only way to know where to place the expanded area (I called it infoBox), is to identify the 1st node of the next line, and then insert it before it. If there is no node on the last line, we can append it to the end of the ul.
I've also added a window.resize event handler that will close the infoBox, so it won't break the responsive layout, and a close button.
Working example - fiddle.
HTML was copy paste from the codrop article.
JS
var rfgrid = document.querySelector('.cbp-rfgrid');
var items = Array.from(document.querySelectorAll('.cbp-rfgrid > li'));
/** Create infoBox **/
var infoBox = document.createElement('div');
infoBox.classList.add('infoBox');
infoBox.innerHTML = '<div class="close">X</div><div class="content"></div>';
infoBoxClose = infoBox.querySelector('.close');
infoBoxContent = infoBox.querySelector('.content');
/** add close button functionality **/
infoBoxClose.addEventListener('click', function() {
rfgrid.removeChild(infoBox);
});
/** remove infoBox on resize to maintain layout flow **/
window.addEventListener('resize', function() {
rfgrid.removeChild(infoBox);
});
items.forEach(function (item) {
item.addEventListener('click', function (event) {
event.preventDefault();
var insertReference = findReference(this); // get refence to next line 1st node
infoBoxContent.innerHTML = items.indexOf(this); // example of changing infoBox content
if(insertReference) {
rfgrid.insertBefore(infoBox, insertReference); // insert infoBox before the reference
} else {
rfgrid.appendChild(infoBox); // insert infoBox as last child
};
});
});
/** find reference to 1st item of next line or null if last line **/
function findReference(currentNode) {
var originalTop = currentNode.offsetTop; // get the clicked item offsetTop
do {
currentNode = currentNode.nextSibling; // get next sibling
} while (currentNode !== null && (currentNode.nodeType !== 1 || currentNode.offsetTop === originalTop)); // keep iterating until null (last line) or a node with a different offsetTop (next line)
return currentNode;
}
CSS (in addition to the original)
.infoBox {
position: relative;
width: 100%;
height: 200px;
padding: 20px 0 0 0;
clear: both;
background: paleturquoise;
}
.infoBox > .close {
position: absolute;
top: 5px;
right: 5px;
cursor: pointer;
}

Store positioning information from each element (JQuery/Javascript)

Pleasantries
I've been playing around with this idea for a couple of days but can't seem to get a good grasp of it. I feel I'm almost there, but could use some help. I'm probably going to slap myself right in the head when I get an answer.
Actual Problem
I have a series of <articles> in my <section>, they are generated with php (and TWIG). The <article> tags have an image and a paragraph within them. On the page, only the image is visible. Once the user clicks on the image, the article expands horizontally and the paragraph is revealed. The article also animates left, thus taking up the entire width of the section and leaving all other articles hidden behind it.
I have accomplished this portion of the effect without problem. The real issue is getting the article back to where it originally was. Within the article is a "Close" <button>. Once the button is clicked, the effect needs to be reversed (ie. The article returns to original size, only showing the image, and returns to its original position.)
Current Theory
I think I need to retrieve the offset().left information from each article per section, and make sure it's associated with its respective article, so that the article knows where to go once the "Close" button is clicked. I'm of course open to different interpretations.
I've been trying to use the $.each, each(), $.map, map() and toArray() functions to know avail.
Actual Code
/*CSS*/
section > article.window {
width:170px;
height:200px;
padding:0;
margin:4px 0 0 4px;
position:relative;
float:left;
overflow:hidden;
}
section > article.window:nth-child(1) {margin-left:0;}
<!--HTML-->
<article class="window">
<img alt="Title-1" />
<p><!-- I'm a paragraph filled with text --></p>
<button class="sClose">Close</button>
</article>
<article class="window">
<!-- Ditto + 2 more -->
</article>
Failed Attempt Example
function winSlide() {
var aO = $(this).parent().offset()
var aOL = aO.left
var dO = $(this).offset()
var dOL = dO.left
var dOT = dO.top
var adTravel = dOL-aOL
$(this).addClass('windowOP');
$(this).children('div').animate({left:-(adTravel-3)+'px', width:'740px'},250)
$(this).children('div').append('<button class="sClose">Close</button>');
$(this).unbind('click', winSlide);
}
$('.window').on('click', winSlide)
$('.window').on('click', 'button.sClose', function() {
var wW = $(this).parents('.window').width()
var aO = $(this).parents('section').offset()
var aOL = aO.left
var pOL = $(this).parents('.window').offset().left
var apTravel = pOL - aOL
$(this).parent('div').animate({left:'+='+apTravel+'px'},250).delay(250, function() {$(this).animate({width:wW+'px'},250); $('.window').removeClass('windowOP');})
$('.window').bind('click', winSlide)
})
Before you go scratching your head, I have to make a note that this attempt involved an extra div within the article. The idea was to have the article's overflow set to visible (.addclass('windowOP')) with the div moving around freely. This method actually did work... almost. The animation would fail after it fired off a second time. Also for some reason when closing the first article, the left margin was property was ignored.
ie.
First time a window is clicked: Performs open animation flawlessly
First time window's close button is clicked: Performs close animation flawlessly, returns original position
Second time SAME window is clicked: Animation fails, but opens to correct size
Second time window's close button is clicked (if visible): Nothing happens
Thank you for your patience. If you need anymore information, just ask.
EDIT
Added a jsfiddle after tinkering with Flambino's code.
http://jsfiddle.net/6RV88/66/
The articles that are not clicked need to remain where they are. Having problems achieving that now.
If you want to go for storing the offsets, you can use jQuery's .data method to store data "on" the elements and retrieve it later:
// Store offset before any animations
// (using .each here, but it could also be done in a click handler,
// before starting the animation)
$(".window").each(function () {
$(this).data("closedOffset", $(this).position());
});
// Retrieve the offsets later
$('.window').on('click', 'button.sClose', function() {
var originalOffset = $(this).data("originalOffset");
// ...
});
Here's a (very) simple jsfiddle example
Update: And here's a more fleshed-out one
Big thanks to Flambino
I was able to create the effect desired. You can see it here: http://jsfiddle.net/gck2Y/ or you can look below to see the code and some explanations.
Rather than having each article's offset be remembered, I used margins on the clicked article's siblings. It's not exactly pretty, but it works exceptionally well.
<!-- HTML -->
<section>
<article>Click!</article>
<article>Me Too</article>
<article>Me Three</article>
<article>I Aswell</article>
</section>
/* CSS */
section {
position: relative;
width: 404px;
border: 1px solid #000;
height: 100px;
overflow:hidden
}
article {
height:100px;
width:100px;
position: relative;
float:left;
background: green;
border-right:1px solid orange;
}
.expanded {z-index:2;}
//Javascript
var element = $("article");
element.on("click", function () {
if( !$(this).hasClass("expanded") ) {
$(this).addClass("expanded");
$(this).data("originalOffset", $(this).offset().left);
element.data("originalSize", {
width: element.width(),
height: element.height()
});
var aOffset = $(this).data("originalOffset");
var aOuterWidth = $(this).outerWidth();
if(!$(this).is('article:first-child')){
$(this).prev().css('margin-right',aOuterWidth)
} else {
$(this).next().css('margin-left',aOuterWidth)
}
$(this).css({'position':'absolute','left':aOffset});
$(this).animate({
left: 0,
width: "100%"
}, 500);
} else {
var offset = $(this).data("originalOffset");
var size = $(this).data("originalSize");
$(this).animate({
left: offset + "px",
width: size.width + "px"
}, 500, function () {
$(this).removeClass("expanded");
$(this).prev().css('margin-right','0')
$(this).next().css('margin-left','0')
element.css({'position':'relative','left':0});
});
}
});​

Categories