I have a site with back/next buttons fixed on the right and left side of the page. They are a single colour icon. Problem is they overlay both black and white images as the page scrolls. Can an 'anchor' or something similar be set so when the page reaches it (similar to how 'sticky' objects work I guess) I can change color of the div?
html (Wordpress)
...
<div><?php bnNav_content_nav( 'nav-below' ); ?></div> //puts the back/next buttons on the page
css
[class*="navigation"] .nav-previous a,
[class*="navigation"] .nav-next a {
position: fixed;
z-index: 999;
color: #fff;
}
I understand my code is complicated to understand but essentially the output is
post images ...
'anchor' to change the .nav color
post content...
<nav>
<nav id="nav-next"> ... </div>
<nav id="nav-previous"> ... </div>
</nav>
EDIT: The nav overlays images then the content is on a white background. I want the nav to be white when its over the images then when it hits the content turn black. So basically set up a spot where it will change
You can use JavaScript to iterate through all elements but the nav and check which elements intersect and then put attributes on the elements the nav will intersect with the color you want the nav text to be and then update the color on every scroll event.
var nav = document.querySelector("nav");
var navRect = nav.getBoundingClientRect();
function checkNavColor() {
var allButNav = document.querySelectorAll(":not(nav)");
for (var i = 0; i < allButNav.length; i++) {
var rect1 = allButNav[i].getBoundingClientRect();
var rect2 = navRect;
// By Buu Nguyen (http://stackoverflow.com/a/12067046/4245061)
if (!(rect1.right < rect2.left || rect1.left > rect2.right || rect1.bottom < rect2.top || rect1.top > rect2.bottom)) {
nav.style.color = allButNav[i].getAttribute("data-navcolor");
}
}
}
window.addEventListener("scroll", checkNavColor);
checkNavColor();
body {
height: 200vh;
}
nav {
position: fixed;
}
div {
height: 200px;
}
div:first-child {
background: black;
}
div:nth-child(2) {
background: white;
}
div:last-child {
background: black;
}
<nav>Text which changes color</nav>
<main>
<div data-navcolor="white"></div>
<div data-navcolor="black"></div>
<div data-navcolor="white"></div>
</main>
It is a really bad solution if you have more than a couple of elements like in the snippet and also uses HTML for non-semantic content.
If you want the text to be visible no matter the background you can add a shadow with the opposite color of the text:
body {
height: 200vh;
}
nav {
position: fixed;
/* Add the smallest possible shadow in all directions */
text-shadow: -1px -1px 0 white, 1px -1px 0 white, -1px 1px 0 white, 1px 1px 0 white;
}
div {
height: 200px;
}
div:first-child {
background: black;
}
div:nth-child(2) {
background: white;
}
div:last-child {
background: black;
}
<nav>Text which has a shadow of the opposite color</nav>
<main>
<div></div>
<div></div>
<div></div>
</main>
Related
I have coded a script (with the help of a user here) which allows me to expand a selected div and make the other divs behave accordingly by stretching equally to fit the remaining space (except the first one which width is fixed).
And here is a picture of what I want to achieve:
For that I use flex and transitions.
It works well, but the jQuery script specifies a "400%" stretch value (which is great for testing).
Now I would like the selected div to expand/shrink to exactly fit the content instead of the "400%" fixed value.
I have no idea how I could do that.
Is it possible ?
I tried to clone the div, fit it to the content, get its value and then use this value to transition BUT this means I have an initial width in percentages but a target value in pixels. That doesn't work.
And if I convert the pixel value in percentages, then the result doesn't exactly fit the content for whatever reason.
In all cases, this seems a bit of a complicated way to achieve what I want anyway.
Isn't there any flex property that could be transitioned in order to fit the content of a selected div?
Here is the code (edited/simplified since for a better read) :
var expanded = '';
$(document).on("click", ".div:not(:first-child)", function(e) {
var thisInd =$(this).index();
if(expanded != thisInd) {
//fit clicked fluid div to its content and reset the other fluid divs
$(this).css("width", "400%");
$('.div').not(':first').not(this).css("width", "100%");
expanded = thisInd;
} else {
//reset all fluid divs
$('.div').not(':first').css("width", "100%");
expanded = '';
}
});
.wrapper {
overflow: hidden;
width: 100%;
margin-top: 20px;
border: 1px solid black;
display: flex;
justify-content: flex-start;
}
.div {
overflow: hidden;
white-space: nowrap;
border-right: 1px solid black;
text-align:center;
}
.div:first-child {
min-width: 36px;
background: #999;
}
.div:not(:first-child) {
width: 100%;
transition: width 1s;
}
.div:not(:first-child) span {
background: #ddd;
}
.div:last-child {
border-right: 0px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Click on the div you want to fit/reset (except the first div)
<div class="wrapper">
<div class="div"><span>Fixed</span></div>
<div class="div"><span>Fluid (long long long long long text)</span></div>
<div class="div"><span>Fluid</span></div>
<div class="div"><span>Fluid</span></div>
</div>
Here is the jsfiddle:
https://jsfiddle.net/zajsLrxp/1/
EDIT: Here is my working solution with the help of you all (sizes updated on window resize + number of divs and first column's width dynamically calculated):
var tableWidth;
var expanded = '';
var fixedDivWidth = 0;
var flexPercentage = 100/($('.column').length-1);
$(document).ready(function() {
// Set width of first fixed column
$('.column:first-child .cell .fit').each(function() {
var tempFixedDivWidth = $(this)[0].getBoundingClientRect().width;
if( tempFixedDivWidth > fixedDivWidth ){fixedDivWidth = tempFixedDivWidth;}
});
$('.column:first-child' ).css('min-width',fixedDivWidth+'px')
//Reset all fluid columns
$('.column').not(':first').css('flex','1 1 '+flexPercentage+'%')
})
$(window).resize( function() {
//Reset all fluid columns
$('.column').not(':first').css('flex','1 1 '+flexPercentage+'%')
expanded = '';
})
$(document).on("click", ".column:not(:first-child)", function(e) {
var thisInd =$(this).index();
// if first click on a fluid column
if(expanded != thisInd)
{
var fitDivWidth=0;
// Set width of selected fluid column
$(this).find('.fit').each(function() {
var c = $(this)[0].getBoundingClientRect().width;
if( c > fitDivWidth ){fitDivWidth = c;}
});
tableWidth = $('.mainTable')[0].getBoundingClientRect().width;
$(this).css('flex','0 0 '+ 100/(tableWidth/fitDivWidth) +'%')
// Use remaining space equally for all other fluid column
$('.column').not(':first').not(this).css('flex','1 1 '+flexPercentage+'%')
expanded = thisInd;
}
// if second click on a fluid column
else
{
//Reset all fluid columns
$('.column').not(':first').css('flex','1 1 '+flexPercentage+'%')
expanded = '';
}
});
body{
font-family: 'Arial';
font-size: 12px;
padding: 20px;
}
.mainTable {
overflow: hidden;
width: 100%;
border: 1px solid black;
display: flex;
margin-top : 20px;
}
.cell{
height: 32px;
border-top: 1px solid black;
white-space: nowrap;
}
.cell:first-child{
background: #ccc;
border-top: none;
}
.column {
border-right: 1px solid black;
transition: flex 0.4s;
overflow: hidden;
line-height: 32px;
text-align: center;
}
.column:first-child {
background: #ccc;
}
.column:last-child {
border-right: 0px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span class="text">Click on the header div you want to fit/reset (except the first one which is fixed)</span>
<div class="mainTable">
<div class="column">
<div class="cell"><span class="fit">Propriété</span></div>
<div class="cell"><span class="fit">Artisan 45</span></div>
<div class="cell"><span class="fit">Waterloo 528</span></div>
</div>
<div class="column">
<div class="cell"><span class="fit">Adresse</span></div>
<div class="cell"><span class="fit">Rue du puit n° 45 (E2)</span></div>
<div class="cell"><span class="fit">Chaussée de Waterloo n° 528 (E1)</span></div>
</div>
<div class="column">
<div class="cell"><span class="fit">Commune</span></div>
<div class="cell"><span class="fit">Ixelles</span></div>
<div class="cell"><span class="fit">Watermael-Boitsfort</span></div>
</div>
<div class="column">
<div class="cell"><span class="fit">Ville</span></div>
<div class="cell"><span class="fit">Marche-en-Famenne</span></div>
<div class="cell"><span class="fit">Bruxelles</span></div>
</div>
<div class="column">
<div class="cell"><span class="fit">Surface</span></div>
<div class="cell"><span class="fit">120 m<sup>2</sup></span></div>
<div class="cell"><span class="fit">350 m<sup>2</sup></span></div>
</div>
</div>
And here is a fully fledged example at work (styles + padding + more data):
https://jsfiddle.net/zrqLowx0/2/
Thank you all !
It is possible to solve it using max-width and calc().
First, replace width: 100% with flex: 1 for the divs in CSS, so they will grow, which is better in this case. In addition, use transition for max-width.
Now, we have to store some relevant values:
The amount of divs that will be animated (divsLength variable) - 3 in this case.
The total width used for the fixed div and the borders (extraSpace variable) - 39px in this case.
With those 2 variables, we can set a default max-width (defaultMaxWidth variable) to all the divs, as well as using them later. That is why they are being stored globally.
The defaultMaxWidth is calc((100% - extraSpace)/divsLength).
Now, let's enter the click function:
To expand the div, the width of the target text will be stored in a variable called textWidth and it will be applied to the div as max-width. It uses .getBoundingClientRect().width (since it return the floating-point value).
For the remaining divs, it is created a calc() for max-width that will be applied to them.
It is: calc(100% - textWidth - extraScape)/(divsLength - 1).
The calculated result is the width that each remaining div should be.
When clicking on the expanded div, that is, to return to normal, the default max-width is applied again to all .div elements.
var expanded = false,
divs = $(".div:not(:first-child)"),
divsLength = divs.length,
extraSpace = 39, //fixed width + border-right widths
defaultMaxWidth = "calc((100% - " + extraSpace + "px)/" + divsLength + ")";
divs.css("max-width", defaultMaxWidth);
$(document).on("click", ".div:not(:first-child)", function (e) {
var thisInd = $(this).index();
if (expanded !== thisInd) {
var textWidth = $(this).find('span')[0].getBoundingClientRect().width;
var restWidth = "calc((100% - " + textWidth + "px - " + extraSpace + "px)/" + (divsLength - 1) + ")";
//fit clicked fluid div to its content and reset the other fluid divs
$(this).css({ "max-width": textWidth });
$('.div').not(':first').not(this).css({ "max-width": restWidth });
expanded = thisInd;
} else {
//reset all fluid divs
$('.div').not(':first').css("max-width", defaultMaxWidth);
expanded = false;
}
});
.wrapper {
overflow: hidden;
width: 100%;
margin-top: 20px;
border: 1px solid black;
display: flex;
justify-content: flex-start;
}
.div {
overflow: hidden;
white-space: nowrap;
border-right: 1px solid black;
text-align:center;
}
.div:first-child {
min-width: 36px;
background: #999;
}
.div:not(:first-child) {
flex: 1;
transition: max-width 1s;
}
.div:not(:first-child) span {
background: #ddd;
}
.div:last-child {
border-right: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
Click on the div you want to fit/reset (except the first div)
<div class="wrapper">
<div class="div"><span>Fixed</span></div>
<div class="div"><span>Fluid (long long long long text)</span></div>
<div class="div"><span>Fluid</span></div>
<div class="div"><span>Fluid</span></div>
</div>
This approach behaves dynamically and should work on any resolution.
The only value you need to hard code is the extraSpace variable.
You need to deal with the width or calc functions. Flexbox would have a solution.
To make all divs equal (not first one) we use flex: 1 1 auto.
<div class="wrapper">
<div class="div"><span>Fixed</span></div>
<div class="div"><span>Fluid (long long long long text)</span></div>
<div class="div"><span>Fluid</span></div>
<div class="div"><span>Fluid</span></div>
</div>
Define flex rules for your normal div and selected div. transition: flex 1s; is your friend. For selected one we don't need flex grow so we use flex: 0 0 auto;
.wrapper {
width: 100%;
margin-top: 20px;
border: 1px solid black;
display: flex;
}
.div {
white-space: nowrap;
border-right: 1px solid black;
transition: flex 1s;
flex: 1 1 auto;
}
.div.selected{
flex: 0 0 auto;
}
.div:first-child {
min-width: 50px;
background: #999;
text-align: center;
}
.div:not(:first-child) {
text-align: center;
}
.div:last-child {
border-right: 0px;
}
div:not(:first-child) span {
background: #ddd;
}
Add selected class each time when the user clicks a div. You can also use toggle for the second click so you can save selected items in a map and you can show multiple selected items (not with this code example of course).
$(document).on("click", ".div:not(:first-child)", function(e) {
const expanded = $('.selected');
$(this).addClass("selected");
if (expanded) {
expanded.removeClass("selected");
}
});
https://jsfiddle.net/f3ao8xcj/
After a few trial versions, this seems to be my shortest and most straighforward solution.
All that essentially needs to be done is have Flexbox stretch the <div> elements to their limits by default, but when <span> clicked, constraint the stretch of the <div> to <span> width ...
pseudo code:
when <span> clicked and already toggled then <div> max-width = 100%, reset <span> toggle state
otherwise <div> max-width = <span> width, set <span> toggle state
I have split the CSS into a 'relevant mechanism' and 'eye-candy only' section for easy reading (and code recyling).
The code is heavily commented, so not much text here...
Quirk Somehow there is an extra delay in the transition when switching the div from max-width: 100% to max-width = span width. I've checked this behaviour in Chrome, Edge, IE11 and Firefox (all W10) and all seem to have this quirk. Either some browser internal recalc going on, or maybe the transition time is used twice ('feels like'). Vice Versa, oddly enough, there is no extra delay.
However, with a short transition time (e.g. 150ms, as I am using now) this extra delay is not/hardly noticable. (Nice one for another SO question...)
$(document).on('click', '.wrapper>:not(.caption) span', function (e) {
// Save the current 'toggle' status
var elemToggled = e.target.getAttribute('toggled');
// Set parent max-width to maximum space or constraint to current child width
e.target.parentElement.style.maxWidth =
(elemToggled=="true") ? '100%' : parseFloat(window.getComputedStyle(e.target).width) + 'px';
// (Re)set child toggle state
e.target.setAttribute('toggled', (elemToggled=="true") ? false : true);
});
/*********************/
/* Wrapper mechanism */
/*********************/
.wrapper { /* main flexible parent container */
display : flex; /* [MANDATORY] Flexbox Layout container, can't FBL without */
flex-wrap: nowrap; /* [MANDATORY] default FBL, but important. wrap to next line messes things up */
flex-grow: 1; /* [OPTIONAL] Either: if '.wrapper' is a FBL child itself, allow it to grow */
width : 100%; /* [OPTIONAL] or : full parent width */
/* (Maybe a fixed value, otherwise redundant here as 'flex-grow' = 1) */
}
/* generic rule */
.wrapper>* { /* flexed child containers, being flexible parent containers themselves */
flex-grow : 1; /* [MANDATORY] important for this mechanism to work */
overflow: hidden; /* [MANDATORY] important, otherwise output looks messy */
display: flex; /* [MANDATORY] for FBL stretching */
justify-content: center;/* [MANDATORY] as per SOQ */
max-width : 100%; /* [OPTIONAL/MANDATORY], actually needed to trigger 'transition' */
}
/* exception to the rule */
.wrapper>.fixed { /* fixed child container */
flex-grow: 0; /* [MANDATORY] as per SOQ, don't allow grow */
}
/******************/
/* Eye-candy only */
/******************/
.wrapper {
border: 1px solid black;
}
.wrapper>:not(.fixed) {
transition: max-width 150ms ease-in-out;
}
.wrapper>:not(:last-child){
border-right: 1px solid black;
}
/* generic rule */
.wrapper>*>span {
white-space: nowrap;
background-color: #ddd;
}
/* exception to the rule */
.wrapper>.fixed>span {
background-color: #999;
}
/* debug helper: show all elements with outlines (put in <body>) */
[debug="1"] * { outline: 1px dashed purple }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
<div class="fixed"><span>Fixed</span></div>
<div><span>Fluid (long long long long long text)</span></div>
<div><span>Fluid</span></div>
<div><span>Fluid</span></div>
</div>
UPDATE
New version that resets all other <div>. I truly hate the jumpiness, but that is due to Flexbox stretching and the transition value. Without transition no jumps visible. You need to try out what works for you.
I only added document.querySelectorAll() to the javascript code.
$(document).on('click', '.wrapper>:not(.caption) span', function (e) {
var elemToggled = e.target.getAttribute('toggled'); // Toggle status
var elemWidth = parseFloat(window.getComputedStyle(e.target).width); // Current element width
// reset ALL toggles but 'this'...
document.querySelectorAll('.wrapper>:not(.caption) span')
.forEach( function (elem,idx) {
if (elem != this){
elem.parentElement.style.maxWidth = '100%';
elem.setAttribute('toggled',false);
};
});
// Set parent max-width to maximum space or constraint to current child width
e.target.parentElement.style.maxWidth =
(elemToggled=="true") ? '100%' : parseFloat(window.getComputedStyle(e.target).width) + 'px';
// (Re)set child toggle state
e.target.setAttribute('toggled', (elemToggled=="true") ? false : true);
});
/*********************/
/* Wrapper mechanism */
/*********************/
.wrapper { /* main flexible parent container */
display : flex; /* [MANDATORY] Flexbox Layout container, can't FBL without */
flex-wrap: nowrap; /* [MANDATORY] default FBL, but important. wrap to next line messes things up */
flex-grow: 1; /* [OPTIONAL] Either: if '.wrapper' is a FBL child itself, allow it to grow */
width : 100%; /* [OPTIONAL] or : full parent width */
/* (Maybe a fixed value, otherwise redundant here as 'flex-grow' = 1) */
}
/* generic rule */
.wrapper>* { /* flexed child containers, being flexible parent containers themselves */
flex-grow : 1; /* [MANDATORY] important for this mechanism to work */
overflow: hidden; /* [MANDATORY] important, otherwise output looks messy */
display: flex; /* [MANDATORY] for FBL stretching */
justify-content: center;/* [MANDATORY] as per SOQ */
max-width : 100%; /* [OPTIONAL/MANDATORY], actually needed to trigger 'transition' */
}
/* exception to the rule */
.wrapper>.fixed { /* fixed child container */
flex-grow: 0; /* [MANDATORY] as per SOQ, don't allow grow */
}
/******************/
/* Eye-candy only */
/******************/
.wrapper {
border: 1px solid black;
}
.wrapper>:not(.fixed) {
transition: max-width 150ms ease-in-out;
}
.wrapper>:not(:last-child){
border-right: 1px solid black;
}
/* generic rule */
.wrapper>*>span {
white-space: nowrap;
background-color: #ddd;
}
/* exception to the rule */
.wrapper>.fixed>span {
background-color: #999;
}
/* show all elements with outlines (put in <body>) */
[debug="1"] * { outline: 1px dashed purple }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
<div class="fixed"><span>Fixed</span></div>
<div><span>Fluid (long long long long long text)</span></div>
<div><span>Fluid</span></div>
<div><span>Fluid</span></div>
</div>
If you need only one row, there is a simpler solution based on this code : https://jsfiddle.net/jpeter06/a5cu52oy/
with the css flex modified for columns instead of rows :
.container {
flex-grow: 10;
flex-shrink: 0;
flex-basis: auto;
display: flex;
flex-direction: row;
width: 100%;
}
.item { min-width:30px;
flex-basis:30px;
overflow-x:hidden;
transition: flex-basis 500ms ease-in-out;
}
.expanded {
flex-basis: 20em;
}
html, body {
width: 100%; height: 100%;
margin: 0; padding: 0; border: 0; overflow: hidden;
}
html code :
<div class="container">
<div class="item" style="background: red">a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/>a<br/></div>
<div class="item" style="background: green">b<br/>b<br/>b<br/>b</div>
<div class="item" style="background: blue">c<br/>c<br/>c<br/>c</div>
</div>
JS code :
$(document).ready(function() {
$(".item").click(function() {
$(this).addClass('expanded');
$(".item").not(this).each(function() {
$(this).removeClass("expanded");
});
});
});
I am new to CSS/HTML/Javascript. I sort of just tweak and see what works and what doesn't, so I don't really get how to make my element that is in a fixed position to stay relative to the center page. The reason, is that when I zoom out, it stays in the right of the page, which I understand as I have read that fixed position do not have a parent.
So how can I keep it fixed to the position it was in previously.
window.onscroll = function() {
Navmove()
};
var box = document.getElementById("Navfixed");
var stock = box.offsetTop;
var box1 = document.getElementById("Navfixed1");
var stock1 = box1.offsetTop;
function Navmove() {
if (window.pageYOffset > stock) {
box.classList.add("Sticky");
box1.classList.add("Sticky1");
} else {
box.classList.remove("Sticky");
box1.classList.remove("Sticky1");
}
}
.Navnormal a:link {
color: #296da0;
}
.Navhover a:hover {
color: #4386bc;
background: #bcbcbc;
}
.Navbox {
margin: auto;
width: 13em;
height: 26.5em;
color: #b53206;
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);
background: rgba(255, 255, 255, 0.7);
border-color: #b53206;
padding: 1em;
border-radius: 0px 15px 15px 0px;
}
.Navbox2 {
margin-top: -225em;
margin-left: 102em;
}
.Container1 {
top: 0;
bottom: 0;
}
<div class="Container1">
<div class="Navbox2">
<div id="Navfixed" class="Navbar Navnormal Navhover Navbox">
<span class="Subheader"><strong><u>Directory</u></strong></span>
<p>
<span class="Borderfix1">
Home</span>
About Us
Research
Data Repository
Media
Other tools
<span class="Borderfix2">
Contact Us</span>
</div>
</div>
```
<div id = "Navfixed1" class = "Navigate Imagehover">
<ul style = "list-style-type: none;">
<div class = "Donate">
<li><img src = "Discord.png"></img></li>
<li><img src = "patreon.png"></img></li>
<li><img src = "Paypal.jpg"></img></li>
</div>
<div class = "Donate2 Donate3">
<li><img src = "f_logo_RGB-Blue_58.png"></img></li>
</div>
</ul>
</div>
```
Essentially this is a scroll for my navbar, however, it works perfectly when at 100% zoom level, but once it gets past the Yoffset it starts sticking to the right because of the fixed position. How can I fix this? Thank you.
First of all, you say that your element is position fixed but I do not see any position: fixed; on your CSS.
For what I understand from your explanation, you should do something like the next:
.Navbox2 {
position: fixed;
top: 50%;
margin-top: -14.25em; /* Negative half of height of the element. */
}
This will position your element fixed relative to the web browser window, sticked to the top-left corner, It does not depend on any parent becase what it is looking for to be positioned is, as I said before, the web browser window.
About the top:50%; and margin-top: -14.25em; is used to position a fixed element in the middle of the screen.
The top:50%; is standard and the margin-top has to be the negative half of the height of the element. Because I see that your element has height: 26.5em; and padding:1em this means that the real height is 28.5em, you have to sum one em of the padding from the top, and other em from the bottom.
So now you can see your element fixed and in the middle of the screen.
Example on fiddle:https://jsfiddle.net/Samuel10F/msha7zot/23/
I understand that you want something like this but I am not 100% sure with your explanation, if there is something else just tell me :)
I have build sidebar with css and jquery. It's working fine but i want that when sidebar opens then whole screen except sidebar should get semi-black or disabled.
Here is my working
jsFiddle
How can i make whole screen semi-black or disabled on sidebar open?
You can use a box-shadow on the sidebar:
#sidebar{
box-shadow:0 0 0 10000px rgba(0,0,0,.50);
}
This is black, at .50 opacity. It's set to 10000px to cover the full screen.
Or change rgba(0,0,0,.50) to a solid color like #5a5a5a.
In your case add to your css:
#slide-out.visible:not(.close){
box-shadow:0 0 0 10000px #666666;
}
The general concept to achieve this is fairly straightforward:
Modify the javascript to add a class to the body when the nav is open (I called it nav-open.)
Modify the CSS so that the "overlay" element (you already had one in place) is displayed when the body has the class nav-open
Adjust your overlay element CSS to cause it to show properly (for some reason, it had opacity: 0 on it, which meant it was there, but was not visible).
Here's the relevant CSS:
#sidenav-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
width: 100vw;
height: 100vh;
// removed opacity: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 997;
// set display to none by default
display: none;
}
// when the body has the class nav-open, display the overlay
.nav-open #sidenav-overlay {
display: block;
}
Here's the relevant changes to your javascript:
// no-conflict-safe document ready function
jQuery(function($) {
$('#show-hide-menu').click(function() {
if ($('#slide-out').hasClass('visible')) {
// $('#slide-out').removeClass('visible');
$('#slide-out').toggleClass('close');
} else {
$('#slide-out').addClass('visible');
}
// check if the nav is "open"
var open = !$('#slide-out').hasClass('close');
// for simplicity, always first remove the nav-open from the body
$('body').removeClass('nav-open');
// if the nav is open, add the 'nav-open' class to the body
if (open) {
$('body').addClass('nav-open');
}
});
// modify to use "on", is best-practice
// $(document).click(function(e) {
$(document).on('click', function(e) {
var sidebar = $(".sidenav, #show-hide-menu");
if (!sidebar.is(e.target) && sidebar.has(e.target).length === 0) {
$('#slide-out').toggleClass('close');
// be sure the nav-open class is removed when the sidebar is dismissed
$('body').removeClass('nav-open');
}
});
});
Here is a link to your fiddle, modified with these changes to do what you want: http://jsfiddle.net/cale_b/hThGb/8849/
Make a content div below your nav. Something like:
<div id="maincontent" class="">
<p>Lorem.</p>
</div>
Add some styling so it has min-height, etc.
#maincontent {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
min-height: 400px;
}
Add some JS so when the nav menu button is clicked, it toggles on and off a new style class for this area.
$('#show-hide-menu').click(function () {
if ($("div#maincontent").hasClass("overlayed")) {
$("div#maincontent").removeClass("overlayed");
}
else {
$("div#maincontent").addClass("overlayed");
}
});
Define the overlayed class in the CSS.
.overlayed {
background-color: rgba(0,0,0,.8);
}
I have a navbar that uses some CSS to change the opacity:
.navbar {
background-color: #4B5253;
opacity: 0.8;
filter: alpha(opacity = 80);
}
I need the opacity to change to 1.0 after the user scrolls down a certain number of pixels, for example, 500px.
I'm using jQuery, but I didn't find a solution.
Also, I'm not good with JavaScript, and sometimes I don't know where should I put my code. So if is there any way to do it all with CSS, it will be great!
Here is an example of what I want—pay close attention to the header as you scroll down.
If you want a native solution then use this:
function changeCss () {
var bodyElement = document.querySelector("body");
var navElement = document.querySelector("nav");
this.scrollY > 500 ? navElement.style.opacity = .8 : navElement.style.opacity = 1;
}
window.addEventListener("scroll", changeCss , false);
here is a live demo
function changeCss () {
var bodyElement = document.querySelector("body");
var navElement = document.querySelector("nav");
this.scrollY > 500 ? navElement.style.opacity = .8 : navElement.style.opacity = 1;
}
window.addEventListener("scroll", changeCss , false);
body{
background-color: white;
height: 1000vh
}
nav{
position:fixed;
top:0;
left:0;
width:100%;
text-align: center;
background: blueviolet
}
nav li{display: inline-block}
nav a{
padding: 10px 12px;
color: white;
text-transform:uppercase;
text-decoration: none
}
<nav class="menu">
<ul>
<li>Home</li>
<li>About</li>
<li>Contact</li>
</ul>
</nav>
I wrote CSS for class a, then class b.
In .a, opacity was 0.8 and in .b the opacity was 1.0. With jQuery, I just changed the element's class:
.a {
opacity: 0.8;
}
.b {
opacity: 1.0;
}
$(window).scroll(function () {
var $heightScrolled = $(window).scrollTop();
var $defaultHeight = 500;
if ($heightScrolled < $defaultHeight) {
$('#mynav').removeClass("b")
$('#mynav').addClass("a")
}
else {
$('#mynav').addClass("b")
}
});
The easiest way to accomplish what you're trying to do is a combination of some simple jQuery and CSS transitions.
We will use JavaScript to check for the windows scroll position on every scroll event and compare it to the distance of the bottom of the #main element; if the scroll position is greater, then we'll apply a class to the body to indicate we have scrolled past #main, and then we will use CSS to define the nav styling for that state.
Change the CSS code so it changes opacity when it's past #main.
// get the value of the bottom of the #main element by adding the offset of that element plus its height, set it as a variable
var mainbottom = $('#main').offset().top + $('#main').height();
// on scroll,
$(window).on('scroll', function() {
// we round here to reduce a little workload
stop = Math.round($(window).scrollTop());
if (stop > mainbottom) {
$('.nav').addClass('past-main');
} else {
$('.nav').removeClass('past-main');
}
});
.nav {
background-color: transparent;
color: #fff;
transition: all 0.25s ease;
position: fixed;
top: 0;
width: 100%;
background-color: #ccc;
padding: 1em 0;
/* make sure to add vendor prefixes here */
}
.nav.past-main {
background-color: #fff;
color: #444;
}
#main {
height: 500px;
background-color: red;
}
#below-main {
height: 1000px;
background-color: #eee;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav class="nav">
[logo]
</nav>
<div id="main">#main</div>
<div id="below-main">#below-main</div>
I have fixed bootstrap menu on the top of the page and an asbolutely positioned scroll button .btn-navigate at the bottom of the viewport (in #home-slide).
On (any) scroll, I want the fixed menu to change background from transparent to semigray and also the scroll button to disappear. The button should keep on being hidden from now on, but when I scroll to the top, I need the menu to become transparent again.
For this purpose I am using jQuery Waypoints. I have achieved both effects using the following code, but when I scroll, the menu jumps, EDIT: More specificaly it flashes as if the menu is not at fixed position all the time. When I scroll, it sometimes look as if the menu scroll out with the page and then suddenly jumps back in the fixed position. Sometimes after a while is starts to work correctly. It s not jumping if I remove the following two lines of code, but I need the same trigger for both events.
EDIT2: It is also not flashing if I don't use waypoints with the menu. The scrolling is smooth and the menu is always atop of all other elements in the page.
$("#home-slide .btn-navigate").removeClass("pulse animated");
$("#home-slide .btn-navigate").addClass("fadeOutUp animated2");
HTML:
<header id="masthead">
<nav class="navbar navbar-fixed-top">
<div class="container">
MENU CONTENT
</div>
</nav>
</header>
<section id="home-slide">
<div class="container">
<h1 class="heading">HEADING</h1>
<p class="font2">
TEXT</p>
Scroll Button
</div>
</section>
jQuery:
jQuery(document).ready(function ($) {
$(function () {
$("#masthead nav").waypoint(function () {
$("#masthead nav").toggleClass('scrolling');
$("#home-slide .btn-navigate").removeClass("pulse animated");
$("#home-slide .btn-navigate").addClass("fadeOutUp animated2");
}, { offset: '-20px' });
});
});
MY Navigation CSS:
#masthead {
nav {
min-height: 120px;
padding-top: 2.727rem;
background: rgba(51,58,64,0.0);
-webkit-transition: background-color 0.5s linear;
.container {
position: relative;
}
.navbar-nav {
a {
color: #lms-white;
font-weight: bold;
text-transform: none;
text-shadow: 1px 1px 2px rgba(50, 50, 50, 1);
padding: 7px 1.17rem;
border: 2px solid transparent;
.border-radius(5px);
&:hover {
background: transparent;
border: 2px solid #lms-pink;
}
}
}
.navbar-brand {
padding: 7px 15px;
}
&.scrolling {
background: rgba(51,58,64,0.9);
-webkit-transition: background-color 0.5s linear;
}
}
Bootstrap Navigation CSS:
.navbar-fixed-top {
top: 0;
border-width: 0 0 1px;
}
.navbar-fixed-top, .navbar-fixed-bottom {
position: fixed;
right: 0;
left: 0;
z-index: 1030;
}
.navbar {
position: relative;
min-height: 50px;
margin-bottom: 20px;
border: 1px solid transparent;
}
Any idea how to solve this? Thank you!
I have found the solution. The blinking was not cause by Waypoints. Adding
-webkit-backface-visibility: hidden; /* Chrome, Safari, Opera */
backface-visibility: hidden;
to nav solved the problem.
As described in the debugging guide, using a fixed-position element as a waypoint can lead to a bad time. A waypoint's element's position in the document (client offsetX/Y) determines where it triggers and fixed position elements' offsets are constantly changing as you scroll.
It looks like you already have a perfectly good statically positioned element you can use instead of that nav, the #masthead itself. You may also want to make some changes to your code to look at the direction the user is scrolling when the waypoint is crossed. I believe you want to undo some of these animated states if the user scrolls back up.
$("#masthead").waypoint(function (direction) {
$("#masthead nav").toggleClass('scrolling');
if (direction === 'down') {
$("#home-slide .btn-navigate").removeClass("pulse animated");
$("#home-slide .btn-navigate").addClass("fadeOutUp animated2");
}
else {
$("#home-slide .btn-navigate").addClass("pulse animated");
$("#home-slide .btn-navigate").removeClass("fadeOutUp animated2");
}
}, { offset: -20 });
This can be reduced a little bit using the toggleClass variation that takes a boolean as the second argument, where if that boolean is true the toggle will add the classes, and if it is false the classes are removed.
$("#masthead").waypoint(function (direction) {
$("#masthead nav").toggleClass('scrolling', direction === 'down');
$("#home-slide .btn-navigate")
.toggleClass("pulse animated", direction === 'up')
.toggleClass("fadeOutUp animated2", direction === 'down');
}
}, { offset: -20 });