アンカーの動作をクリーンアップしようとしています。ページの上部に固定されたヘッダーがあるため、ページの他の場所にあるアンカーにリンクすると、ページがジャンプしてアンカーがページの上部に表示され、固定ヘッダーの後ろにコンテンツが残ります (希望それは理にかなっている)。アンカーをヘッダーの高さから 25px オフセットする方法が必要です。私は HTML または CSS を好みますが、Javascript も同様に受け入れられます。
28 に答える
JavaScript を使用せずに CSS を使用できます。
アンカーにクラスを与えます:
<a class="anchor" id="top"></a>
次に、アンカーをブロック要素にして相対的に配置することで、アンカーが実際にページに表示される位置よりも上または下にオフセットして配置できます。-250px はアンカーを 250px 上に配置します
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>
これにより、コンテンツにギャップが生じることはなく、アンカー リンクは非常にうまく機能します。
私もこれに対する解決策を探していました。私の場合、それはかなり簡単でした。
すべてのリンクを含むリスト メニューがあります。
<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 を持つスパン タグをタグ内に配置しました。
<h3><span id="one"></span>one</h3>
2 行の CSS を使用して、それらを適切に配置します。
h3{ position:relative; }
h3 span{ position:absolute; top:-200px;}
上部の値を変更して、固定ヘッダー (またはそれ以上) の高さに合わせます。これは他の要素でも機能すると思います。
FWIWこれは私のために働いた:
[id]::before {
content: '';
display: block;
height: 75px;
margin-top: -75px;
visibility: hidden;
}
これはプレゼンテーションの問題であるため、純粋な CSS ソリューションが理想的です。ただし、この質問は 2012 年に提起されたものであり、相対的な配置 / 負のマージンの解決策が提案されていますが、これらのアプローチはかなりハッキリしているように見え、フローの問題を引き起こす可能性があり、DOM / ビューポートの変更に動的に対応することはできません。
そのことを念頭に置いて、JavaScript を使用することが依然として(2017 年 2 月) 最良のアプローチであると私は信じています。以下は、アンカー クリックに応答し、読み込み時にページ ハッシュを解決するバニラ JS ソリューションです(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);
Alexander Savin に触発された純粋な css ソリューション:
a[name] {
padding-top: 40px;
margin-top: -40px;
display: inline-block; /* required for webkit browsers */
}
ターゲットがまだ画面外にある場合は、必要に応じて次を追加できます。
vertical-align: top;
私のソリューションでは、CMS のターゲット セレクターとビフォア セレクターを組み合わせています。他の手法では、アンカー内のテキストは考慮されません。高さと負のマージンを必要なオフセットに調整します...
:target::before {
content: '';
display: block;
height: 180px;
margin-top: -180px;
}
js や html を変更せずに実行できます。cssのみです。
a[id]::before {
content: '';
display: block;
height: 50px;
margin: -30px 0 0;
}
これにより、id を持つすべての a-tag の前に疑似要素が追加されます。ヘッダーの高さに合わせて値を調整します。
同じ問題に対して、私は簡単な解決策を使用しました: 各アンカーに 40px のパディングトップを置きます。
@moeffju が示唆するように、これはCSS で実現できます。私が遭遇した問題 (私が議論したのを見たことがないことに驚いています) は、前の要素をパディングまたは透明な境界線でオーバーラップさせるトリックです。 z オーダー。
私が見つけた最良の修正は、セクションのコンテンツを次の場所に配置することdiv
でした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;
}
これは 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();
});
a[name]:not([href])
css セレクターを使用すると、ID なしでこれを実現できます。これは単に、名前があり、href がないリンクを探すだけです。<a name="anc1"></a>
ルールの例は次のとおりです。
a[name]:not([href]){
display: block;
position: relative;
top: -100px;
visibility: hidden;
}
すべての「コンテンツ要素」が次のようなものでラップされている TYPO3 Web サイトでこの問題に直面しています。
<div id="c1234" class="contentElement">...</div>
レンダリングを変更して、次のようにレンダリングします。
<div id="c1234" class="anchor"></div>
<div class="contentElement">...</div>
そしてこのCSS:
.anchor{
position: relative;
top: -50px;
}
トップバーの高さは 40px に固定されていましたが、アンカーが再び機能し、トップバーの下 10px から開始します。
この手法の唯一の欠点は、もはや使用できないこと:target
です。
次の属性を使用してアンカーを追加することもできます。
(text-indent:-99999px;)
visibility: hidden;
position:absolute;
top:-80px;
親コンテナに相対的な位置を与えます。
私にぴったりです。
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;
}
@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 フェージング ディキシング ヘッダーが好きな人にとっては便利かもしれません!
.vspace
各要素の前にアンカーを保持する40px-height 要素を追加しましh1
た。
<div class="vspace" id="gherkin"></div>
<div class="page-header">
<h1>Gherkin</h1>
</div>
CSS で:
.vspace { height: 40px;}
それはうまく機能しており、スペースが詰まることはありません。
当サイトで使用しているソリューションは次のとおりです。headerHeight
ヘッダーの高さに合わせて変数を調整します。js-scroll
クリック時にスクロールするアンカーにクラスを追加します。
// SCROLL ON CLICK
// --------------------------------------------------------------------------
$('.js-scroll').click(function(){
var headerHeight = 60;
$('html, body').animate({
scrollTop: $( $.attr(this, 'href') ).offset().top - headerHeight
}, 500);
return false;
});
@AlexanderSavinのソリューションは、WebKit
ブラウザでうまく機能します。
さらに、選択したアンカーにスタイルを適用して & のパディングを調整する :target 疑似クラスを使用する必要がありました。FF
Opera
IE9
a:target {
padding-top: 40px
}
このスタイルはChrome
/用ではないことに注意してください。そのSafari
ため、おそらく css-hacks や条件付きコメントなどを使用する必要があります。
また、対象となる要素がinline
. リンクが必要ない場合は、単にdisplay
プロパティを変更できます。
<div id="myanchor" style="display: inline">
<h1 style="padding-top: 40px; margin-top: -40px;">My anchor</h1>
</div>
私はこの同じ問題に遭遇し、次のようにクリック イベントを手動で処理することになりました。
$('#mynav a').click(() ->
$('html, body').animate({
scrollTop: $($(this).attr('href')).offset().top - 40
}, 200
return false
)
もちろん、スクロールアニメーションはオプションです。