HTML5 placeholder disappears on focus - html

Is there a freely available jQuery plugin that changes placeholder behavior to match HTML5 spec?
Before Focus
On Focus Good (Safari)
On Focus Bad (Chrome, Firefox)
You can what your browser does with this simple fiddle.
HTML5 draft spec says:
User agents should present this hint to the user, after having stripped line breaks from it, when the element's value is the empty string and/or the control is not focused (e.g. by displaying it inside a blank unfocused control and hiding it otherwise).
The "/or" is new in current draft so I suppose that's why Chrome and Firefox don't support it yet. See WebKit bug #73629, Chromium bug #103025.

Stefano J. Attardi wrote a nice jQuery plugin that just does that.
It is more stable than Robert's and also fades to a lighter grey when the field gets focused.
See the demo page
Grab it on GitHub
Play with the fiddle
I modified his plugin to read placeholder attribute as opposed to manually creating a span.
This fiddle has complete code:
HTML
<input type="text" placeholder="Hello, world!">
JS
// Original code by Stefano J. Attardi, MIT license
(function($) {
function toggleLabel() {
var input = $(this);
if (!input.parent().hasClass('placeholder')) {
var label = $('<label>').addClass('placeholder');
input.wrap(label);
var span = $('<span>');
span.text(input.attr('placeholder'))
input.removeAttr('placeholder');
span.insertBefore(input);
}
setTimeout(function() {
var def = input.attr('title');
if (!input.val() || (input.val() == def)) {
input.prev('span').css('visibility', '');
if (def) {
var dummy = $('<label></label>').text(def).css('visibility','hidden').appendTo('body');
input.prev('span').css('margin-left', dummy.width() + 3 + 'px');
dummy.remove();
}
} else {
input.prev('span').css('visibility', 'hidden');
}
}, 0);
};
function resetField() {
var def = $(this).attr('title');
if (!$(this).val() || ($(this).val() == def)) {
$(this).val(def);
$(this).prev('span').css('visibility', '');
}
};
var fields = $('input, textarea');
fields.live('mouseup', toggleLabel); // needed for IE reset icon [X]
fields.live('keydown', toggleLabel);
fields.live('paste', toggleLabel);
fields.live('focusin', function() {
$(this).prev('span').css('color', '#ccc');
});
fields.live('focusout', function() {
$(this).prev('span').css('color', '#999');
});
$(function() {
$('input[placeholder], textarea[placeholder]').each(
function() { toggleLabel.call(this); }
);
});
})(jQuery);
CSS
.placeholder {
background: white;
float: left;
clear: both;
}
.placeholder span {
position: absolute;
padding: 5px;
margin-left: 3px;
color: #999;
}
.placeholder input, .placeholder textarea {
position: relative;
margin: 0;
border-width: 1px;
padding: 6px;
background: transparent;
font: inherit;
}
/* Hack to remove Safari's extra padding. Remove if you don't care about pixel-perfection. */
#media screen and (-webkit-min-device-pixel-ratio:0) {
.placeholder input, .placeholder textarea { padding: 4px; }
}

Robert Nyman discusses the problem and documents his approach in his blog.
This fiddle that has all the neccessary HTML, CSS and JS.
Unfortunately, he solves the problem by changing value.
This will not work by definition if placeholder text is itself a valid input.

I found this question by googling out the solution to the same problem. It seems that existing plugins either don't work in elder browsers or hide placeholder on focus.
So I decided to roll on my own solution while trying to combine best parts from existing plugins.
You may check it out here and open an issue if you face any problems.

How about something simple like this? On focus save out the placeholder attribute value and remove the attribute entirely; on blur, put the attribute back:
$('input[type="text"]').focus( function(){
$(this).attr("data-placeholder",$(this).attr('placeholder')).removeAttr("placeholder");
});
$('input[type="text"]').blur( function(){
$(this).attr("placeholder",$(this).attr('data-placeholder'));
});

I wrote my own css3 only solution. See if that fullfills all your needs.
http://codepen.io/fabiandarga/pen/MayNWm
This is my solution:
the input element is set to "required"
an aditional span element for the placeholder is needed. This element is moved on top of the input element (position: absolute;)
with css selectors the input element is tested for validity (required fields are invalid as long as there is no input) and the placeholder is then hidden.
Pitfall: The placeholder is blocking mouseevents to the input! This problem is circumvented by hiding the placeholder element when the mouse is inside the parent (wrapper).
<div class="wrapper">
<input txpe="text" autofocus="autofocus" required/>
<span class="placeholder">Hier text</span>
</div>
.placeholder {
display: none;
position: absolute;
left: 0px;
right: 0;
top: 0px;
color: #A1A1A1;
}
input:invalid + .placeholder {
display: block; /* show the placeholder as long as the "required" field is empty */
}
.wrapper:hover .placeholder {
display: none; /* required to guarantee the input is clickable */
}
.wrapper{
position: relative;
display: inline-block;
}

