CATEGORIES:CSS JAVA WORDPRESS
検索フォームに最近の検索履歴を表示する#02

※ デモなので、実際には検索しない。検索した言葉が履歴に入るだけ。

※ デモなので、実際には検索しない。検索した言葉が履歴に入るだけ。

WWW.EXAMPLE.COM | COPYRIGHT 2020 SAMPLE

虫眼鏡を押すと開く検索フォームに、最近の検索履歴を表示する。履歴を押せばそのまま検索、× で1件ずつ消せる。

「検索フォームに最近の検索履歴を表示する」では、ふつうの検索フォームに履歴を表示していたのだが、履歴の機能を虫眼鏡で開く検索フォームに、そのまま追加すると履歴の幅が狭くなる、検索窓が開かなくなる、× を押すと検索窓が閉じる、閉じても履歴が残る、といったことが起きる。追加する手順をまとめる。

動きは次のとおり。

状態履歴
閉じている(最初)出ない
虫眼鏡を押して開く検索窓の真下に、窓と同じ幅で出る
履歴を押すその言葉で検索する
× を押すその1件だけ消える。窓は開いたまま
入力なしで虫眼鏡を押して閉じる履歴も消える
外をクリック・Esc キー履歴を閉じる

※ 「検索フォームに最近の検索履歴を表示する」の CSS・JavaScript と、「クリックで飛び出す検索フォーム」のコードが、先に入っている前提。jQuery は不要。虫眼鏡の表示に、クリックで飛び出す検索フォームと同じ Font Awesome 4.7 を使う。
※ 「虫眼鏡のヨコにテキストがない場合」は、クリックで飛び出す検索フォームの最初の形。「ヨコにテキストがある場合」は、コピーライトの横などに置いて、文字の上に重ねて広げる形。それぞれに応じた修正方法を記載。

CSS を配置

「検索フォームに最近の検索履歴を表示する」の CSS と、「クリックで飛び出す検索フォーム」の CSS の下に、次の追加1〜3を配置。ヨコにテキストがない場合は追加4、ある場合は追加5も配置。

※ .search-history の position などを上書きするので、必ず下に置く

追加1;履歴を、窓の左端・真下に、同じ幅で出す

「検索フォームに最近の検索履歴を表示する」では、入力欄の幅を JavaScript で測って、履歴の位置と幅を決めていた。ただ、虫眼鏡で開く検索フォームは、開く動き(0.35秒)の途中で測ると、まだ狭い幅を拾ってしまう。ヨコにテキストがない場合は、履歴の幅が10px前後になった。測るのをやめて、CSS で窓に合わせる。窓の幅が動けば、履歴も同じように動く。

/* 履歴:検索窓の左端・真下に、窓と同じ幅で出す(窓の幅が動けば、履歴も同じように動く) */
.search-history {
 left: 0;
 top: 100%;
 width: 100%;
}

追加2;窓が閉じているときは、履歴も隠す

入力なしで虫眼鏡を押すと、窓は閉じる。ただ、「クリックで飛び出す検索フォーム」の閉じる処理は、履歴のことを知らないので、窓だけ閉じて履歴が残る。閉じるときに .is-closed が付くので、.is-closed を目印に履歴を隠す。

/* 検索窓が閉じているときは、履歴も出さない */
.search-slide.is-closed .search-history {
 display: none;
}

追加3;指で押す画面は、1行を高くする

1行が約25pxだと、指では押しにくい。マウスの画面は変えず、指で押す画面(pointer: coarse)だけ約37pxにする。

/* 指で押す画面:1行を押しやすい高さにする(約25px → 約37px) */
@media (pointer: coarse) {
 .search-history_word,
 .search-history_del {
  padding-top: 10px;
  padding-bottom: 10px;
 }
}

追加4;ヨコにテキストがない場合だけ、フォームを中身の幅にする

履歴の位置の基準にするため、「検索フォームに最近の検索履歴を表示する」の JavaScript は form に position: relative を付けていた(修正2 で消す)。代わりに CSS で付ける。display: inline-flex にしておくと、form の幅が窓の幅と同じになり、履歴も窓と同じ幅になる。

/* ヨコにテキストがない場合だけ:フォームを中身の幅にして、履歴の位置の基準にする */
.search-slide {
 position: relative;
 display: inline-flex;
}

※ クリックで飛び出す検索フォームの .search-slide { display: flex; } を上書きするので、必ず下に置く

追加5;ヨコにテキストがある場合だけ狭い画面ではみ出さないようにする

ヨコにテキストがある場合は、窓の幅が文字の長さで決まる。320px 前後の画面だと、履歴が右へはみ出して、× が見えなくなる。履歴の最大幅を、画面の幅から左右の余白を引いた値にする。

