Inserting padding to compensate for "scrollbar jump" - javascript

I have a horizontally centered container with a navbar that hides and shows divs of varying length with js. Sometimes, if the content in the shown div is too long, showing the div will also show a scrollbar and cause the page to "jump" to the left in certain browsers. The CSS is just Bootstrap's basic scaffolding.
Below is the gist of what's going on in the site. but you can see the problem in production here: http://dylanpatrickclark.com
<body>
<script type="text/javascript">
$(document).ready(function(){
function setNavState(currentHash) {
$('nav ul li').removeClass('active');
var selector = 'nav ul li a[href="' + currentHash + '"]';
$(selector).parent().addClass('active');
};
function hash() {
var hash = window.location.hash;
if (hash != ''){
$('.tabs div').hide();
$(hash).show();
}
else {
$('.tabs div').hide();
$('.tabs div#tab1').show();
hash = 'tab1'
}
setNavState(hash);
};
hash();
$(window).bind('hashchange', function() {
hash()
});
});
</script>
<h1>Hello, world!</h1>
<div class="container">
<div class="row">
<nav>
<ul>
<li> Tab1 </li>
<li> Tab2 </li>
</ul>
</nav>
</div>
</div>
<div class="row">
<div class="tabs">
<div class="tab-pane" id="tab1">
<p>Short</p>
</div>
<div class="tab-pane" id="tab2">
<p>Long</p>
</div>
</div>
</div>
</body>
I have seen a lot of older answers to this question here, a lot of them suggest forcing the scrollbar to show, but I'd rather use js to insert padding to compensate for the scrollbar. I think facebook does something like this. I'm not really want to worried about IE support, as I am mostly focusing on finding a solution that I can understand with my rudimentary understanding of javascript.
Can anyone explain simply how to best compensate for the appearance/disappearance of a scrollbar with javascript?
Thank you so much!

Two ways come to my mind, first you can define body { overflow:scroll } for preveting sliding with scroll or second you can create your own scroll with scrollbar plugin and define scrollbar's css { position: absolute; right:0px; }. Note: relative to body or wrapper ofcourse.

body {overflow-y:scroll} worked perfectly for me when I had this issue

Related

Removing a class from navbar to make it collapse upon navbar item being clicked

