position: sticky
の要素が「スタック」していて、ビューポートよりも長い場合、コンテナの一番下までスクロールした後にのみそのコンテンツを表示できます。
「スタック」要素がドキュメントと一緒にスクロールして、その下端に到達したら停止した場合は、すばらしいでしょう。ユーザーがスクロールバックすると、同じことが再び起こりますが、逆になります。
TLDR;私が探していることを実行するライブラリ( StickyKit )がありますが、新しい非同期スクロールではパフォーマンスが低下します。
JSFiddlewith StickyKithttps://jsfiddle.net/cibulka/4nd3b0tt/これは私が説明していることを行います、ただしパフォーマンスは低下します。以下を参照してください)
JSFiddle withnativeposition: sticky
----(https://jsfiddle.net/cibulka/np6afe9c/1/ --- https://jsfiddle.net/cibulka/pxz6e0qv/これはしません)
私は長い間StickyKitの幸せなユーザーでした。残念ながら、パフォーマンスを向上させるためにますます多くのブラウザで採用されている---(非同期スクロール ではうまく機能しません。たとえば、新しいFirefox Quantum(57)では、StickyKitはほとんど使用できません。
StickyKit Githubで問題を作成しましたが、パッケージは作成者によって放棄されたようです: https://github.com/leafo/sticky-kit/issues/252
そのため、StickyKitを廃止し、ネイティブposition:sticky
( StickyFill でポリフィルされた)に移動することを余儀なくされました。残念ながら、position:sticky
でできないことがいくつかあり、これはそのうちの1つです。
position:sticky
で発生している別の問題もあります: 位置スティッキー:オーバーレイ
基本的に、この問題へのアプローチ方法に関する推奨事項。別のJS/jQueryライブラリを使用したり、独自のコードを記述したり、風変わりなCSSハックを使用してposition:sticky
機能をハックしたりしています。
スクロール方向に応じてjQueryを使用して、スティッキー要素のアンカーと位置を上から下に切り替えて、CSSのネイティブposition: sticky
を使用することができます。
this codepen で動作させましたが、方向が変わったときのジャンプをスムーズにする時間がありませんでした。しかし、多分これはあなたにとって十分です。
// Use display: flex on the container
window.onscroll = function (e) {
if (window.scrollY < this.prevScrollY) {
scrollUpwards();
} else {
scrollDownwards();
}
this.prevScrollY = window.scrollY;
}
function scrollUpwards() {
$("aside").css("top", 0);
$("aside").css("bottom", '');
$("aside").css("align-self", "flex-start");
}
function scrollDownwards() {
$("aside").css("top", '');
$("aside").css("bottom", 0);
$("aside").css("align-self", "flex-end");
}
私はjnnsの回答を受け取り、スティッキーキットのようにスクロール間でスムーズになるように更新しました。唯一の問題は、それが含まれているdivs.tにマジックナンバーを必要としたことです。コンテナは、divが絶対的に配置されている間、そのサイズを維持します。これは、css変数によってコードで解決される可能性があります。
window.onscroll = function (e) {
if (window.scrollY < this.prevScrollY) {
// Track position state of nav
// 1 == stuck to top
// 0 == absolute positioning
// -1 == stuck to bottom
this.stick_pos = scrollUpwards(this.stick_pos);
} else {
this.stick_pos = scrollDownwards(this.stick_pos);
}
this.prevScrollY = window.scrollY;
}
function scrollUpwards(stick_pos) {
// If the element is already stuck to the top then we are fine
if(stick_pos === 1) return stick_pos;
// Figure out where the new window will be after scroll
let aside = $("aside").get(0);
let aboveAside = aside.getBoundingClientRect().top > 0;
// If we are going above the element then we know we must stick
// it to the top
if (aboveAside){
$("aside").css("position", "sticky")
.css("top", 0)
.css("bottom", '')
.css("align-self", "flex-start");
return 1;
}
// If it will still be below the top of the element, then we
// must absolutely position it to its current position - if it already is absolutely positioned then we do nothing
if (stick_pos == 0) return stick_pos;
// Undo the stick to the bottom
// First get the current position
$("aside")
.css("top", aside.offsetTop)
.css("position", "absolute")
.css("bottom", '')
.css("align-self", "");
return 0;
}
function scrollDownwards(stick_pos) {
/*
let aside = $("aside").get(0);
let aboveAside = aside.offsetTop >= window.scrollY;
let browser_bottom = window.scrollY + window.innerHeight;
let aside_bottom = aside.offsetTop + aside.offsetHeight;
let belowAside = browser_bottom >= aside_bottom;
if (aboveAside) {
//console.log("stick to bottom");
$("aside").css("top", '');
$("aside").css("bottom", 0);
$("aside").css("align-self", "flex-end");
}
*/
// If the element is already stuck to the bottom then we are fine
if(stick_pos === -1) return stick_pos;
// Figure out where the new window will be after scroll
let aside = $("aside").get(0);
let browser_bottom = window.innerHeight;
let aside_bottom = aside.getBoundingClientRect().top + aside.offsetHeight;
let belowAside = browser_bottom > aside_bottom;
// If we are going below the element then we know we must stick
// it to the bottom.
if (belowAside){
$("aside").css("position", "sticky")
.css("top", '')
.css("bottom", 0)
.css("align-self", "flex-end");
return -1;
}
// If it will still be above the bottom of the element, then we
// must absolutely position it to its current position - if it already is absolutely positioned then we do nothing
if (stick_pos == 0) return stick_pos;
// Undo the stick to the top
// First get the current position
// $("aside").css("position", "absolute")
// .css("top", aside.offsetTop);
$("aside")
.css("top", aside.offsetTop)
.css("position", "absolute")
.css("bottom", '')
.css("align-self", "");
return 0;
}
div#section {
/* begin: irrelevant styling */
margin: 5em auto;
padding: 0.625rem;
max-width: 300px;
font-family: sans-serif;
font-size: 18px;
line-height: 1.5em;
text-align: justify;
background-color: #dbe4ee;
/* end: irrelevant styling */
display: flex;
justify-content: space-around;
}
div#section div#nav-container {
position: relative;
display: flex;
min-width: 2em;
}
div#section div#nav-container aside {
position: sticky;
align-self: flex-start;
/* begin: irrelevant styling */
background-color: #81a4cd;
color: white;
text-align: center;
width: 2em;
}
div#section div#nav-container aside div {
padding: 0 .3em;
}
div#section article {
margin-left: 0.5em;
}
div#section article p {
margin: 0;
}
div#section article p + p {
margin-top: 1.5em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='section'>
<div id='nav-container'>
<aside>
<div>A</div>
<div>B</div>
<div>C</div>
<div>D</div>
<div>E</div>
<div>F</div>
<div>G</div>
<div>H</div>
<div>I</div>
<div>J</div>
<div>K</div>
<div>L</div>
<div>M</div>
<div>N</div>
<div>O</div>
<div>P</div>
<div>Q</div>
<div>R</div>
<div>S</div>
<div>T</div>
<div>U</div>
<div>V</div>
<div>W</div>
<div>X</div>
<div>Y</div>
<div>Z</div>
</aside>
</div>
<article>
<p>Perferendis ut iusto voluptatem ex temporibus aut autem amet. Sit vero in soluta. Est officia asperiores tenetur vel quam nostrum eum facere. Sed totam quasi libero at facilis doloremque. Non aut velit odio. Tempora dolore sunt recusandae sed quia
sunt.</p>
<p>Voluptatem optio asperiores dolorem voluptatem. Ipsa alias perspiciatis doloribus est nisi ut. Fuga aut et vitae consequatur dolor corrupti aut minima.</p>
<p>Facilis et ut eligendi. Excepturi labore asperiores vero. Perferendis porro sunt molestiae. In sit dolorem eum esse sit inventore est. Atque perspiciatis commodi nihil.</p>
<p>Consequatur ipsa id repellendus voluptatem perspiciatis temporibus. Praesentium eveniet nemo laudantium inventore similique impedit nihil esse. Maiores iste commodi molestiae quas odit nihil ex corrupti. Illum id amet non vero.</p>
<p>Voluptas soluta itaque et. Aperiam quasi sint eos ullam. Assumenda facilis omnis alias numquam. Odio quia esse vel et minima soluta architecto. Qui saepe consequatur aut rerum. Et et aut voluptatibus inventore.</p>
<p>Perferendis ut iusto voluptatem ex temporibus aut autem amet. Sit vero in soluta. Est officia asperiores tenetur vel quam nostrum eum facere. Sed totam quasi libero at facilis doloremque. Non aut velit odio. Tempora dolore sunt recusandae sed quia sunt.</p>
<p>Voluptatem optio asperiores dolorem voluptatem. Ipsa alias perspiciatis doloribus est nisi ut. Fuga aut et vitae consequatur dolor corrupti aut minima.</p>
<p>Facilis et ut eligendi. Excepturi labore asperiores vero. Perferendis porro sunt molestiae. In sit dolorem eum esse sit inventore est. Atque perspiciatis commodi nihil.</p>
<p>Consequatur ipsa id repellendus voluptatem perspiciatis temporibus. Praesentium eveniet nemo laudantium inventore similique impedit nihil esse. Maiores iste commodi molestiae quas odit nihil ex corrupti. Illum id amet non vero.</p>
<p>Voluptas soluta itaque et. Aperiam quasi sint eos ullam. Assumenda facilis omnis alias numquam. Odio quia esse vel et minima soluta architecto. Qui saepe consequatur aut rerum. Et et aut voluptatibus inventore.</p>
</div>
Sticky Sidebar というライブラリがあります。これはまさにその問題を解決するために作られています。
調べましたか Scrollama
新しい Intersection Observer Web APIを使用します。これは基本的に、JSがスクロールイベントをリッスンすることなく、特定の要素がビューポート内に表示されたときにJSに通知するブラウザです。したがって、JSでposition: sticky
のような動作をパフォーマンスの高い方法で実装するのに役立ちます。