/* ヨコにテキストがある場合だけ:狭い画面(320px 前後)で、履歴が右へはみ出さない */
.search-history {
 max-width: calc(100vw - 40px); /* ★ 画面の左右の余白に合わせて変える */
}

JavaScript を直す

「検索フォームに最近の検索履歴を表示する」の JavaScript の、次の6か所を直す。置く場所は同じ。

修正1;使わなくなる変数を消す

submit は、place() が検索ボタンの位置を測るためだけに使っていた。修正3 で place() を消すと、使い道がなくなる。

		var submit = form.querySelector( '[type="submit"]' );

修正2;form に position: relative を付けている部分を消す

履歴の位置の基準にするための処理。ヨコにテキストがない場合は、追加4 で CSS に移した。ヨコにテキストがある場合は、付けると窓が開かなくなる。窓(.search-inner)は position: absolute で、位置の基準が form に変わり、form が虫眼鏡ぶん(18px)の幅しかないため。付けなければ、基準は外側の枠(.search-overlay-wrap)のままで、履歴も窓と同じ左端・幅で出る。

		if ( window.getComputedStyle( form ).position === 'static' ) {
			form.style.position = 'relative'; // リストの位置の基準にする
		}

修正3;位置を測る place() の関数を、まるごと消す

追加1 で、位置と幅は CSS で決めることにした。測る必要がなくなる。

		// 入力欄(+検索ボタン)の真下に、同じ幅で出す
		// フォーム自体が横幅いっぱいのことがあるので、入力欄の位置を測って合わせる
		function place() {
			var fr = form.getBoundingClientRect();
			var ir = input.getBoundingClientRect();
			var right = submit ? Math.max( ir.right, submit.getBoundingClientRect().right ) : ir.right;
			box.style.left  = ( ir.left - fr.left ) + 'px';
			box.style.top   = ( ir.bottom - fr.top ) + 'px';
			box.style.width = ( right - ir.left ) + 'px';
		}

修正4;render() の最後にある place(); を消す

関数を消したので、呼び出しも消す。残すと「place is not defined」のエラーになる。

			box.hidden = false;
			place();   // ← この行を消す

修正5;画面の幅が変わったときに位置を測り直す部分をまるごと消す

place() を呼んでいる部分。履歴の幅は CSS で窓に合わせるので、画面の幅が変わっても測り直さなくていい。残すと修正4 と同じエラーになる。

		// 開いている間に画面の幅が変わったら、位置を測り直す
		window.addEventListener( 'resize', function () {
			if ( ! box.hidden ) {
				place();
			}
		} );

修正6;×(閉じる) の処理を直す

履歴は、描き直すたびに中身を作り直している。× を押すと、× の処理が先に動いて履歴を描き直し、押した × がページから消える。続けて、クリックが上へ伝わっていき、「クリックで飛び出す検索フォーム」の「外をクリックしたら(入力が空なら)閉じる」処理に届く。「外をクリック」の処理は、押された場所が検索フォームの中かを調べているのだが、× はもうページに無いので、フォームの外と判定されて、窓が閉じる。ヨコにテキストがない場合も、ある場合も起きる。

e.stopPropagation(); は、クリックが上へ伝わるのを止める。止めると「外をクリック」の処理に届かなくなり、窓は開いたままになる。変更点は、e.stopPropagation(); の1行と function ( e )。

変更前

				del.addEventListener( 'click', function () {
					remove( word );
					render();
				} );

変更後

				del.addEventListener( 'click', function ( e ) {
					e.stopPropagation(); // 窓が閉じるのを防ぐ
					remove( word );
					render();
				} );

調整するときの変更箇所

調整するときの変更箇所は次のとおり。

変えたいもの変更する場所
残す件数JavaScript の MAX(初期値 5)
1件の最大文字数JavaScript の LIMIT(初期値 50)
リストの見出しJavaScript の TITLE(初期値 'RECENT'。'' で出さない)
検索窓の nameJavaScript の PARAM(初期値 's')
文字・枠線の色CSS の --sh-color --sh-sub --sh-light --sh-line
指で押す画面の、1行の高さCSS の @media (pointer: coarse) の padding-top・padding-bottom
履歴の右の余白(テキストあり)CSS の max-width の 40px

※ JavaScript が動かない環境では、履歴は出ない。検索はできる ※ 指で押す画面(pointer: coarse)では、1行を約25pxから約37pxに広げている。マウスの画面は変わらない

表示環境によって動きの見え方が異なる場合があるため、本番に反映する前に確認してね。

NOTICES

  • 記事内容は実装させたものがほとんどですが自己責任で参考にしてください。

TO HEADER