I have a navbar that's inherited from some legacy code - and I'm trying to get the mobile version to collapse when a menu item is clicked.
http://shitnavbar.brodiedigital.io/
If you resize the window and scroll beyond the first 100vh of the page the hamburger menu will appear.
clicking will reveal the menu items
clicking a menu item WILL scroll you to correct area of page, but not collapse/close the menu
At the moment I'm using some jquery to attempt to do this by targeting just a single item on the menu - 'BIKES', with little joy:
$('#_bikes').on('click', function(){
$('.menu').removeClass('active');
});
html for the section is
<div class="menu active">
<div class="menu_content d-flex flex-column align-items-center justify-content-center">
<ul class="menu_nav_list text-center">
<li>LOCATIONS</li>
<li>BIKES</li>
<li>CONCIERGE</li>
<li>ABOUT</li>
<li>ENQUIRE</li>
<li>CONTACT</li>
</ul>
</div>
</div>
Jquery isnt my strong point, but feel like im having a bit of a brain fart moment here - something very simple I'm doing wrong.
Has anyone got an insight into why clicking bikes is not removing the class 'active' from the div that has 'menu' class in it?
Your selector is probably the problem, the following will work for all your nav links
$('.menu_nav_list li a').on('click', function(){
$('.menu').removeClass('active');
});
You have no element with an id of _bikes that is why your jquery doesn't work. Use a selector that will work:
$('.menu_nav_list a').on('click', function(e){ // target all anchors in the menu nav list
e.preventDefault(); // prevent default action of link click
$(this).closest('.menu').removeClass('active'); // get the closest ancestor of the link that has a class of .menu
});
.active a {
color:red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="menu active">
<div class="menu_content d-flex flex-column align-items-center justify-content-center">
<ul class="menu_nav_list text-center">
<li>LOCATIONS</li>
<li>BIKES</li>
<li>CONCIERGE</li>
<li>ABOUT</li>
<li>ENQUIRE</li>
<li>CONTACT</li>
</ul>
</div>
</div>
Your website has console errors. It's from this:
<script type="text/javascript">
$('#_bikes').on('click', function(){
$('.menu').removeClass('active');
});
</script>
When you run jQuery code, you need to include this code below the link to the jQuery file, right now you are tryint to run jQuery code before the jQuery library has been loaded.
And also wrap it in something to wait for the document to become ready
<script type="text/javascript">
$(function() {
$('#_bikes').on('click', function(){
$('.menu').removeClass('active');
});
});
</script>
It also looks like you are including jQuery library twice, and at two different versions. v3.2.1 and v1.11.0
(Also as a side note, the codebase might be legacy, but that site looks really slick!)
In your code above you used .on() incorrectly and you are also targeting the element
if you wanted to target the href you would need to put the following inside the selector a[href="_bikes"] because currently you are trying to select a ID not the href in your selector.
You need to add the following code to your javascript file and it will close the menu if you click on any link inside you nav
$(document).on('click','.menu_nav_list a', function(){
$('.menu').removeClass('active');
});

Scrollspy offset for a button

I have a fixed navbar, so I need a little offset when a certain element in the navbar is clicked, for which I used this code (It works perfectly fine for the navigation bar elements) :
var offset = 68;
$('.navbar li a').click(function(event) {
event.preventDefault();
$($(this).attr('href'))[0].scrollIntoView();
scrollBy(0, -offset);
});
But I have two buttons that also link to certain sections of the website:
<div id="main">
<img src="images/face.png" class="logo">
<div id="promo">
<h2> So, your website doesn't look good anymore? <br><h3> We'll give it a second breath, then support you along the way.</h3></h2>
</div>
<div id="buttons">
<a href="#portfolio"><button id="portbut">
View portfolio
</button></a>
<a href="#contact"><button id="quotebut">
Get a quote
</button></a>
</div>
</div>
But when I place their id's in the js code I mention above, it's not working, the offset is not taken into consideration when "moving" to a certain section of the website.
What should I edit so the offset would be taken into consideration for those two buttons ?
If someone ever needs it, the answer is:
var offset = 68;
$('#buttons a').click(function(event) {
event.preventDefault();
$($(this).attr('href'))[0].scrollIntoView();
scrollBy(0, -offset);
});

Javascript: Vertical Spacing between two elements

My website consists of a navigation bar (class .nav-primary), a widget box (id #mw-panel) and an article. Recently, I tried to move the widget box up to the top, by applying the following changes to my CSS file:
.mw-panel{top: 50px;}
The problem with this option was, that my element was fixed to a specific position. Instead I wanted the widget element to be exactly 100px under the menu bar (and moving when I am scrolling down the page). Instantly, I knew that JavaScript would be the correct way to solve this problem.
Because I had no success, I asked the StackOverflow community, which helped me a lot.
The JavaScript code in the JS section of the attached code snippet, was partially done by me, but it does not work as it should.
Can someone explain me what I need to change to get this JS code working? Again, #mw-panel has to be positioned exactly 100px beneath .nav-primary.
var menu = document.getElementsByClassName("nav-primary")[0];
var widget = document.getElementById("mw-panel");
var difference = widget.offsetTop - menu.offsetBottom;
if (difference > 100) {
document.getElementById("mw-panel").style.top = (menu.offsetBottom + 100) + "px";
}
.content .entry {
margin-top: 40px;
padding-bottom: 400px;
}
<body class="full-width-content">
<link rel="stylesheet" id="child-theme-css" href="http://vocaloid.de/wp-content/themes/Vuturize/style.css" type="text/css" >
<div class="site-container">
<nav class="nav-primary">
<div class="wrap">
<ul class="menu genesis-nav-menu menu-primary">
<li class="menu-item">Home
</li>
<li class="menu-item">News
</li>
<li class="menu-item">Ranking
</li>
</ul>
</div>
</nav>
</div>
<div class="site-inner">
<div class="content-sidebar-wrap">
<main class="content">
<article class="page entry">
<div>
<h1>Test Article</h1>
</div>
</article>
</main>
</div>
</div>
<div id="mw-panel">
<div>
<h3>Navigation</h3>
<div>
<ul>
<li>Letzte Änderungen
</li>
</ul>
</div>
</div>
<h3>Werkzeuge</h3>
<div>
<ul>
<li>Datei hochladen
</li>
<li>Spezialseiten
</li>
</ul>
</div>
</div>
</body>
There's No such property as offsetBottom. Redo your code ONLY considering offsetTop + offsetHeight to get bottom number.
Example:
var menu = document.getElementsByClassName("nav-primary")
var TrueOffset=menu[0].offsetTop+menu[0].offsetHeight;
You're getting the error because there is no offsetBottom property.
Do console.log(menu) in chrome to see the objects available properties
**Update:
Add this to your css:
.mw-panel{
position: absolute;
}
Here it is in action
Updated code in action
After re-reading your question, I missed one key detail: you're trying to do this JavaScript. This is your problem.
If I understand correctly, you have three items: a nav, an article, and a widget box. You want the widget box to stand 100px below the nav, and then move with the page when you scroll.
if this is the case (if not, correct me), then there's only a few things you need to do:
Keep your nav the way it is. Good job here.
I'm assuming you want the widget next to the article (on the left?). So you'll need to make two columns (some sort of containers, each height: 100%). Your widget container will have the property position: fixed; and the article will have position: static; (or relative, you decide).
Each container will have a width, you might choose 30% for the widget container and 70% for the article, for example.
Now you have two columns, one will move with the page as you scroll.
Here are some links to get you started:
Best Way to do Columns in HTML/CSS
https://css-tricks.com/guide-responsive-friendly-css-columns/
http://www.456bereastreet.com/lab/developing_with_web_standards/csslayout/2-col/

I need javascript on one page to influence elements on a different page

I'm using javascript to control where my page page scrolls to after clicking on an anchor link, as I have a fixed nav.
I have one page that the anchors + script work correctly on (PAGE B). My issue is that I have buttons on a different page (PAGE A) that need to go the anchors on the correctly working page (PAGE B). The anchor itself works correctly, but the javascript does not fire.
The reason why it's not firing (tested by putting an alert and not receiving a popup) is because the javascript for the buttons on PAGE A does not know to look for the element on PAGE B. After googling for three hours I cannot figure out how to tell it to look at a new page instead of just the hierarchy of elements. I'm sure this is stupidly simple, but I'm a beginner at javascript and appreciate the help.
The code:
PAGE A Button HTML:
<a href="productsandservices.html#financing" class="btn btn-sm btn-default
actively2">Learn more</a>
PAGE A Javascript:
<script>
$("div ul li a[href^='productsandservices.html#']").on('click', function(e) {
// prevent default anchor click behavior
e.preventDefault();
// animate
$('html, body').animate({
scrollTop: $(this.hash).offset().top - 150
}, 300, function(){
});
});</script>
PAGE B Anchor HTML:
<div class="col-md-10 col-md-offset-1 col-sm-12 col-xs-12"><section id="financing">
PAGE B: Javascript: (the exact same as PAGE A)
$("div ul li a[href^='productsandservices.html#']").on('click', function(e) {
// prevent default anchor click behavior
e.preventDefault();
// animate
$('html, body').animate({
scrollTop: $(this.hash).offset().top - 150
}, 300, function(){
});
});</script>
Please and Thanks.
Page B will never be able to respond to a click event on the previous page, which seems to be what you're trying to do in the code.
Try using location.hash to access the hash instead.
$(window).on('hashchange', function(e) {
$('html, body').animate({
scrollTop: $(location.hash).offset().top - 150
}, 300);
});
I also came up with a different solution.
I moved added a names, and placed them at the end of the previous div before the section id. Then I added some extra padding to each header of the anchor. This way, I can smoothly travel to an anchor on a different page. Arguably, this does not solve my javascript issue, but it can count as (not too badly) hacked work-around.
Not sure the contribution was worth it but as I'm always asking and never giving solutions as I'm still learning I figured I could at least answer my own question!
Basically, instead of having
<div class="a">
<section id="a"><h2>Title</h2></section>
<p>yadda yadda</p>
</div>
<div class="b">
<section id="b"><h2>Title</h2></section>
<p>yadda yadda</p>
</div>
<div class="c">
<section id="c"><h2>Title</h2></section>
<p>yadda yadda</p>
</div>
I added 30px of padding to each div in the css:
div.a, div.b, div.c {
padding:30px 0px;
}
And added a names to the section above the div in question, like so:
yadda yadda
<div class="a">
<section id="a"><h2>Title</h2></section>
<p>yadda yadda</p>
<a name="#b"> </a>
</div>
<div class="b">
<section id="b"><h2>Title</h2></section>
<p>yadda yadda</p>
<a name="#c"> </a>
</div>
<div class="c">
<section id="c"><h2>Title</h2></section>
<p>yadda yadda</p>
</div>
I understand the a name is depreciated using HTML5, but drupal 7 has an issue with recognizing relative anchors. This also solved that issue.

how does accordion works?

I'm not asking how to show/hide content upon click.
All I want to know is how by placing 2 divs, one on top the other, I can get the effect that by clicking on the bottom div, it "closing" the upper div. that's all. Not exactly accordion, but this is enough for my situation.
I tried to achieve this by animating the upper div height to 0, after clicking the bottom div. It works but not smoothly enough. and IE browsers didn't like it:
JQUERY
$('#BottomDiv').click(function() {
$('#UpperDiv').animate({ height: '0px' }, "slow");
});
in the markup side, both divs are position - relative:
HTML
<div id="UpperDiv" style="height:190px; width:100%; margin-top:80px; position:relative">
</div>
<div id="BottomDiv" style="width:100%; position:relative; z-index:10; float:left;" >
</div>
So I was just curious maybe there is a better way to achieve this, like jQuery accordion does it. Smooth and works for all browsers.
Assuming a structure such as:
<div id="accordionWrapper">
<div id="UpperDiv" class="accordionSlides">
<h2>Accordion tab</h2>
<!-- other content, 'p' elements in the demo -->
</div>
<div id="MiddleDiv" class="accordionSlides">
<h2>Accordion tab</h2>
<!-- other content, 'p' elements in the demo -->
</div>
<div id="BottomDiv" class="accordionSlides">
<h2>Accordion tab</h2>
<!-- other content, 'p' elements in the demo -->
</div>
</div>​
Then I'd suggest:
$('#accordionWrapper .accordionSlides').click(
function(){
var cur = $(this);
cur.siblings().children().not('h2').slideUp(); // hides
cur.find('p').slideToggle(); // shows
});​
JS Fiddle demo.
References:
children().
click().
find().
not().
slideToggle().
slideUp().
Does this help ?
Markup:
<div id="UpperDiv" style='background:red;height:200px;'>
</div>
<div id="BottomDiv" style="background:Gray;height:200px;">
</div>
Javascript:
$('#BottomDiv').click(function() {
$('#UpperDiv').slideUp("slow","linear");
});
$('#BottomDiv').click(function() {
$('#UpperDiv').css("display", 'none');
});
The simple solution is above, however, more elegant would be to define a css class such as:
.invisible
{
display: none;
}
and you can make something invisible by using the addClass function and you can remove this class by using removeClass from the tag to make it visible again.

Categories