1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

検索欄を残すか一覧を広げるか スクロール領域の設計とPlaywrightでの検証

1
Last updated at Posted at 2026-10-05

商品検索や管理画面で、検索欄の下に長い一覧を表示することがあります。検索欄を常に残せば条件を変えやすくなりますが、その分、一覧を表示できる高さは小さくなります。

このバランスは「どの要素をスクロールさせるか」で変えられます。まず図で見え方の違いを確認し、その後、同じHTMLで実現する方法とPlaywrightでの検証例を紹介します。

現在の実サイトで見るスクロール前後

デュエマクラシック08 カード検索の公開本番を、2026年10月6日にChromeで撮影しました。同じ表示幅の初期表示とスクロール後を比べています。過去の変更前後ではなく、現在の実サイトの動作例です。

モバイル幅は390×844、PC幅は1280×800のviewportです。モバイル幅もPCのChromeで表示幅を変えて撮影しており、実機スマートフォンでの撮影ではありません。どちらの幅でも、一覧を下へスクロールすると検索欄が画面外へ移動し、上部ヘッダーが残る様子を確認できます。

モバイル幅の初期表示

現在の実サイト モバイル幅の初期表示

モバイル幅のスクロール後

現在の実サイト モバイル幅のスクロール後

PC幅の初期表示

現在の実サイト PC幅の初期表示

PC幅のスクロール後

現在の実サイト PC幅のスクロール後

操作のしやすさと一覧の広さを選ぶ

下の概念図で、スクロール前後を比べます。濃い枠の内側が画面に見える範囲、青い破線がスクロールする範囲です。上向きの矢印は、下へ読み進めたときに内容が動く方向を表しています。

概念図 A 検索欄を残して一覧だけをスクロール

Aでは検索欄がその場に残り、下の一覧だけが動きます。条件を変えやすい一方、一覧に使える範囲は検索欄の下だけです。

概念図 B 検索欄と一覧を一緒にスクロール

Bでは検索欄も一覧と一緒に上へ流れます。検索欄が画面外へ出た後は、ヘッダー直下まで一覧を表示できます。

図では同じだけ下へ進んだ状態を示しています。どちらも商品05まで見えていますが、Bでは商品01と02も同じ画面に残っています。最初から画面が広いのではなく、検索欄が退避した分を一覧に使えるのが違いです。これは仕組みを説明する概念図で、実画面のスクリーンショットや寸法の測定結果ではありません。

どちらを選ぶかは、画面で繰り返す操作を基準に考えます。

  • 条件を少しずつ変えて結果を比較するなら、検索欄を残す構造が候補になります

  • 一度絞り込んだ結果を長く眺めるなら、検索欄も流す構造が候補になります

後者では条件を変えるために戻る操作が増えます。閲覧領域だけを広げて終わらせず、再検索への戻り方も一緒に設計します。

実装例 同じHTMLで二つの構造を作る

以下は設計の違いを説明するためのサンプルです。ブラウザでの動作確認は未完了のため、利用時には自身の環境で検証してください。

ここでは、ヘッダーと、その下の検索欄・一覧を持つ画面を使います。検索処理を省いた説明用のサンプルです。HTMLは body 内の抜粋で、CSSは後述の共通設定とA・Bのいずれかを読み込みます。スマートフォン向けには head に <meta name="viewport" content="width=device-width, initial-scale=1"> も指定します。

<div class="app">
  <header class="header">
    商品一覧
    <button id="back" type="button">検索に戻る</button>
  </header>
  <main class="panel" aria-label="商品検索">
    <div class="search">
      <label for="query">商品名</label>
      <input id="query" type="search">
    </div>
    <ul class="results" aria-label="検索結果"></ul>
  </main>
</div>

スクロールできるだけの内容を用意します。次のJavaScriptはHTMLの後に置きます。

const results = document.querySelector('.results');
for (let i = 1; i <= 50; i++) {
  const li = document.createElement('li');
  li.textContent = '商品 ' + i;
  results.append(li);
}

共通のCSSです。Flexboxは、子要素を並べて余った領域を分配できるレイアウト方式です。ここでは縦方向に並べ、.panel がヘッダー以外の高さを使います。100dvh はブラウザの動的な表示領域に合わせる高さの指定です。

