カスタム検索の「Google臭さ」をJSとCSSでカスタマイズするスマートな方法

2016/10/20

Almir Bijedic

61

Articles in this issue reproduced from SitePoint
Copyright © 2016, All rights reserved. SitePoint Pty Ltd. www.sitepoint.com. Translation copyright © 2016, KADOKAWA ASCII Research Laboratories, Inc. Japanese syndication rights arranged with SitePoint Pty Ltd, Collingwood, Victoria,Australia through Tuttle-Mori Agency, Inc., Tokyo

Googleカスタム検索を使うとサイト内検索を簡単に実装できますが、デザインがいかにも「Googleっぽく」なってしまいます。サイト全体となじむデザインにカスタマイズする方法を紹介しましょう。

WebサイトでCMS内蔵の検索機能や独自の検索機能を使う代わりに、Google カスタム検索エンジン(GCSE)を使うケースが多くなってきています。理由は単純で、作業が簡単で、効果的だからです。高度なフィルターやカスタム検索パラメーターを使わないのであれば、GSCEはコンテンツ検索にぴったりです。

この記事では、結果ボックスを(特別なGCSEタグを使用せずに)手動で表示する方法と、検索フィールドをスタリングする方法について紹介します。

Googleカスタム検索をただ設置するだけでは済まない理由

運営しているWebサイトにGCSEを追加するのは、スクリプトやカスタムHTMLタグをコピー&ペーストするのと同じくらい簡単です。特別なGCSEタグを配置するだけで、入力フィールドが表示されます。このフィールドから入力・検索をすると、以前に設定したパラメーターに基づいてGoogle検索ができます(たとえばsitepoint.com内だけを検索するなど)。

よくある質問は「GCSEの入力フィールドのプレースホルダーを変更する方法」です(日本版編注:GCSEのプレースホルダーにはGoogleロゴが表示されている)。この場合、GCSEからのAjax呼び出しが完了していること(input要素がDOMにアタッチされていること)を待ち、その後、JavaScriptで属性を変更します。ただこの方法は、信頼性の低いsetTimeoutメソッドを使用するので、残念ながら最初に表示されるプレースホルダーはかなりの確率で正しくありません。

そこで、要素を参照してJSで属性を変更するものの、やみくもにsetTimeout()を実行するのではなく、inputが読み込まれていることを保証するGCSEが提供するコールバックを使います。

GCSEアカウントの作成

検索エンジンはすべてオンラインで設定します。GCSEのサイトへ進み、追加をクリックします。検索したいドメイン(通常は自分のサイトURL)を入力してウィザードに従います。この段階で、詳細設定はしません。

完了をクリックすると、次の3つのオプションが提示されます。

  1. コードを取得:自分のサイトに検索結果を表示するためのコードを取得
  2. パブリックURL:設定した検索のワーキングプレビューを表示
  3. コントロールパネル:検索をカスタマイズ

コントロールパネルへ移動し、検索エンジンIDをクリックして値をメモします。

HTML設定

GSCEを試すために必要なHTMLを含む基本的なindex.htmlと、検索の表示およびカスタマイズに必要な関数を含むapp.jsファイルを作成します。

以下のコードを含む基本的なHTMLファイルを作成します。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>GCSE test</h1>
    <div class="gcse-search-wrapper"></div>
    <div class="gcse-results-wrapper"></div>
    <script src="app.js"></script>
</body>
</html>

検索フォームと結果を表示する要素として認識できるように、特別なclassがある2つの<div>を追加しました。

手動表示の関数

app.jsに次のコードを追加します。

var config = {
  gcseId: '006267341911716099344:r_iziouh0nw',
  resultsUrl: 'http://localhost:8080',
  searchWrapperClass: 'gcse-search-wrapper',
  resultsWrapperClass: 'gcse-results-wrapper'
};

var renderSearchForms = function () {
  if (document.readyState == 'complete') {
    queryAndRender();
  } else {
    google.setOnLoadCallback(function () {
      queryAndRender();
    }, true);
  }
};

var queryAndRender = function() {
  var gsceSearchForms = document.querySelectorAll('.' + config.searchWrapperClass);
  var gsceResults = document.querySelectorAll('.' + config.resultsWrapperClass);

  if (gsceSearchForms) {
    renderSearch(gsceSearchForms[0]);
  }
  if (gsceResults) {
    renderResults(gsceResults[0]);
  }
};

var renderSearch = function (div) {
    google.search.cse.element.render(
      {
        div: div.id,
        tag: 'searchbox-only',
        attributes: {
          resultsUrl: config.resultsUrl
        }
      }
    );
    if (div.dataset &&
        div.dataset.stylingFunction &&
        window[div.dataset.stylingFunction] &&
        typeof window[div.dataset.stylingFunction] === 'function') {
      window[div.dataset.stylingFunction](form);
    }
};