Maybe you can try with Float Label Pattern :)
See Float labels in CSS

Related

How to show hidden content when hover in CSS

As the title says I want to show a hidden span "box" when hovering an image, but I can't get it to work, so I was hoping you guys could figure out my mistake.
HTML
<span class="DDAA__bg">
<h1 class="DDAA__headline">DANSK DYREVÆRN ÅRHUS</h1>
</span>
<span class="DDAA__pic">
<img src="img/DDAA-Logo.png" width="980" height="200" alt="Dansk Dyreværn Århus"/>
</span>
CSS
span.DDAA__bg{
height: 200px;
width: 980px;
background-color: #666;
position: absolute;
display: none;
}
span.DDAA__pic{
display:block;
visibility: visible;
}
span.DDAA__pic:hover{
visibility: hidden;
transition-delay: 2s;
}
span.DDAA__pic:hover + span.DDAA__bg{
display:block;
}
You can see here how it works now, not as good :/
http://jsfiddle.net/ary3bt83/3/
element:hover > other_element {
display: block;
}
this is equal to the jQuery code
$(element).on('hover', function() { $(this).css("display", "block"); });
But doing hover on css sometimes is really buggy...
First you need to have jQuery installed ( look for jquery.js / jquery.min.js in source code or google for w3c jquery install )
After this you write following :
<script>
$(document).ready(function() {
// everything here is done once the page is loaded
// define hover event handler for a specific element
$(".the_hovered_element").on('hover', function() {
// show the element
$(".the_element_to_be_shown").css("display","block");
});
});
</script>
Don't forget that you must initially set display: none to the div that is first hidden and then shown. Also instead of .css("display","block") you can have simple animation like .fadeIn("slow");

How to remove selection on images

I want to remove the selection-highlight on all images on my page.
I found some useful additions like :
CSS
img {
-webkit-user-select:none;
-khtml-user-select:none;
-moz-user-select:none;
-o-user-select:none;
user-select:none;
pointer-events:none
}
But when I press down my mouse button and select multiple things or press Ctrl+A for "select all" my images get highlighted with a blue shade.
I tried to change it via :
CSS
img::selection {background:transparent;color:inherit;}
img::-moz-selection {background:transparent;color:inherit;}
But that don't have any effect.
Does someone have a useful solution or is there none yet ?
P.S. : I don't care about selecting my images - I just want to get rid of that blue shape.
Here goes a wacky solution I came up with...
1) After some testing I found that this only occurs on mozilla. Other browsers don't show the blue selection on images when the code
img::selection {
background: transparent;
}
is set.
2) Even mozilla - only has a problem with image elements. But other elements with a background-image obey the ::selection rule.
So technically we could work around this assuming we add an empty span in our markup after each img element which we set to display:none;
Then we can add some CSS which will only run in firefox which sets the images to display:none and places a background-image on the adjacent span.
Like this:
FIDDLE
**
img::selection {
background: transparent;
}
img + span {
display: none;
}
#-moz-document url-prefix() {
img {
display: none;
}
img + span {
background: url(http://placehold.it/200x200) no-repeat;
width: 200px;
height: 200px;
display: block;
}
}
<div>Hello there </div>
<img src="http://placehold.it/200x200" /><span></span>
<div>Hello there </div>
1: http://jsfiddle.net/GMuzV/30/
This disabled highlighting on a DOM element:
function disableSelection(target){
if (typeof target.onselectstart!="undefined") // if IE
target.onselectstart=function(){return false}
else if (typeof target.style.MozUserSelect!="undefined") // if Firefox
target.style.MozUserSelect="none";
else // others
target.onmousedown=function(){return false;}
target.style.cursor = "default";
}
Use it like this:
disableSelection(document.getElementById("my_image"));

IE 11 Bug - Image inside label inside form

