私は私のアンカーが働く方法をきれいにしようとしています。ページ上部に固定されたヘッダーがあるので、ページ内の他の場所にあるアンカーにリンクすると、ページがジャンプしてアンカーがページ上部に表示され、固定ヘッダーの後ろにコンテンツが残りますそれは理にかなっている)。ヘッダーの高さからアンカーを25ピクセル分オフセットする方法が必要です。私はHTMLかCSSを好むでしょうが、Javascriptも同様に受け入れられるでしょう。
JavaScriptを使わずにCSSを使うことができます。
あなたのアンカーにクラスを与えます:
<a class="anchor" id="top"></a>
その後、アンカーをブロック要素にして相対的に配置することで、アンカーをページ上の実際の表示位置よりも高いまたは低いオフセットに配置できます。 -250ピクセルはアンカーを250ピクセル上に配置します
a.anchor {
display: block;
position: relative;
top: -250px;
visibility: hidden;
}
私はこの解決策を見つけました:
<a name="myanchor">
<h1 style="padding-top: 40px; margin-top: -40px;">My anchor</h1>
</a>
これによってコンテンツにギャップが生じることはなく、アンカーリンクは本当にうまく機能します。
これはプレゼンテーションの問題であるため、純粋なCSSソリューションが理想的です。しかし、この問題は2012年に提起されたもので、相対的ポジショニング/ネガティブマージンの解決策が提案されていますが、これらのアプローチはかなり厄介で、潜在的なフローの問題を引き起こし、DOM /ビューポートの変更に動的に対応できません。
それを念頭に置いて、私はJavaScriptを使用することがstill(2017年2月)が最善のアプローチであると信じています。下記はVanilla-JSソリューションです。アンカークリックに応答し、loadのページハッシュを解決します(JSFiddleを参照)。動的計算が必要な場合は.getFixedOffset()
メソッドを修正してください。あなたがjQueryを使っているなら、 これはより良いイベント委譲とスムーズなスクロールを持つ修正された解決策です 。
(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);
私もこれに対する解決策を探していました。私の場合は、とても簡単でした。
すべてのリンクを含むリストメニューがあります。
<ul>
<li><a href="#one">one</a></li>
<li><a href="#two">two</a></li>
<li><a href="#three">three</a></li>
<li><a href="#four">four</a></li>
</ul>
そしてその下には、それが行くべき見出しがあります。
<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>
私は自分のページの上部に固定メニューを持っているので、メニューの後ろにあるのでそれを自分のタグに移動させることはできません。
代わりに、私は自分のタグの中に適切なIDでspanタグを入れます。
<h3><span id="one"></span>one</h3>
2行のcssを使ってそれらを正しく配置します。
h3{ position:relative; }
h3 span{ position:absolute; top:-200px;}
あなたの固定ヘッダの高さ(あるいはそれ以上)に合うように上の値を変更してください。今、私はこれが他の要素でもうまくいくと思います。
これは私のために働いた:
*[id]:before {
display: block;
content: " ";
margin-top: -75px;
height: 75px;
visibility: hidden;
}
Alexander Savinに触発された純粋なcssソリューション:
a[name] {
padding-top: 40px;
margin-top: -40px;
display: inline-block; /* required for webkit browsers */
}
ターゲットがまだ画面から外れている場合は、オプションで以下を追加することができます。
vertical-align: top;
これは以前の答えから多くの要素を取り、小さな(194バイトの最小化)匿名jQuery関数に結合します。 fixedElementHeight メニューまたはブロッキング要素の高さに合わせて調整します。
(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);
アニメーションが気に入らない場合は、
$('html, body')
.stop()
.animate({
scrollTop: $anchor.offset().top - fixedElementHeight
}, 200);
と:
window.scrollTo(0, $anchor.offset().top - fixedElementHeight);
醜いバージョン:
!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);
私は同様の問題に直面していました、残念ながら上記のすべての解決策を実行した後、私は次の結論に至りました。
私はこの単純なスクロールjsを書きました、それはヘッダーのために引き起こされるオフセットを考慮して、そして約125ピクセル下のdivを再配置しました。あなたが合うようにそれを使ってください。
HTML
<div id="#anchor"></div> <!-- #anchor here is the anchor tag which is on your URL -->
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;
}
}
});
ライブの実装はこちら を参照してください。
最近のブラウザでは、CSS3:ターゲットセレクタをページに追加するだけです。これは自動的にすべてのアンカーに適用されます。
:target {
display: block;
position: relative;
top: -100px;
visibility: hidden;
}
a[id]:before {
content:"";
display:block;
height:50px;
margin:-30px 0 0;
}
それはidを持つすべてのa-tagの前に擬似要素を追加します。ヘッダの高さに合わせて値を調整します。
私の解決策は私たちのCMSのためのターゲットと前セレクタを組み合わせたものです。他の手法ではアンカー内のテキストを考慮しません。必要なオフセットに合わせて高さと負の余白を調整します。
:target:before {
content: "";
display: block;
height: 180px;
margin: -180px 0 0;
}
@moeffjuが示唆するように、これは CSSで達成することができます 。私が遭遇した問題(私がこれまで議論したことがなかったのは驚いたことですが)前の要素をパディングまたは透明なボーダーで重ね合わせることによるトリックです。 zオーダー.
私が見つけた最善の解決策は、セクションのコンテンツをz-index: 1
のdiv
に配置することです。
// 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;
}
同じ問題について、私は簡単な解決策を使用しました。各アンカーに40pxのパディングトップを追加します。
位置特性を変更する解決策は常に可能というわけではありません(それはレイアウトを破壊することができます)それ故に私はこれを提案します:
HTML:
<a id="top">Anchor</a>
CSS:
#top {
margin-top: -250px;
padding-top: 250px;
}
これを使って:
<a id="top"> </a>
重なりを最小限にし、font-sizeを1pxに設定します。空のアンカーは一部のブラウザでは動作しません。
このリンクでの回答からコードの一部を借用する (作成者は指定されていない)アンカーに-60pxで止まるようにしながら、アンカーにNice smooth-scroll効果を含めることができます。固定されたブートストラップナビゲーションバーのすぐ下(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(){
});
});
私はこれと同じ問題に遭遇し、手動でクリックイベントを処理することになりました。
$('#mynav a').click(() ->
$('html, body').animate({
scrollTop: $($(this).attr('href')).offset().top - 40
}, 200
return false
)
もちろんスクロールアニメーションはオプションです。
上記の方法は、アンカーがテーブル要素である場合、またはテーブル(行またはセル)内にある場合はあまりうまくいきません。
この問題を回避するには、javascriptを使用してwindowのhashchange
イベントにバインドする必要がありました( 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();
});
*注: hashchange イベントはすべてのブラウザで利用できるわけではありません。
ページの残りのコンテンツに重なっている固定位置ナビゲーションバーを使用する代わりに(ページ本体全体をスクロール可能にする)、代わりに固定ナビゲーションバーを使用してページコンテンツをスクロール可能にすることを検討します。下の絶対位置スクロール可能div。
つまり、次のようなHTMLがあります。
<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>
...そしてCSSはこんな感じ:
.static-navbar {
height: 100px;
}
.scrollable-content {
position: absolute;
top: 100px;
bottom: 0;
overflow-y: scroll;
width: 100%;
}
これにより、直接的でハッキングのない方法で目的の結果が得られます。これと上で提案した巧妙なCSSハックのいくつかの間の動作の唯一の違いはスクロールバー(それをレンダリングするブラウザで)はページの全高ではなくcontent divにアタッチされるということです。あなたはこれを望ましいと考えてもしなくてもよいです。
これはShouvikによる答えに触発されました - 彼と同じ概念、固定ヘッダのサイズだけがハードコードされていません。あなたの固定ヘッダが最初のヘッダノードにある限り、これは "ただ動く"はずです。
/*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();
});
私はTYPO3ウェブサイトでこの問題に直面しています。そこでは全ての "Content Elements"が次のようなもので包まれています。
<div id="c1234" class="contentElement">...</div>
そして私はそれがこのようにレンダリングするようにレンダリングを変更しました:
<div id="c1234" class="anchor"></div>
<div class="contentElement">...</div>
そしてこのCSS:
.anchor{
position: relative;
top: -50px;
}
固定トップバーの高さは40ピクセルで、アンカーは再び機能し、トップバーの下から10ピクセルの位置から開始します。
このテクニックの唯一の欠点はあなたがもはや:target
を使うことができないということです。
@Janからの優れた回答へのさらなるひねりは、jQuery(またはMooTools)を使用する#uberbar固定ヘッダにこれを組み込むことです。 ( http://davidwalsh.name/persistent-header-opacity )
私はコードを微調整して、コンテンツの先頭が常に固定ヘッダーの下にならないようにし、また@Janのアンカーを追加しました。アンカーが常に固定ヘッダーの下に配置されるようにします。
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;
}
JQuery(#uberbarとアンカーの両方への調整を含む):
<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>
そして最後に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>
たぶんこれは#uberbarフェージング混合ヘッダが好きな人には便利です!
Ziavの答えに加えて(Alexander Savinのおかげで)、私たちのコードでは<a name="...">...</a>
を別の目的に使用しているので、私は昔の<div id="...">...</div>
を使用する必要があります。私はdisplay: inline-block
を使用していくつかの表示上の問題を抱えていました - すべての<p>
要素の最初の行はわずかに右インデントされていることが判明しました(WebkitとFirefoxブラウザの両方で)。私は他のdisplay
値を試してみることにしました、そしてdisplay: table-caption
は私のために完全に働きます。
.anchor {
padding-top: 60px;
margin-top: -60px;
display: table-caption;
}
a[name]:not([href])
cssセレクタを使うと、IDなしでこれを実現できます。これは単に名前とhrefのないリンクを探すだけです。 <a name="anc1"></a>
規則の例は次のとおりです。
a[name]:not([href]){
display: block;
position: relative;
top: -100px;
visibility: hidden;
}
アンカーを保持する40px-heightの.vspace
要素を各h1
要素の前に追加しました。
<div class="vspace" id="gherkin"></div>
<div class="page-header">
<h1>Gherkin</h1>
</div>
CSSでは:
.vspace { height: 40px;}
それは素晴らしい仕事をしていて、スペースはぎっしり詰まっていません。
ナビゲーションバーの高さを提供するリンク可能なIDを持つ隠しスパンタグはどうでしょうか。
#head1 {
padding-top: 60px;
height: 0px;
visibility: hidden;
}
<span class="head1">somecontent</span>
<h5 id="headline1">This Headline is not obscured</h5>
フィドルをヘレス: http://jsfiddle.net/N6f2f/7
Follow attrを使ってアンカーを追加することもできます。
(text-indent:-99999px;)
visibility: hidden;
position:absolute;
top:-80px;
そして親コンテナに相対位置を与えます。
私にぴったりです。