navbar opacity/rgba change on scroll - javascript

I've been trying to create a nav that would be transparent at the top and would gain white color as the user scrolls down the page. My header height is 800px and I want my nav to lose 100% of transparency after those 800px. Here`s my code:
<header id="header">
<nav class="navbar">
<ul class="navigation">
<li>Home</li>
<li>About us</li>
<li>Our qualities</li>
<li>Contact us</li>
<li>contact us</li>
</ul>
</nav>
nav {
width: 1600px;
position: fixed;
top: 0;
ul {
margin: 0 auto;
li {
display: inline-block;
padding: 5px 20px;
a {
font-family: $f1;
font-size: 16pt;
color: $c3;
}
}
}
}
}
First I tried with opacity, but it didn't work, and on top of that child elements (ul and li) had opacity of 0 as well.
Here`s the JS for that:
jQuery(document).ready( function() {
var navOffset = jQuery("nav").offset().top;
jQuery(window).scroll(function() {
var scrollPos = jQuery(window).scrollTop();
var navOpacity = scrollPos /800;
jQuery('.navbar').css(opacity, 'navOpacity');
if (jQuery('nav').css('opacity') < 1) {
jQuery('.navigation').css('opacity', '1')
};
Then I tried to change RGBA value on scroll, that didn't work either
Instead of
jQuery('.navbar').css( opacity, 'navOpacity' );
I used
jQuery('.navbar').css(backgroundcolor, 'rgba (255, 255, 255, + "navOpacity")');
That failed as well, so, I have to ask you too help me

You have made opacity not a string, but the variable navOpacity has become a string. That was wrong. Everything else is working fine in general. :)
// change
$('.navbar').css(opacity, "navOpacity");
// to
$('.navbar').css("opacity", navOpacity);
Working example.

The issue in your code is that you're providing navOpacity as a string to css(), instead of the variable itself. Try this:
$('.navbar').css('opacity', navOpacity);
Also note that your current logic is backwards to what you describe as your goal (the header starts transparent and becomes opaque at 800px) and the logic can also be simplified a lot. Try this:
$(window).scroll(function() {
var pc = $(this).scrollTop() / 800;
$('.navbar').css('opacity', 1 - pc);
});
Working example

Alternatively you could use jquery method .fadeTo() instead of css('opacity'). This method animates the opacity of the elements smoothly. It is easier to use and the animation is pretty good looking compared to instant opacity change.
jQuery('.navbar').fadeTo( "slow" , navOpacity);
if (jQuery('nav').css('opacity') < 1) {
jQuery('.navigation').fadeTo( "slow" , 1);
};

Related

Make anchor link go some pixels above id

I'm currently working on a website and I'm having a trouble with anchors. My header is fixed and when I click on anchor it sends me on other page how it is supposed to be, but I'm missing 80 pixels which is height of my fixed header. There is a script that made accordion opened on new page when I click on anchor but it should scroll 80px less... here is some code I have over there in my .jsp file
<a href="${parentLink}#${menuItem.name}" class="${menuItem.classes[anchorClasses]}">
and there is a .js that makes my accordion opened on the new page
$(document).ready(function () {
if (location.hash != null && location.hash != "") {
$('.collapse').removeClass('in');
$(location.hash + '.collapse').collapse('show');
}
});
I think that you guys will need more info, so ask me anything that could help you. I'm new in this and I don't even know which code should I post here to help you guys realize what the problem is... Thank you (:
One common way is to add an invisible pseudo element to the original target element of the link via CSS, like this:
#your_anchor_id::before {
display: block;
content: " ";
margin-top: -80px;
height: 80px;
visibility: hidden;
pointer-events: none;
}
This will "extend" the element with that ID in a way which causes the anchor to be 80px above the main element, without causing any other visible changes.
Another idea is to use smooth scrolling with an offset. (View the example "Full Page" by clicking that link at top right of the snippet window)
$("nav ul li a").on('click', function(event) {
if (this.hash !== "") {
var myOffset = $('#myOff').val(); //get value from input (offset value)
if (myOffset==='') $('input').addClass('alert');
event.preventDefault(); // Prevent default anchor click behavior
var hash = this.hash; // Store hash
// jQuery animate() method for smooth page scroll
// 900 is the number of ms to scroll to the specified area
$('html, body').animate({
scrollTop: $(hash).offset().top - myOffset
}, 900);
} // End if
});
//$('div:contains(Section)').css('font-weight','bold');
html,body{margin:0;padding:0;font-family:Calibri;}
body{height:2500px;}
ul,li{margin:0;padding:0;}
*{box-sizing:border-box;}
section{
display: grid;
place-items: center;
width: 100%;
height: 500px;
}
nav{position:fixed;width:80vw;background:white;border:1px solid red;}
::placeholder{color:#ccc;}
nav ul li{
display: inline-block;
padding:0;
border: 1px solid rgba(200,200,200,0.3);
}
nav ul li:hover{background: #ddd;}
a{text-decoration:none;padding:10px 25px;display:inline-block;}
#one{background:palegreen; padding:50px;}
#two{background:palegoldenrod;}
#twa{background:lightblue;}
#fer{height:1500px;}
.alert{border:1px solid red;background:#ffc0cb99;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav>
<ul>
<li>NAV / HEADER:</li>
<li>One</li>
<li>Two</li>
<li>Three</li>
<li><input id="myOff" type="text" placeholder="Offset (e.g. 75):" /></li>
</ul>
</nav>
<section id="one">
<div>
<div style="text-align:center">Section One</div>
<div>Directions:<br>(a) View as Full Page (link at top right)<br>(b) Enter offset number (for how many pixels the smooth-scroll will stop short)<br>(c) Click nav "Two" or "Three" and observe<br>(4) Repeat using a different offset value<br>Note: The fixed header is deliberately not full width in order to show the top of the next section scrolling UNDER the header (undesireable) The offset prevents that, and is what you are asking about.</div>
</div>
</section>
<section id="two">
Section Two
</section>
<section id="twa">
Section Three
</section>
<section id="fer">
Section Four
</section>
Example code ripped off from:
w3schools Company Theme example

Reveal nav when scrolling down

What I'm trying to achieve is when a page is scrolled down the navigation is hidden - as in it disappears off the top of the screen like it traditionally would. When a user scrolls back up the page, the navigation slides into view again. Likewise, if you scroll down again, it's hidden.
I've tried a few different plugins for this and they nearly work. The one I'm currently looking at is "jquery-unveiled-navigation"
Link: https://github.com/weaintplastic/jquery-unveiled-navigation
Example: http://codepen.io/weaintplastic/full/RNpXOO/
This very nearly does what I want it to. It could do with some classes once the script is 'active'. As I only want to add a background-color when the script is 'active'. So it would be transparent until the navigation had left the screen and wasn't at the top.
Also, I know with this navigation if you scroll back up so half the navigation is in view, it will quickly adjust so you can see the bar in it's entirety. But I quite like the idea of it only showing as much as you've scrolled up by. So if the nav is 100px tall, and you scroll 30px, you only see the bottom 30px of the bar. Scrolling back down would hide the bar again, pixel by pixel - does that make sense?
So the steps would be (if this makes it clearer):
Header at the top of the page, transparent background.
When scrolling down, pixel by pixel the navigation leaves the screen.
When the user scrolls back up, the header starts to reveal it's self again - this time is has a background-color.
Once header hits the top of the browser again, the background is removed.
My markup is pretty simple. The bar only holds a logo and navigation toggle as the nav is hidden until the toggle is clicked, which displays the nav full screen.
<header class="page-head">
<span>Menu</span>
<nav class="site-nav">
<ul class="site-nav__list">
<li class="site-nav__item">Link</li>
<li class="site-nav__item">Link</li>
<li class="site-nav__item">Link</li>
<li class="site-nav__item">Link</li>
<li class="site-nav__item">Link</li>
</ul>
</nav>
</header>
I've removed the SVG I have within page-head__home-link otherwise it would be a wall of code!
Hope someone can help :)
You can do this pretty easily without jquery or a library. You just need to watch the scroll event and when the direction changes place the header just above the field of vision and then as you continue to scroll make sure it never moves off of the top of the parent container.
var body, direction, margin, pageHead, pageHeadHeight, scrolled;
body = document.getElementById('tall');
scrolled = 0;
direction = null;
pageHead = document.getElementsByClassName('page-head')[0];
pageHeadHeight = pageHead.offsetHeight - 1;
margin = 0;
body.addEventListener("scroll", function(event) {
if (scrolled < body.scrollTop) {
direction = 'down';
} else {
if (direction === 'down') {
direction = 'up';
margin = Math.max(0, body.scrollTop - pageHeadHeight);
}
if (margin > body.scrollTop) {
margin = body.scrollTop;
}
pageHead.style['margin-top'] = margin + 'px';
}
return scrolled = body.scrollTop;
});
.tall {
background-color: blue;
min-height: 3000px;
min-width: 100%;
}
#tall {
max-height: 180px;
border: 3px solid pink;
overflow: auto;
}
.page-head{
color: white;
display: inline-block;
}
a {
color: white;
}
<div id="tall">
<div class='tall'>
<header class="page-head">
<span>Menu</span>
<nav class="site-nav">
<ul class="site-nav__list">
<li class="site-nav__item">Link</li>
<li class="site-nav__item">Link</li>
<li class="site-nav__item">Link</li>
<li class="site-nav__item">Link</li>
<li class="site-nav__item">Link</li>
</ul>
</nav>
</header>
</div>
</div>

jQuery plugin stops working when assigning an id to an element

I have an issue I was hoping someone could kindly help me with. I'm currently building a webiste, and tried to use a jquery plugin for the first time to create a sticky navigation bar (http://stanhub.com/scroll-to-top-then-fixed-navigation-effect-with-jquery-and-css-free-download/).
When I assign an #ID to the nav tag, and change the CSS rule accordingly to apply just on this specific nav, the plugin stops working. The problem is that I would like to have a few navs on my page and I don't see another option.
Any suggestions?
Thanks!
And here is a link to the full code:
http://codepen.io/anon/pen/gbQBOo
HTML:
<section id="screen1">
<p>Scroll down</p>
<nav id="main-nav">
<ul>
<li>Home</li>
<li>About</li>
<li>Services</li>
<li>Team</li>
<li>Contact</li>
</ul>
</nav>
</section>
<section id="screen2"></section>
<section id="screen3"></section>
CSS:
/* Navigation Settings */
#main-nav {
position: absolute;
bottom: 0;
width: 100%;
height: 70px;
background: #fff;
}
JS:
$(document).ready(function(){
$(window).bind('scroll', function() {
var navHeight = $( window ).height() - 70;
if ($(window).scrollTop() > navHeight) {
$('#main-nav').addClass('fixed');
}
else {
$('#main-nav').removeClass('fixed');
}
});
});
In CSS, #main-nav is more precise than .fixed, so it takes precedence.
You could:
1) change .fixed into #main-nav.fixed
2) set the position from .fixed to fixed!important
3) not use an id but a specific class for your nav, and make sure .fixed is defined after that new class

The "Hide div before scrolling" codes does not work no matter what

I'm building a local website on the Bitnami Wordpress Stack with the Arras theme, if that's important.
I'm making a fixed menu that I want to show after I have scrolled 190 pixels down on the page. The problem is that anything works, no matter which JQuery or JavaScript code I try. I have searched and searched here on StackOverflow, and I know that this question have been asked numerous times here before - but I have tried every code I could find, and none works. This is my JavaScript/JQuery/HTML/PHP code for my menu, placed in the header.php file:
<div class="medfolg" id="medfolg">
<script type="text/javascript">
$(document).ready(function(){
$(window).bind('scroll', function(){
if($(window).scrollTop() > 190){
$('#medfolg').show();
} else {
$('#medfolg').hide();
};
});
});
</script>
<?php
if ( function_exists('wp_nav_menu') ) {
wp_nav_menu( array(
'menu' => 'medfolg',
'menu_class' => 'sf-menu'
) );
}
?>
</div>
And this is the CSS code I have placed in my default.css file:
#medfolg.medfolg {position:fixed;}
#medfolg { text-transform: lowercase; position: absolute; top: 0; width: 100%; background: #f5f5f5; z-index:5000; display: none;}
#medfolg .menu-medfolg-container { width: 980px; margin: 0 auto; }
#medfolg .sf-menu { position: relative; top:3px !important; }
#medfolg .sf-menu a { font-size: 22px; color: #444; margin-right: 15px;}
I desperately need some help - please!
EDIT: I've made a jsFiddle here with only small modifications (Wordpress .php menu cannot be read on other places than Wordpress): http://jsfiddle.net/wHMjr/
For completeness, I will post my code:
First, the code is wrapped with a self-executing function to prevent conflict between libraries:
(function($){
//code goes here, now $ is a local reference to the jQuery object.
})(jQuery)
Then, I create the handler:
var setMenuVisibility = function(){
if($(window).scrollTop() > 190){
$('#medfolg').show();
} else {
$('#medfolg').hide();
};
}
which will be attached to the window's scroll event and change the menu's visibility according to the scroll status.
The attachment is done by binding the function to the event:
$(window).bind('scroll', setMenuVisibility);
//and set the initial visibility
setMenuVisibility();
The last line in the above section sets the initial state of the menu, as it is possible that the initial scroll value would require it to be visible (e.g, a link to a lower subsection of the page).
The entire process is initiated when the document's markup is ready.
See demo here.
Try using vanilla js instaead of $(window).scrollTop() try window.scrollY > 190
for the complete function I would use toggle too so:
jQuery
//Use jQuery to make sure we are using correct function
jQuery(window).on('scroll', function () {
var el = jQuery('#medfolg');
if (window.scrollY > 100) {
el.show(); //Use this to toggle element visibility
} else {
el.hide()
}
});
HTML
<div style="display:none" id="medfolg">
<ul>
<li>Home
</li>
<li>Tutorials
</li>
<li>Articles
</li>
<li>Inspiration
</li>
</ul>
</div>
Demo

offsetting an html anchor to adjust for fixed header [duplicate]

This question already has answers here:
Fixed page header overlaps in-page anchors
(38 answers)
Closed 7 years ago.
I am trying to clean up the way my anchors work. I have a header that is fixed to the top of the page, so when you link to an anchor elsewhere in the page, the page jumps so the anchor is at the top of the page, leaving the content behind the fixed header (I hope that makes sense). I need a way to offset the anchor by the 25px from the height of the header. I would prefer HTML or CSS, but Javascript would be acceptable as well.
You could just use CSS without any javascript.
Give your anchor a class:
<a class="anchor" id="top"></a>
You can then position the anchor an offset higher or lower than where it actually appears on the page, by making it a block element and relatively positioning it. -250px will position the anchor up 250px
a.anchor {
display: block;
position: relative;
top: -250px;
visibility: hidden;
}
I found this solution:
<a name="myanchor">
<h1 style="padding-top: 40px; margin-top: -40px;">My anchor</h1>
</a>
This doesn't create any gap in the content and anchor links works really nice.
I was looking for a solution to this as well. In my case, it was pretty easy.
I have a list menu with all the links:
<ul>
<li>one</li>
<li>two</li>
<li>three</li>
<li>four</li>
</ul>
And below that the headings where it should go to.
<h3>one</h3>
<p>text here</p>
<h3>two</h3>
<p>text here</p>
<h3>three</h3>
<p>text here</p>
<h3>four</h3>
<p>text here</p>
Now because I have a fixed menu at the top of my page I can't just make it go to my tag because that would be behind the menu.
Instead, I put a span tag inside my tag with the proper id.
<h3><span id="one"></span>one</h3>
Now use 2 lines of CSS to position them properly.
h3{ position:relative; }
h3 span{ position:absolute; top:-200px;}
Change the top value to match the height of your fixed header (or more).
Now I assume this would work with other elements as well.
FWIW this worked for me:
[id]::before {
content: '';
display: block;
height: 75px;
margin-top: -75px;
visibility: hidden;
}
As this is a concern of presentation, a pure CSS solution would be ideal. However, this question was posed in 2012, and although relative positioning / negative margin solutions have been suggested, these approaches seem rather hacky, create potential flow issues, and cannot respond dynamically to changes in the DOM / viewport.
With that in mind I believe that using JavaScript is still (February 2017) the best approach. Below is a vanilla-JS solution which will respond both to anchor clicks and resolve the page hash on load (See JSFiddle). Modify the .getFixedOffset() method if dynamic calculations are required. If you're using jQuery, here's a modified solution with better event delegation and smooth scrolling.
(function(document, history, location) {
var HISTORY_SUPPORT = !!(history && history.pushState);
var anchorScrolls = {
ANCHOR_REGEX: /^#[^ ]+$/,
OFFSET_HEIGHT_PX: 50,
/**
* Establish events, and fix initial scroll position if a hash is provided.
*/
init: function() {
this.scrollToCurrent();
window.addEventListener('hashchange', this.scrollToCurrent.bind(this));
document.body.addEventListener('click', this.delegateAnchors.bind(this));
},
/**
* Return the offset amount to deduct from the normal scroll position.
* Modify as appropriate to allow for dynamic calculations
*/
getFixedOffset: function() {
return this.OFFSET_HEIGHT_PX;
},
/**
* If the provided href is an anchor which resolves to an element on the
* page, scroll to it.
* #param {String} href
* #return {Boolean} - Was the href an anchor.
*/
scrollIfAnchor: function(href, pushToHistory) {
var match, rect, anchorOffset;
if(!this.ANCHOR_REGEX.test(href)) {
return false;
}
match = document.getElementById(href.slice(1));
if(match) {
rect = match.getBoundingClientRect();
anchorOffset = window.pageYOffset + rect.top - this.getFixedOffset();
window.scrollTo(window.pageXOffset, anchorOffset);
// Add the state to history as-per normal anchor links
if(HISTORY_SUPPORT && pushToHistory) {
history.pushState({}, document.title, location.pathname + href);
}
}
return !!match;
},
/**
* Attempt to scroll to the current location's hash.
*/
scrollToCurrent: function() {
this.scrollIfAnchor(window.location.hash);
},
/**
* If the click event's target was an anchor, fix the scroll position.
*/
delegateAnchors: function(e) {
var elem = e.target;
if(
elem.nodeName === 'A' &&
this.scrollIfAnchor(elem.getAttribute('href'), true)
) {
e.preventDefault();
}
}
};
window.addEventListener(
'DOMContentLoaded', anchorScrolls.init.bind(anchorScrolls)
);
})(window.document, window.history, window.location);
Pure css solution inspired by Alexander Savin:
a[name] {
padding-top: 40px;
margin-top: -40px;
display: inline-block; /* required for webkit browsers */
}
Optionally you may want to add the following if the target is still off the screen:
vertical-align: top;
My solution combines the target and before selectors for our CMS. Other techniques don't account for text in the anchor. Adjust the height and the negative margin to the offset you need...
:target::before {
content: '';
display: block;
height: 180px;
margin-top: -180px;
}
This takes many elements from previous answers and combines into a tiny (194 bytes minified) anonymous jQuery function. Adjust fixedElementHeight for the height of your menu or blocking element.
(function($, window) {
var adjustAnchor = function() {
var $anchor = $(':target'),
fixedElementHeight = 100;
if ($anchor.length > 0) {
$('html, body')
.stop()
.animate({
scrollTop: $anchor.offset().top - fixedElementHeight
}, 200);
}
};
$(window).on('hashchange load', function() {
adjustAnchor();
});
})(jQuery, window);
If you don't like the animation, replace
$('html, body')
.stop()
.animate({
scrollTop: $anchor.offset().top - fixedElementHeight
}, 200);
with:
window.scrollTo(0, $anchor.offset().top - fixedElementHeight);
Uglified version:
!function(o,n){var t=function(){var n=o(":target"),t=100;n.length>0&&o("html, body").stop().animate({scrollTop:n.offset().top-t},200)};o(n).on("hashchange load",function(){t()})}(jQuery,window);
For modern browsers, just add the CSS3 :target selector to the page. This will apply to all the anchors automatically.
:target {
display: block;
position: relative;
top: -100px;
visibility: hidden;
}
You can do it without js and without altering html. It´s css-only.
a[id]::before {
content: '';
display: block;
height: 50px;
margin: -30px 0 0;
}
That will append a pseudo-element before every a-tag with an id. Adjust values to match the height of your header.
I had been facing a similar issue, unfortunately after implementing all the solutions above, I came to the following conclusion.
My inner elements had a fragile CSS structure and implementing a position relative / absolute play, was completely breaking the page design.
CSS is not my strong suit.
I wrote this simple scrolling js, that accounts for the offset caused due to the header and relocated the div about 125 pixels below. Please use it as you see fit.
The HTML
<div id="#anchor"></div> <!-- #anchor here is the anchor tag which is on your URL -->
The JavaScript
$(function() {
$('a[href*=#]:not([href=#])').click(function() {
if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'')
&& location.hostname == this.hostname) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top - 125 //offsets for fixed header
}, 1000);
return false;
}
}
});
//Executed on page load with URL containing an anchor tag.
if($(location.href.split("#")[1])) {
var target = $('#'+location.href.split("#")[1]);
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top - 125 //offset height of header here too.
}, 1000);
return false;
}
}
});
See a live implementation here.
For the same issue, I used an easy solution : put a padding-top of 40px on each anchor.
As #moeffju suggests, this can be achieved with CSS. The issue I ran into (which I'm surprised I haven't seen discussed) is the trick of overlapping previous elements with padding or a transparent border prevents hover and click actions at the bottom of those sections because the following one comes higher in the z-order.
The best fix I found was to place section content in a div that is at z-index: 1:
// Apply to elements that serve as anchors
.offset-anchor {
border-top: 75px solid transparent;
margin: -75px 0 0;
-webkit-background-clip: padding-box;
-moz-background-clip: padding;
background-clip: padding-box;
}
// Because offset-anchor causes sections to overlap the bottom of previous ones,
// we need to put content higher so links aren't blocked by the transparent border.
.container {
position: relative;
z-index: 1;
}
Solutions with changing position property are not always possible (it can destroy layout) therefore I suggest this:
HTML:
<a id="top">Anchor</a>
CSS:
#top {
margin-top: -250px;
padding-top: 250px;
}
Use this:
<a id="top"> </a>
to minimize overlapping, and set font-size to 1px. Empty anchor will not work in some browsers.
Borrowing some of the code from an answer given at this link (no author is specified), you can include a nice smooth-scroll effect to the anchor, while making it stop at -60px above the anchor, fitting nicely underneath the fixed bootstrap navigation bar (requires jQuery):
$(".dropdown-menu a[href^='#']").on('click', function(e) {
// prevent default anchor click behavior
e.preventDefault();
// animate
$('html, body').animate({
scrollTop: $(this.hash).offset().top - 60
}, 300, function(){
});
});
The above methods don't work very well if your anchor is a table element or within a table (row or cell).
I had to use javascript and bind to the window hashchange event to work around this (demo):
function moveUnderNav() {
var $el, h = window.location.hash;
if (h) {
$el = $(h);
if ($el.length && $el.closest('table').length) {
$('body').scrollTop( $el.closest('table, tr').position().top - 26 );
}
}
}
$(window)
.load(function () {
moveUnderNav();
})
.on('hashchange', function () {
moveUnderNav();
});
* Note: The hashchange event is not available in all browsers.
You can achieve this without an ID using the a[name]:not([href]) css selector. This simply looks for links with a name and no href e.g. <a name="anc1"></a>
An example rule might be:
a[name]:not([href]){
display: block;
position: relative;
top: -100px;
visibility: hidden;
}
Instead of having a fixed-position navbar which is underlapped by the rest of the content of the page (with the whole page body being scrollable), consider instead having a non-scrollable body with a static navbar and then having the page content in an absolutely-positioned scrollable div below.
That is, have HTML like this...
<div class="static-navbar">NAVBAR</div>
<div class="scrollable-content">
<p>Bla bla bla</p>
<p>Yadda yadda yadda</p>
<p>Mary had a little lamb</p>
<h2 id="stuff-i-want-to-link-to">Stuff</h2>
<p>More nonsense</p>
</div>
... and CSS like this:
.static-navbar {
height: 100px;
}
.scrollable-content {
position: absolute;
top: 100px;
bottom: 0;
overflow-y: scroll;
width: 100%;
}
There is one significant downside to this approach, however, which is that while an element from the page header is focused, the user will not be able to scroll the page using the keyboard (e.g. via the up and down arrows or the Page Up and Page Down keys).
Here's a JSFiddle demonstrating this in action.
This was inspired by the answer by Shouvik - same concept as his, only the size of the fixed header isn't hard coded. As long as your fixed header is in the first header node, this should "just work"
/*jslint browser: true, plusplus: true, regexp: true */
function anchorScroll(fragment) {
"use strict";
var amount, ttarget;
amount = $('header').height();
ttarget = $('#' + fragment);
$('html,body').animate({ scrollTop: ttarget.offset().top - amount }, 250);
return false;
}
function outsideToHash() {
"use strict";
var fragment;
if (window.location.hash) {
fragment = window.location.hash.substring(1);
anchorScroll(fragment);
}
}
function insideToHash(nnode) {
"use strict";
var fragment;
fragment = $(nnode).attr('href').substring(1);
anchorScroll(fragment);
}
$(document).ready(function () {
"use strict";
$("a[href^='#']").bind('click', function () {insideToHash(this); });
outsideToHash();
});
I'm facing this problem in a TYPO3 website, where all "Content Elements" are wrapped with something like:
<div id="c1234" class="contentElement">...</div>
and i changed the rendering so it renders like this:
<div id="c1234" class="anchor"></div>
<div class="contentElement">...</div>
And this CSS:
.anchor{
position: relative;
top: -50px;
}
The fixed topbar being 40px high, now the anchors work again and start 10px under the topbar.
Only drawback of this technique is you can no longer use :target.
Adding to Ziav's answer (with thanks to Alexander Savin), I need to be using the old-school <a name="...">...</a> as we're using <div id="...">...</div> for another purpose in our code. I had some display issues using display: inline-block -- the first line of every <p> element was turning out to be slightly right-indented (on both Webkit and Firefox browsers). I ended up trying other display values and display: table-caption works perfectly for me.
.anchor {
padding-top: 60px;
margin-top: -60px;
display: table-caption;
}
I added 40px-height .vspace element holding the anchor before each of my h1 elements.
<div class="vspace" id="gherkin"></div>
<div class="page-header">
<h1>Gherkin</h1>
</div>
In the CSS:
.vspace { height: 40px;}
It's working great and the space is not chocking.
how about hidden span tags with linkable IDs that provide the height of the navbar:
#head1 {
padding-top: 60px;
height: 0px;
visibility: hidden;
}
<span class="head1">somecontent</span>
<h5 id="headline1">This Headline is not obscured</h5>
heres the fiddle: http://jsfiddle.net/N6f2f/7
You can also add an anchor with follow attr:
(text-indent:-99999px;)
visibility: hidden;
position:absolute;
top:-80px;
and give the parent container a position relative.
Works perfect for me.
A further twist to the excellent answer from #Jan is to incorporate this into the #uberbar fixed header, which uses jQuery (or MooTools). (http://davidwalsh.name/persistent-header-opacity)
I've tweaked the code so the the top of the content is always below not under the fixed header and also added the anchors from #Jan again making sure that the anchors are always positioned below the fixed header.
The CSS:
#uberbar {
border-bottom:1px solid #0000cc;
position:fixed;
top:0;
left:0;
z-index:2000;
width:100%;
}
a.anchor {
display: block;
position: relative;
visibility: hidden;
}
The jQuery (including tweaks to both the #uberbar and the anchor approaches:
<script type="text/javascript">
$(document).ready(function() {
(function() {
//settings
var fadeSpeed = 200, fadeTo = 0.85, topDistance = 30;
var topbarME = function() { $('#uberbar').fadeTo(fadeSpeed,1); }, topbarML = function() { $('#uberbar').fadeTo(fadeSpeed,fadeTo); };
var inside = false;
//do
$(window).scroll(function() {
position = $(window).scrollTop();
if(position > topDistance && !inside) {
//add events
topbarML();
$('#uberbar').bind('mouseenter',topbarME);
$('#uberbar').bind('mouseleave',topbarML);
inside = true;
}
else if (position < topDistance){
topbarME();
$('#uberbar').unbind('mouseenter',topbarME);
$('#uberbar').unbind('mouseleave',topbarML);
inside = false;
}
});
$('#content').css({'margin-top': $('#uberbar').outerHeight(true)});
$('a.anchor').css({'top': - $('#uberbar').outerHeight(true)});
})();
});
</script>
And finally the HTML:
<div id="uberbar">
<!--CONTENT OF FIXED HEADER-->
</div>
....
<div id="content">
<!--MAIN CONTENT-->
....
<a class="anchor" id="anchor1"></a>
....
<a class="anchor" id="anchor2"></a>
....
</div>
Maybe this is useful to somebody who likes the #uberbar fading dixed header!
#AlexanderSavin's solution works great in WebKit browsers for me.
I additionally had to use :target pseudo-class which applies style to the selected anchor to adjust padding in FF, Opera & IE9:
a:target {
padding-top: 40px
}
Note that this style is not for Chrome / Safari so you'll probably have to use css-hacks, conditional comments etc.
Also I'd like to notice that Alexander's solution works due to the fact that targeted element is inline. If you don't want link you could simply change display property:
<div id="myanchor" style="display: inline">
<h1 style="padding-top: 40px; margin-top: -40px;">My anchor</h1>
</div>
Here's the solution that we use on our site. Adjust the headerHeight variable to whatever your header height is. Add the js-scroll class to the anchor that should scroll on click.
// SCROLL ON CLICK
// --------------------------------------------------------------------------
$('.js-scroll').click(function(){
var headerHeight = 60;
$('html, body').animate({
scrollTop: $( $.attr(this, 'href') ).offset().top - headerHeight
}, 500);
return false;
});
I ran into this same issue and ended up handling the click events manually, like:
$('#mynav a').click(() ->
$('html, body').animate({
scrollTop: $($(this).attr('href')).offset().top - 40
}, 200
return false
)
Scroll animation optional, of course.

Categories