●サイト内検索とは?なぜ必要か
皆さんは、自社のWebサイトを改善するミッションを任されていると思います。
その中でも、サイト内検索機能の実装は重要な課題の1つではないでしょうか。
サイト内検索とは、Webサイト内のコンテンツを検索できる機能のことです。
ユーザーが目的の情報にすぐにたどり着けるようにサポートするために欠かせません。
○サイト内検索の重要性
サイト内検索がなぜ重要かというと、ユーザビリティの向上に直結するからです。
サイトマップやカテゴリ別のナビゲーションだけでは、欲しい情報になかなかたどり着けないことがありますよね。
そんな時、検索窓に関連キーワードを入力すれば、目的のページがすぐに見つかります。
これにより、ユーザーの満足度とサイトの滞在時間が増加。離脱率の改善にもつながるのです。
○JavaScriptを使う利点
では、サイト内検索の実装に JavaScriptを使うメリットは何でしょうか。
それは、動的な処理が可能になることです。
例えば、検索フォームに入力された文字列をリアルタイムでチェックし、検索候補を表示するサジェスト機能などが実現できます。
また、JavaScriptなら、サーバーとの通信を待たずにクライアント側で検索処理を完結できるので、レスポンスの高速化にも役立ちます。
●JSONデータからキーワード検索
さて、サイト内検索を実装するには、まず検索対象のデータが必要ですよね。
ここでは、JSONファイルに保存されたデータから、キーワードに合致する情報を抜き出していきます。
○サンプルコード1:シンプルな検索
最初は、JSONデータの中から、特定のキーの値がキーワードと完全に一致するものを探す単純な検索を実装してみましょう。
function searchData(keyword) {
// JSONデータを読み込む
const jsonData = [
{ id: 1, title: "JavaScript基礎" },
{ id: 2, title: "JSONデータの操作" },
{ id: 3, title: "サイト内検索の実装" }
];
// 検索処理
const results = jsonData.filter(item => item.title === keyword);
// 結果を返す
return results;
}
// 検索実行
const keyword = "JSONデータの操作";
const searchResults = searchData(keyword);
console.log(searchResults);
実行すると、次のような結果が得られます。
[{ id: 2, title: "JSONデータの操作" }]
ポイントは、Array.filter()を使って、titleプロパティがキーワードと厳密に等しい(===)オブジェクトだけを抽出していることです。
これにより、完全一致する情報だけを検索結果として取得できました。
○サンプルコード2:部分一致検索
しかし、現実には、ユーザーが入力したキーワードと完全に同じタイトルのコンテンツばかりとは限りません。
そこで、部分一致検索ができるように改良を加えてみましょう。
function searchData(keyword) {
const jsonData = [
{ id: 1, title: "JavaScript基礎" },
{ id: 2, title: "JSONデータの操作" },
{ id: 3, title: "サイト内検索の実装" }
];
// 大文字小文字を区別しない部分一致検索
const results = jsonData.filter(item =>
item.title.toLowerCase().includes(keyword.toLowerCase())
);
return results;
}
const keyword = "json";
const searchResults = searchData(keyword);
console.log(searchResults);
実行結果は次のようになります。
[
{ id: 2, title: "JSONデータの操作" }
]
今度は、String.includes()メソッドを使って、タイトルの一部にキーワードが含まれているかどうかをチェックしています。
また、toLowerCase()で大文字小文字を統一することで、検索の柔軟性も高めました。
○サンプルコード3:複数キーワード検索
実際の検索では、ユーザーが複数のキーワードを入力して絞り込む場合もあります。
そこで、スペース区切りで入力された複数のキーワードにも対応できるようにしてみましょう。
function searchData(keywords) {
const jsonData = [
{ id: 1, title: "JavaScript基礎" },
{ id: 2, title: "JSONデータの操作" },
{ id: 3, title: "サイト内検索の実装" }
];
// 複数キーワードによる検索
const keywordArray = keywords.toLowerCase().split(" ");
const results = jsonData.filter(item =>
keywordArray.every(keyword =>
item.title.toLowerCase().includes(keyword)
)
);
return results;
}
const keywords = "json データ";
const searchResults = searchData(keywords);
console.log(searchResults);
出力結果は次の通りです。
[
{ id: 2, title: "JSONデータの操作" }
]
ここでのミソは、入力されたキーワード文字列をスペースで区切って配列化し、Array.every()で各キーワードが全てタイトルに含まれているかを確認している点です。
これで、AND検索のような挙動を実現できました。
でも、検索機能はこれだけでは不十分。
検索結果の表示方法など、UI/UXの観点からも改善が必要です。
次章では、その辺りを掘り下げていきましょう!
●検索結果の表示方法
JSONデータから目的のコンテンツを抽出できたら、いよいよ検索結果をユーザーに見やすく表示する段階ですね。
せっかく欲しい情報が見つかっても、ごちゃごちゃと出力されたのでは、使い勝手は良くありません。
ここからは、検索結果の表示方法にフォーカスしていきましょう。
HTMLとCSSを効果的に使って、ビジュアル面からもサイト内検索の質を高めていくコツを解説していきます。
○サンプルコード4:テーブル形式
検索結果の定番とも言えるのが、テーブル形式ですよね。
縦横に整理された情報は、一覧性に優れ、必要なデータを探しやすくなります。
まずは、シンプルなテーブル表示の実装例を見てみましょう。
<table id="resultTable">
<thead>
<tr>
<th>ID</th>
<th>タイトル</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
function displayResults(results) {
const tableBody = document.querySelector("#resultTable tbody");
tableBody.innerHTML = "";
for (const item of results) {
const row = document.createElement("tr");
const idCell = document.createElement("td");
const titleCell = document.createElement("td");
idCell.textContent = item.id;
titleCell.textContent = item.title;
row.appendChild(idCell);
row.appendChild(titleCell);
tableBody.appendChild(row);
}
}
</script>
このコードでは、テーブルのヘッダー部分はHTMLで静的に記述し、検索結果を動的に追加していくtbody
は空にしておきます。
そして、JavaScriptでdisplayResults
関数を定義し、検索結果を受け取ったら、tbody
の中身を一旦クリアした上で、各データをtr
とtd
要素として順次追加していくという流れになります。
○サンプルコード5:リスト形式
テーブルはシンプルですが、レイアウトの自由度はやや低いですよね。
そこで、もう少し柔軟性の高いリスト形式の表示も考えてみましょう。
<ul id="resultList"></ul>
<script>
function displayResults(results) {
const list = document.querySelector("#resultList");
list.innerHTML = "";
for (const item of results) {
const listItem = document.createElement("li");
const title = document.createElement("h3");
title.textContent = item.title;
const description = document.createElement("p");
description.textContent = `ID: ${item.id}`;
listItem.appendChild(title);
listItem.appendChild(description);
list.appendChild(listItem);
}
}
</script>
ここでは、ul
要素を使ったリスト形式で検索結果を表示しています。
各結果はli
要素として追加され、タイトルと説明文をそれぞれh3
とp
要素で出力するようにしました。
CSSと組み合わせれば、もっと自由にデザインをアレンジできそうです。
○UIの工夫でユーザビリティアップ
検索結果の表示は、機能面だけでなく、UI/UXの観点からも工夫が必要です。
例えば、こんな改善案が考えられます。
・見出しやサムネイル画像を追加して、視認性を高める
・ページネーションを実装して、大量の結果を分割表示する
・ソート機能を設け、ユーザーが並び替えできるようにする
・キーワードをハイライト表示して、マッチ部分を強調する
こうした機能を少しずつ盛り込んでいくことで、ユーザーにとって使いやすく、情報を探しやすい検索結果画面に進化させられるでしょう。
さて、検索結果の表示方法について理解が深まったところで、続いては、もう一歩進んだ検索機能について解説していきたいと思います。
●複数条件での絞り込み検索
シンプルなキーワード検索は、サイト内検索の基本中の基本でしたね。
でも、実際のWebサイトでは、もう少し細かな条件で検索結果を絞り込めると、ユーザーにとってはより便利になります。
例えば、ECサイトなら、商品カテゴリやブランド、価格帯などの条件を組み合わせて商品を探せたり、ブログなら、タグやカテゴリ、投稿日時などでフィルタリングできたりすると良いですよね。
そこで、この章では、複数の条件で検索できる機能の実装方法について解説していきます。
○サンプルコード6:セレクトボックスで絞込
まずは、セレクトボックスを使った絞り込み検索から見ていきましょう。
セレクトボックスは、予め用意した選択肢の中から1つを選ぶUIです。
これを検索条件として使うことで、例えば「カテゴリ」のような区分けされたデータから、特定の値だけに絞り込むことができます。
<select id="categorySelect">
<option value="">すべて</option>
<option value="JavaScript">JavaScript</option>
<option value="HTML">HTML</option>
<option value="CSS">CSS</option>
</select>
<ul id="resultList"></ul>
<script>
function searchData(keyword, category) {
const jsonData = [
{ id: 1, title: "JavaScript基礎", category: "JavaScript" },
{ id: 2, title: "JSONデータの操作", category: "JavaScript" },
{ id: 3, title: "CSSアニメーション", category: "CSS" },
{ id: 4, title: "HTMLフォーム", category: "HTML" }
];
let results = jsonData;
if (category) {
results = results.filter(item => item.category === category);
}
if (keyword) {
results = results.filter(item =>
item.title.toLowerCase().includes(keyword.toLowerCase())
);
}
return results;
}
function displayResults(results) {
const list = document.querySelector("#resultList");
list.innerHTML = "";
for (const item of results) {
const listItem = document.createElement("li");
listItem.textContent = item.title;
list.appendChild(listItem);
}
}
const categorySelect = document.querySelector("#categorySelect");
categorySelect.addEventListener("change", () => {
const category = categorySelect.value;
const results = searchData("", category);
displayResults(results);
});
</script>
コードを詳しく説明すると、HTMLではカテゴリを選ぶためのセレクトボックスと、結果を表示するul
要素を用意しています。
JavaScriptでは、searchData
関数が、キーワードとカテゴリの2つの引数を受け取り、両方の条件に合致するデータを返すようになっています。
categorySelect
の値が変更されたら、そのカテゴリに該当する結果を表示するようにイベントリスナーを設定しています。
これで、セレクトボックスを選択するだけで、対応するカテゴリの記事だけが一覧表示されるようになりました。
○サンプルコード7:チェックボックスで絞込
セレクトボックスが1つの値しか選べないのに対し、チェックボックスは複数選択が可能な点が特徴です。
例えば、ECサイトで「送料無料」「即日配送」のような条件を組み合わせて選びたい時などに役立ちます。
<label><input type="checkbox" value="JavaScript"> JavaScript</label>
<label><input type="checkbox" value="HTML"> HTML</label>
<label><input type="checkbox" value="CSS"> CSS</label>
<ul id="resultList"></ul>
<script>
function searchData(keyword, categories) {
const jsonData = [
{ id: 1, title: "JavaScript基礎", category: "JavaScript" },
{ id: 2, title: "JSONデータの操作", category: "JavaScript" },
{ id: 3, title: "CSSアニメーション", category: "CSS" },
{ id: 4, title: "HTMLフォーム", category: "HTML" }
];
let results = jsonData;
if (categories.length > 0) {
results = results.filter(item => categories.includes(item.category));
}
if (keyword) {
results = results.filter(item =>
item.title.toLowerCase().includes(keyword.toLowerCase())
);
}
return results;
}
function displayResults(results) {
const list = document.querySelector("#resultList");
list.innerHTML = "";
for (const item of results) {
const listItem = document.createElement("li");
listItem.textContent = item.title;
list.appendChild(listItem);
}
}
const checkboxes = document.querySelectorAll("input[type='checkbox']");
checkboxes.forEach(checkbox => {
checkbox.addEventListener("change", () => {
const categories = Array.from(checkboxes)
.filter(checkbox => checkbox.checked)
.map(checkbox => checkbox.value);
const results = searchData("", categories);
displayResults(results);
});
});
</script>
チェックボックスの場合、選択された項目の値を配列として取得するのがポイントです。
searchData
関数では、categories
引数を配列として受け取り、Array.includes()
メソッドを使って、各データのカテゴリがその配列に含まれているかをチェックしています。
これで、「JavaScript」と「CSS」のチェックボックスをオンにすると、その両方のカテゴリに属する記事だけが絞り込まれて表示されるようになります。
○サンプルコード8:スライダーで範囲指定
最後は、スライダーを使った範囲指定の検索です。
これは、数値データを対象に、最小値と最大値の間に収まるものだけを抽出したい場合などに使えます。
<input type="range" id="priceSlider" min="0" max="10000" step="1000" value="5000">
<p>選択された価格上限: <span id="priceValue"></span>円</p>
<ul id="resultList"></ul>
<script>
function searchData(keyword, maxPrice) {
const jsonData = [
{ id: 1, title: "商品A", price: 3000 },
{ id: 2, title: "商品B", price: 5000 },
{ id: 3, title: "商品C", price: 8000 },
{ id: 4, title: "商品D", price: 10000 }
];
let results = jsonData;
if (maxPrice) {
results = results.filter(item => item.price <= maxPrice);
}
if (keyword) {
results = results.filter(item =>
item.title.toLowerCase().includes(keyword.toLowerCase())
);
}
return results;
}
function displayResults(results) {
const list = document.querySelector("#resultList");
list.innerHTML = "";
for (const item of results) {
const listItem = document.createElement("li");
listItem.textContent = `${item.title} (${item.price}円)`;
list.appendChild(listItem);
}
}
const priceSlider = document.querySelector("#priceSlider");
const priceValue = document.querySelector("#priceValue");
priceValue.textContent = priceSlider.value;
priceSlider.addEventListener("input", () => {
const maxPrice = Number(priceSlider.value);
priceValue.textContent = maxPrice;
const results = searchData("", maxPrice);
displayResults(results);
});
</script>
コード内では、priceSlider
の値が変更される度に、その値をmaxPrice
としてsearchData
関数に渡しています。
searchData
関数内では、各商品のprice
プロパティがmaxPrice
以下であるかを比較し、条件に合う商品だけを抽出しています。
これで、スライダーを動かして価格の上限を設定すると、その価格以下の商品だけが一覧表示されるようになりました。
●検索フォームの作り方
サイト内検索の肝となるのが、検索フォームです。
ここまでは主にJavaScriptでのデータ処理や結果表示について見てきましたが、そもそも利用者が検索キーワードを入力する画面がなければ、検索は始まりませんよね。
ここでは、検索フォームのHTML/CSSでのマークアップ方法と、JavaScriptでの連携の仕方を確認していきます。
シンプルながら使い勝手の良いフォームを目指して、一緒に作っていきましょう。
○サンプルコード9:シンプルなフォーム
手始めに、最もシンプルな検索フォームを作ってみましょう。
テキスト入力欄と検索ボタンだけで構成されたベーシックなフォームです。
<form id="searchForm">
<input type="text" id="searchInput" placeholder="キーワードを入力">
<button type="submit">検索</button>
</form>
<ul id="resultList"></ul>
<script>
const searchForm = document.querySelector("#searchForm");
const searchInput = document.querySelector("#searchInput");
searchForm.addEventListener("submit", (event) => {
event.preventDefault();
const keyword = searchInput.value;
const results = searchData(keyword);
displayResults(results);
});
// 以下の関数は前の章と同様のため省略
// function searchData(keyword) { ... }
// function displayResults(results) { ... }
</script>
フォームはform
タグで囲み、その中にinput
タグとbutton
タグを配置しています。
input
タグのtype
属性は"text"
とし、placeholder
属性でユーザーへのヒントを表示するようにしました。
フォームが送信された時の処理は、submit
イベントリスナーで行います。
このイベントはEnterキーの押下でも発火するので、ボタンクリックだけでなくキーボード操作にも対応できます。
イベントリスナー内では、event.preventDefault()
でフォームのデフォルトの送信動作をキャンセルした上で、searchInput
の値を取得し、searchData
関数に渡して検索を実行。
結果をdisplayResults
関数で表示する流れになっています。
さて、これで一通りの検索の流れは完成です。
でも、もう一歩踏み込んで、検索オプションなども付けられるようにしてみませんか?
○サンプルコード10:検索オプション付きフォーム
せっかくなので、AND・OR検索の切り替えや、絞り込み条件を指定できるフォームを作ってみましょう。
ラジオボタンとセレクトボックスを使って、オプションを選べるようにします。
<form id="searchForm">
<input type="text" id="searchInput" placeholder="キーワードを入力">
<div>
<label>
<input type="radio" name="operator" value="AND" checked> AND検索
</label>
<label>
<input type="radio" name="operator" value="OR"> OR検索
</label>
</div>
<div>
<label>カテゴリ:</label>
<select id="categorySelect">
<option value="">指定なし</option>
<option value="JavaScript">JavaScript</option>
<option value="HTML">HTML</option>
<option value="CSS">CSS</option>
</select>
</div>
<button type="submit">検索</button>
</form>
<ul id="resultList"></ul>
<script>
const searchForm = document.querySelector("#searchForm");
const searchInput = document.querySelector("#searchInput");
const operatorRadios = document.querySelectorAll("input[name='operator']");
const categorySelect = document.querySelector("#categorySelect");
searchForm.addEventListener("submit", (event) => {
event.preventDefault();
const keyword = searchInput.value;
const operator = operatorRadios[0].checked ? "AND" : "OR";
const category = categorySelect.value;
const results = searchData(keyword, operator, category);
displayResults(results);
});
function searchData(keyword, operator, category) {
// 検索処理
// `operator`と`category`の値を条件に応じて使い分ける
}
</script>
AND・OR検索の切り替えは、name
属性が同じ2つのラジオボタンで実装しました。
選択されたラジオボタンの値を取得することで、searchData
関数内で適切な検索ロジックを実行できます。
カテゴリの絞り込みには、select
タグを使用。option
タグでカテゴリ名を並べ、value
属性で対応する値を設定しておきます。
選ばれたカテゴリの値をsearchData
関数に渡せば、結果をフィルタリングできますね。
フォームが少し賑やかになりましたが、機能的にはグンと使いやすくなったのではないでしょうか。
○ユーザビリティを考えたフォームデザイン
せっかくオプションを付けたので、見た目のデザインにもこだわりたいですよね。
フォームのユーザビリティを高めるポイントを意識しながら、CSSでスタイリングしていきましょう。
・十分な余白を設け、間隔を詰め過ぎない
・必須項目とオプション項目を明確に区別する
・選択肢の近くにラベルを配置する
・検索ボタンは目立つ配色にする
・入力欄にフォーカスした時の視認性を高める
こんな感じでしょうか。
<style>
#searchForm {
padding: 16px;
}
#searchInput {
padding: 8px;
width: 100%;
font-size: 16px;
margin-bottom: 16px;
border: 1px solid #ddd;
}
#searchInput:focus {
outline: none;
border-color: #0066cc;
box-shadow: 0 0 4px #0066cc;
}
#searchForm label {
display: inline-block;
margin: 8px 0;
}
button[type="submit"] {
font-size: 16px;
padding: 8px 16px;
background-color: #0066cc;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin-top: 16px;
}
button[type="submit"]:hover {
background-color: #0052a3;
}
</style>
地味な変更ですが、ちょっとした装飾でグッとフォームが引き締まった印象になりました。
実際のサイトでは、サイト全体のデザインともマッチするよう、さらにブラッシュアップしていくといいでしょう。
検索フォームは、サイト内検索の顔とも言えるパーツ。
使いやすさとデザイン性の両立を目指して、ユーザーに最高の検索体験を届けられるよう、工夫を重ねていきたいですね。
●よくあるエラーと対処法
JavaScriptでサイト内検索を実装する際、思わぬところでエラーに遭遇することがあります。
初心者の頃は、エラーメッセージを見ても、何が原因なのか見当もつかず、途方に暮れてしまいますよね。
ここでは、そんなサイト内検索でよくあるエラーとその対処法を確認していきましょう。
あなたの実装で起きたエラーの原因と解決策が見つかるかもしれません。
○データが表示されない時
実装を終えて検索をしてみたのに、何も結果が返ってこない。
そんな時は、次の点をチェックしてみてください。
・JSONデータのパスが正しいか
・データの形式にミスがないか(JSONの記法エラーなど)
・検索ロジックが意図通りか(大文字小文字の区別など)
・結果を表示する要素が正しく指定されているか
これらを1つずつ丁寧に確認していきましょう。
コンソールにエラーが出ていれば、それも手がかりになります。
例えば、こんなエラーメッセージが出ていたとします。
Uncaught SyntaxError: Unexpected token ] in JSON at position 104
これは、JSONデータの104文字目あたりに、不正な]
があることを示唆しています。
データファイルを見直して、閉じ忘れの}
や]
がないか、ダブルクォーテーションの不整合がないかなど、記法をチェックしてみてください。
修正後、再読み込みすれば、無事にデータが表示されるはずです。
エラーメッセージを手掛かりに問題を特定していく。これが、エラー解決の基本的な流れになります。
○検索結果が正しくない時は
検索はできるけど、結果があまり意図したものではない。
そういう場合は、検索ロジックを再確認しましょう。
例を見てみます。
function searchData(keyword) {
const results = jsonData.filter(item =>
item.title.includes(keyword)
);
return results;
}
この部分一致検索の例だと、大文字小文字が区別されてしまいます。
つまり、"JavaScript"
というキーワードでは、"javascript"
という単語を含むアイテムが見つかりません。
これを解決するには、検索時に大文字小文字を統一すればOKですね。
function searchData(keyword) {
const results = jsonData.filter(item =>
item.title.toLowerCase().includes(keyword.toLowerCase())
);
return results;
}
toLowerCase()
を使って、比較時にはどちらも小文字に揃えるようにしました。
これで、"JavaScript"
でも"javascript"
でも、同じ結果が得られるはずです。
検索の仕様と実装をしっかり突き合わせることが、意図通りの結果を得るコツです。
○動作が遅い時の高速化テクニック
サイト内検索の実装が一通り完了しても、検索に時間がかかりすぎるようでは困りますよね。
特に、膨大なデータを扱う場合は深刻です。
パフォーマンスの問題は、検索の精度と同じくらい重要な課題。ユーザー体験に直結するからです。
では、どうすれば検索速度を上げられるでしょうか。
・検索対象のデータを必要最小限に絞る
・インデックスを使って検索効率を上げる
・キャッシュを活用して重複した処理を減らす
これらの高速化テクニックを状況に応じて使い分けていきます。
例えば、1万件のデータから検索するとします。
title
とcategory
の両方を対象にするのではなく、予めcategory
で絞り込んでおけば、検索対象が大幅に減らせます。
function searchData(keyword, category) {
let results = jsonData;
// カテゴリで絞り込んでから検索
if (category) {
results = results.filter(item => item.category === category);
}
results = results.filter(item =>
item.title.toLowerCase().includes(keyword.toLowerCase())
);
return results;
}
1万件が1000件になれば、その分検索も速くなるでしょう。
また、頻繁に検索されるキーワードと結果をキャッシュしておき、同じリクエストが来たらキャッシュを返すのも有効です。
アクセスが集中するサイトならなおさらですね。
const cache = {};
function searchData(keyword) {
// キャッシュがあれば、それを返す
if (cache[keyword]) {
return cache[keyword];
}
const results = jsonData.filter(item =>
item.title.toLowerCase().includes(keyword.toLowerCase())
);
// 結果をキャッシュに保存
cache[keyword] = results;
return results;
}
このように、cache
オブジェクトを使ってキーワードと結果のペアを保存しておきます。
同じキーワードで再度検索された時は、いちいちデータを検索し直さずに済むので、レスポンスが向上するはずです。
パフォーマンスチューニングは、データ量が増えれば増えるほど重要になってきます。
データ構造や処理のロジックを工夫して、できるだけ無駄を省いていく。
これが、高速な検索を実現する秘訣です。
常にユーザー目線に立って、使い勝手の良いサイト内検索を目指していきたいですね。
まとめ
サイト内検索の実装は、エンジニアとしての成長の良い機会になったのではないでしょうか。
複雑なロジックを考え、パフォーマンスと使い勝手の両立を目指す。
そうした経験の積み重ねが、あなたのスキルをレベルアップしていきます。
この記事で得た知識を武器に、現場の課題にどんどん立ち向かっていってください。
もし行き詰まることがあっても、ここで学んだ問題解決の手順を思い出してみてくださいね。