プルトゥリフレッシュ Pull to Refresh

画面を下に引っ張ってコンテンツを更新するパターン。モバイルアプリの標準的な更新操作。

使用場面: SNSのフィードやメール一覧など、最新データを取得したい場面 採用例: Twitter/X, Instagram

ライブデモ

引っ張って更新
フィード項目 1 — 10分前
フィード項目 2 — 30分前
フィード項目 3 — 1時間前
フィード項目 4 — 2時間前
フィード項目 5 — 3時間前

コンテンツを下にドラッグして更新

ソースコード

<div class="demo-ptr-container">
  <div class="demo-ptr-indicator">
    <svg class="demo-ptr-spinner" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M21 12a9 9 0 11-6.219-8.56"/></svg>
    <span class="demo-ptr-text">引っ張って更新</span>
  </div>
  <div class="demo-ptr-content">
    <div class="demo-ptr-item"><span class="demo-ptr-dot"></span>フィード項目 1 — 10分前</div>
    <div class="demo-ptr-item"><span class="demo-ptr-dot"></span>フィード項目 2 — 30分前</div>
    <div class="demo-ptr-item"><span class="demo-ptr-dot"></span>フィード項目 3 — 1時間前</div>
    <div class="demo-ptr-item"><span class="demo-ptr-dot"></span>フィード項目 4 — 2時間前</div>
    <div class="demo-ptr-item"><span class="demo-ptr-dot"></span>フィード項目 5 — 3時間前</div>
  </div>
  <p class="demo-ptr-hint">コンテンツを下にドラッグして更新</p>
</div>
.demo-ptr-container {
  position: relative; height: 260px; overflow-y: auto; overflow-x: hidden;
  border: 1px solid #e5e7eb; border-radius: 10px; background: #fff;
}
.demo-ptr-indicator {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 16px; margin-top: -60px; transition: margin-top 0.3s;
  color: var(--ui-primary);
}
.demo-ptr-spinner {
  transition: transform 0.2s; stroke: var(--ui-primary);
}
.demo-ptr-indicator.refreshing .demo-ptr-spinner {
  animation: demo-ptr-spin 0.8s linear infinite;
}
@keyframes demo-ptr-spin { to { transform: rotate(360deg); } }
.demo-ptr-text { font-size: 12px; color: #999; }
.demo-ptr-content { padding: 0 12px 12px; }
.demo-ptr-item {
  display: flex; align-items: center; gap: 10px;
  padding: 12px; border-bottom: 1px solid #f3f4f6;
  font-size: 13px; color: #444;
}
.demo-ptr-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--ui-primary); flex-shrink: 0;
}
.demo-ptr-hint { text-align: center; font-size: 12px; color: #aaa; padding: 8px; margin: 0; }
(function(){
  var container = document.querySelector('.demo-ptr-container');
  var indicator = document.querySelector('.demo-ptr-indicator');
  var text = document.querySelector('.demo-ptr-text');
  var startY = 0, pulling = false;
  container.addEventListener('touchstart', function(e){
    if(container.scrollTop === 0){ startY = e.touches[0].clientY; pulling = true; }
  }, {passive:true});
  container.addEventListener('mousedown', function(e){
    if(container.scrollTop === 0){ startY = e.clientY; pulling = true; }
  });
  function onMove(y){
    if(!pulling) return;
    var dist = Math.max(0, Math.min(80, (y - startY) * 0.5));
    indicator.style.marginTop = (-60 + dist) + 'px';
    if(dist > 50) text.textContent = '離して更新';
    else text.textContent = '引っ張って更新';
  }
  container.addEventListener('touchmove', function(e){ onMove(e.touches[0].clientY); }, {passive:true});
  container.addEventListener('mousemove', function(e){ if(pulling) onMove(e.clientY); });
  function onEnd(){
    if(!pulling) return;
    pulling = false;
    var mt = parseInt(indicator.style.marginTop) || -60;
    if(mt > -10){
      indicator.style.marginTop = '0px';
      indicator.classList.add('refreshing');
      text.textContent = '更新中...';
      setTimeout(function(){
        indicator.classList.remove('refreshing');
        indicator.style.marginTop = '-60px';
        text.textContent = '引っ張って更新';
      }, 1500);
    } else {
      indicator.style.marginTop = '-60px';
    }
  }
  container.addEventListener('touchend', onEnd);
  container.addEventListener('mouseup', onEnd);
  container.addEventListener('mouseleave', onEnd);
})();

AIプロンプト

Basic
プルトゥリフレッシュをHTML/CSS/JSで作ってください。リストを下に引っ張ると更新インジケーターが表示され、離すとリフレッシュアニメーションが再生されます。
Custom
以下の仕様でプルトゥリフレッシュを実装してください。
- 引っ張り量に応じたスピナー回転アニメーション
- 閾値を超えると「離して更新」テキストに切り替え
- 更新中はスピナーが回転し続ける
- 更新完了後にスムーズに元に戻る
- プライマリカラー: #2563eb
- タッチ・マウス両対応
Advanced
パフォーマンス最適化されたプルトゥリフレッシュを実装してください。
- PointerEvents APIでタッチ/マウスを統一処理
- requestAnimationFrameでの滑らかな描画
- CSS transformのみ使用(リフロー回避)
- overscroll-behavior: containで標準のブラウザ更新を無効化
- 物理ベースのバウンスアニメーション
- 更新中のキャンセル機能
- Service Worker連携でオフライン時のフォールバック