* { box-sizing: border-box; }
body { margin: 0; }
.app {
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.header, .search { flex: none; padding: 16px; }
.panel {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.results { margin: 0; padding: 0; list-style: none; }
.results li { min-height: 80px; padding: 16px; }

A 一覧だけをスクロールさせる

共通CSSに、次の指定を追加します。

.panel { overflow: hidden; }
.results {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

.results が残りの高さに収まり、その中だけがスクロールします。検索欄はスクロール対象の外にあるため、画面に残ります。この例では position: fixed や position: sticky は使っていません。

B 検索欄と一覧を一緒にスクロールさせる

AのCSSを、次のCSSに置き換えます。AとBを同時に適用しないでください。

.panel { overflow-y: auto; }
.results {
  flex: none;
  overflow: visible;
}

今度は親の .panel がスクロール対象です。一覧は flex: none で内容に応じた高さを保ち、検索欄と一緒に流れます。ヘッダーは .panel の外にあるので、引き続き画面に残ります。

高さの制約とスクロール対象をセットで見る

overflow-y: auto は、要素から縦にはみ出した内容をスクロールできるようにする指定です。ただし、要素自体が内容に合わせてどこまでも伸びれば、期待する位置にスクロール領域はできません。上の例では .app の高さを制限し、Flexboxで .panel に残りの高さを割り当てています。overflowの仕様説明

min-height: 0 は、縦に並ぶFlexboxの子要素を、内容の高さより小さくできることを明示する指定です。自動の最小サイズは overflow などの条件によって変わるため、常に必須というわけではありません。入れ子のFlexboxで画面全体が伸びる場合は、スクロールさせたい要素だけでなく、その親の高さと最小サイズも確認します。Flexboxの自動最小サイズ

検索への戻り方も変更する

Bでは「検索に戻る」ボタンを、スクロールしないヘッダーに置いています。実際にスクロールしている .panel を先頭へ戻します。Aにも同じボタンを付ける場合は、戻す対象を .results にします。

const panel = document.querySelector('.panel');
const input = document.querySelector('#query');
panel.tabIndex = 0;
document.querySelector('#back').addEventListener('click', () => {
  panel.scrollTo({ top: 0, behavior: 'smooth' });
  input.focus({ preventScroll: true });
});

scrollTop は、その要素が上端からどれだけスクロールしたかを示す値です。既存の画面でスクロール対象を変える場合は、先頭へ戻す処理だけでなく、スクロール位置の保存・復元や、末尾まで進んだことを検知する処理も確認します。

キーボードだけでもスクロールできるように、Bでは .panel、Aでは .results に tabindex="0" を付けます。入力欄のラベルと、フォーカス位置が分かる見た目も必要です。Bで検索欄へ戻る際は、入力欄へフォーカスも移しています。

Playwrightでは操作後の状態を待つ

Playwrightは、ブラウザを操作して画面の状態を確認できるテストツールです。Bの仕様は、次のように確認できます。

  1. 一覧上でスクロールすると .panel の scrollTop が増える

  2. 検索欄がスクロール領域の上端より上へ移動する

  3. ヘッダーの位置が変わらない

  4. 「検索に戻る」で先頭に戻り、入力欄にフォーカスが当たる

以下は、BのHTML/CSS/JavaScriptを組み合わせた画面を /b.html で配信し、Playwright Testの baseURL を設定した場合のテスト例です。

import { test, expect } from '@playwright/test';

test('検索欄が流れ、ボタンで戻れる', async ({ page }) => {
  await page.goto('/b.html');
  const panel = page.locator('.panel');
  const header = page.locator('.header');
  const before = await header.boundingBox();
  const box = await panel.boundingBox();
  if (!box) throw new Error('panel が見つかりません');

  // 一覧が見えている領域でホイール操作する
  await page.mouse.move(
    box.x + box.width / 2, box.y + box.height - 16
  );
  await page.mouse.wheel(0, 500);

  await expect.poll(() =>
    panel.evaluate(el => el.scrollTop)
  ).toBeGreaterThan(0);

  // 位置関係を確認する。この例の panel には枠線がない
  await expect.poll(() => page.evaluate(() => {
    const p = document.querySelector('.panel').getBoundingClientRect();
    const s = document.querySelector('.search').getBoundingClientRect();
    return s.bottom <= p.top;
  })).toBe(true);
  expect(await header.boundingBox()).toEqual(before);

  await page.getByRole('button', { name: '検索に戻る' }).click();
  await expect.poll(() =>
    panel.evaluate(el => el.scrollTop)
  ).toBe(0);
  await expect(page.locator('#query')).toBeFocused();
});

mouse.wheel() は、スクロールが終わるまで待つAPIではありません。操作直後に座標を読むと、動く前や途中の状態を判定することがあります。expect.poll() で条件が成立するまで値を繰り返し確認すると、固定時間の待機に頼らず検証できます。wheelの挙動、expect.poll

Aを検証する場合は期待値が変わります。増えるのは .results.scrollTop で、検索欄の座標は変わらないはずです。初期状態だけでなく、スクロール中と検索へ戻った状態まで確認します。

動作と見た目と使いやすさを分けて確認する

座標や scrollTop のテストで確認できるのは、決めた構造どおりに動くことです。画面幅が狭いときの文字の折り返しや、検索条件を開いたときの窮屈さは、スクリーンショットでも確認すると把握しやすくなります。比較する際は、画面サイズ、データ、並び順、スクロール位置をそろえます。

page.screenshot() は画像を保存します。保存した基準画像との差分を自動判定したい場合は、Playwright Testの toHaveScreenshot() などを使います。画像を撮る処理と、自動で差分を判定するテストは区別しておきます。Playwrightの画像比較

どちらのレイアウトが利用者に合うかは、さらに別の確認です。「条件を変えて結果を比較する」「絞り込み後に多くの項目を見る」など、実際の操作を通して判断します。狭い画面、文字を拡大した状態、スマートフォンでキーボードを開いた状態でも、一覧と検索欄の両方にアクセスできるかを確認します。

まとめ

検索欄と一覧の設計では、常時表示する要素に必要な高さと、利用者が繰り返す操作をセットで考えます。

一覧だけをスクロールさせれば検索欄が残り、親をスクロールさせれば検索欄も一緒に流れます。対象を変えたら、先頭への復帰や位置の記録も同じ要素に合わせます。そのうえで、動作をテストし、見た目と使い勝手を確かめると、変更の意図と確認すべき点が明確になります。

背景となった実装例:検索画面のスクロール領域の見直し

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?