var renderResults = function(div) {
  google.search.cse.element.render(
    {
      div: div.id,
      tag: 'searchresults-only'
    });
};

window.__gcse = {
  parsetags: 'explicit',
  callback: renderSearchForms
};

(function () {
  var cx = config.gcseId;
  var gcse = document.createElement('script');
  gcse.type = 'text/javascript';
  gcse.async = true;
  gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
    '//cse.google.com/cse.js?cx=' + cx;
  var s = document.getElementsByTagName('script')[0];
  s.parentNode.insertBefore(gcse, s);
})();

設定のため変数を宣言します。先ほどメモしたIDを設定のgcseIdフィールドに入力します。ローカルのindex.htmlファイルのURLをresultsUrlフィールドに入力します。これは、ユーザーが検索クエリを送信したあとに、リダイレクトされる場所です。また、GCSEは設定されたURLのページに結果のフィールドが含まれていることを期待します。

addSearchForms

addSearchForms関数はページの読み込みを確認し、読み込まれている場合はqueryAndRender()を表示する関数を呼び出し、読み込まれていない場合はドキュメントの読み込みが終わったあと戻るためのコールバックを設定します。

queryAndRender

queryAndRender関数は、設定したclassを持つ要素のDOMを参照します。ラッパーのdivがある場合は、検索と結果のフィールドをそれぞれ表示するrenderSearch()renderResults()を呼び出します。

renderSearch

魔法を起こすのは、renderSearch関数です。

Google検索APIを使って検索ボックスを作成し(google.search.cse.elementオブジェクト使用法の詳細マニュアルはここ)、検索クエリがアクティブな場合は結果ボックスを作成します。

render関数はたくさんの引数を受け取るので、カスタマイズが必要な場合はマニュアルを確認してください。引数divは検索を表示したいdivのID、tag引数は何を表示するか(結果、検索、あるいは両方)を指定します。

さらに、renderSearch()はラッパー要素のデータ属性を探して、styling-function属性が存在する場合、スコープ内でその関数名を見つけて要素に対して適用します。これで要素のスタイルを設定できます。

window.__gcse = {
  parsetags: 'explicit',
  callback: renderSearchForms
};

上のコードスニペットは、GCSE内部で使用し、読み込みが完了したときにコールバック関数を実行できるように、グローバルスコープのコールバック変数を設定します。これは、入力フィールドのプレースホルダー(またはほかのもの)をsetTimeout()を使って書き換える方法よりも、うまく機能します。

テスト実行

ここまでで、検索ボックスと結果のレンダリングに必要なすべてをインクルードしました。node.jsをインストールしている場合は、index.htmlapp.jsファイルのあるフォルダに移動してhttp-serverコマンドを実行します。デフォルトでポート8080上のローカルホストのフォルダからコンテンツを提供します。

Test Run

スタイリング

これで、検索のdiv要素にカスタムスタイリング機能を追加する準備ができました。index.htmlに戻り、#searchForm divにstyling-function属性を追加します。

<div styling-function="removePlaceholder"
id="searchForm" class="gcse-search-wrapper"></div>

app.jsに移動し、ファイル上部の設定変数宣言に次の新しい関数を追加します。

var removePlaceholder = function(div) {
  var inputField = div.querySelector("input.gsc-input");

  // Change the placeholder
  inputField.placeholder = "Search SitePoint";

  // Remove the background
  inputField.style.background = "none";

  // The background will get re-attached on blur, so add an event that will also remove it on blur
  // Another way to do this would be to de-attach the element from the DOM and then re-attach again, hence wiping the listeners
  inputField.addEventListener("blur", function() {
    inputField.style.background = "none";
  });
};

もう1度テストページをロードすると、適切なプレースホルダーが表示されます。

Voila!

最後に

簡単な検索機能をすばやく実装するには、静的HTMLサイトの場合は特にGoogleカスタム検索エンジンが最適です。少しのJavaScriptで検索フォームだけでなく結果ページのカスタマイズができ、よりシームレスな体験を提供できます。

※本記事はMark Brownが査読を担当しています。最高のコンテンツに仕上げるために尽力してくれたSitePointの査読担当者のみなさんに感謝します。

※日本版編注:Googleカスタム検索(無料版)にはGoogleロゴの扱いに関する規定があります。ドキュメントを参照してください。

(原文:Quick Tip: How to Style Google Custom Search Manually

[翻訳:柴田理恵/編集:Livit

Copyright © 2016, Almir Bijedic All Rights Reserved.

Almir Bijedic

Almir Bijedic

Webに関することならなんでもこいのオールラウンダーです。Ubuntu Webサーバーから.NET WWFのサービスの設定、フロントエンドまであらゆるものに挑戦しました。最近ではJavaScriptに注目。Webの仕事をしていないときは大好きなIoTの世界に浸っているか、料理や映画鑑賞、ときにはビスケットを食べたりもしています。

Loading...