In IE11, the following piece of code will check the radio button as expected:
<input type="radio" id="myRadio" />
<label for="myRadio">
<img src="..." />
</label>
Wrapping a <form> around the above will however break the functionality of the label.
This SO post offers a solution to the problem by styling the image with pointer-events:none, and the label as a block-level element.
While that should of course not even be necessary, it also disables the ability to handle mouse events.
It would be much appreciated if someone can offer a pure CSS solution to this problem.
PS:
One thing worth mentioning, is that in IE11, if the image is styled as a block-level element, then pointer-events seems to loose its effects.
My markup looks like this (classes and other superfluous attributes removed):
<li>
<label>
<figure>
<img>
</figure>
<div>
<label></label>
<input type="radio">
</div>
</label>
</li>
It's a bit messy because some of it is auto-generated by Drupal. It didn't work in IE 11, but I made it work by adding:
img {
pointer-events: none;
}
I didn't need to change anything else and I have no other special css-trickery that I can see.
As I answered previously in the referred question, there is a pure CSS way.
If your image is display: block that fix can still be used, even tho you have to add some more trickery. For example:
CSS:
label img{
display: block; /* requirement */
/* fix */
pointer-events: none;
position: relative;
}
/* fix */
label{
display: inline-block;
position: relative;
}
label::before{
content: "";
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -1;
}
HTML:
<form>
<label>
<input type="checkbox"> some text
<img src="http://placekitten.com/200/200" alt="kitten!">
</label>
</form>
Fiddle
If the problem is with click handlers on the image it self, you may be able to solve that with a wrapper element on the image instead (which maybe the label, so no extra element may be needed). (But for that I'd like to see a more specific example that you are trying to do.)
img {
pointer-events: none;
position: relative;
z-index: -1;
}
This solved it in my case.
The img will be placed behind the label but "shine through".
I hope it helps.
You can put the image in the background of the label..
<label for="myField1" ><img src="image1.jpg"></label>
becomes
<style>
#lblMyField1 {
background-image: url('image1.jpg');
background-position: center center;/* depend..*/
background-repeat: no-repeat;
}
</style>
<label id="lblMyField1" for="myField1" > </div>
This is a rather interesting find. I'll do a bit more research to determine whether or not I can identify a more root cause, but for the time being I have a couple suggestions.
Nest Your Input
<label>
<input />
<img />
</label>
This is a common convention used for associating inputs with labels. Given the input and the label are both inline, this doesn't affect the actual layout necessarily.
JavaScript Patch
Another option is to perform a click on the corresponding input when one didn't happen naturally. In this approach we setup a timeout to click after 100ms. Any click that happens otherwise will clear our timeout:
$("label[for]").each(function () {
var timeout;
var element = $("#" + $(this).attr("for"));
$(this).on("click", function () {
timeout = setTimeout(function () {
element.click();
}, 100);
});
element.on("click", function () {
clearTimeout(timeout);
});
});
Browsers that already work will clear the timeout, preventing a second click. Internet Explorer 11 will click via the timeout.
Demo: http://jsfiddle.net/CG9XU/
One caveat is that that solution only works for labels that were on the page when the case was ran. If you have forms coming in late (perhaps via ajax), you'll need to listen higher up on the DOM. The below example listens on the document level:
$(document).on("click", "label[for]", function () {
var timeout;
var element = $("#" + $(this).attr("for"));
timeout = setTimeout(function () {
element.click();
}, 100);
element.one("click", function () {
clearTimeout(timeout);
});
});
The label element accepts as its content type all phrasing elements, and this includes image elements. I'll keep looking into this, and will update this answer with any insight.
Here is a solution that worked for me using pointer-events:none without having to set my image to position:relative as I needed it to be position:absolute for my design.
HTML
`<form>
<input id="radio-button-action" type="radio" name="search" value="open">
<label for="radio-button-action">
<div class="img-wrapper">
<img src="images/image.jpg" alt="image">
</div>
</label>
</form>`
CSS
So in this example we have an image that needs to be position: absolute
img {
position: absolute
top: 10px;
right: 10px;
height: 25px;
width: 25px;
display: inline-block; /* can be block, doesn't matter */
}
Now set pointer-eventson the img-wrapper div
.img-wrapper {
position: relative /* this is required for this to work */
pointer-events: none /* this is what will make your image clickable */
}
It works with
img {
pointer-events: none;
}

Multicolored placeholder text

I need to create an HTML text input element that features multicolored placeholder text. All of the text should be gray except, but a closing asterisk should be red, as in:
This strikes me as a seemingly simple task that is actually a lot more complicated because of how browsers restrict our ability to style native input elements.
I have heard of people using CSS to override native input styles so they can use custom fonts, etc., but is there away to have two special text styles (gray and red)? Or do I need to use an alternative (non-native) input?
Try something like this: http://jsfiddle.net/vmuJm/
The trick: address the placeholder text, add a "required" class to required inputs, and use the :after pseudo element to add an appropriately colored asterisk.
[EDIT] It looks like this is only working for Webkit browsers.
I have a rather fun way to do this and seems to work great in all browsers.
(Works fine in IE 8+, chrome, and Firefox.)
What I am doing is using the spans I put inside of the label to act as the value text.
Here is the html structure,
<label><span class="title">Name<span class="symbol">*</span></span>
<input type="text" />
</label>
The css,
label {
position: relative;
}
label:hover span {
display: none;
}
input[type="text"]:focus, input[type="text"]:active {
z-index: 2;
}
label input[type="text"] {
position: relative;
}
.title {
color: gray;
position: absolute;
left: 5px;
top: 1px;
z-index: 1;
}
.symbol {
color: red;
}
Last here is the jQuery I wrote to not allow the span to hover over your input if the input is filled in.
$('input[type="text"]').blur(function() {
if( $(this).val().length >= 1) {
$(this).toggleClass('active');
}
else {
$(this).removeClass('active');
}
});
Here is a JSFIDDLE to play with.

Fixed position navbar obscures anchors [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.