search 搜索输入
type="search" 是 HTML5 为搜索场景设计的输入控件。它在功能上与 type="text" 高度相似,但具有一些搜索场景下的特殊行为:默认样式中的清除按钮(部分浏览器)、移动端搜索键盘(带搜索按钮)、以及语义化标识。本节将详细讲解搜索输入框的使用和优化技巧。
前置知识
阅读本节前,建议先了解:url 网址输入
基础概念
什么是 search 输入
type="search" 创建一个专门用于搜索的输入框。与 type="text" 相比,它的差异主要在于:
- 清除按钮:部分浏览器(Webkit/Blink 内核)在有输入内容时自动显示一个 "X" 清除按钮
- 移动端键盘:在手机上弹出搜索键盘(标准键盘 + "搜索"/"前往"按钮)
- 语义化:屏幕阅读器和辅助技术可以识别这是搜索输入框
- 默认样式:部分浏览器可能为 search 输入框添加圆角等特殊样式
<!-- search 输入 -->
<input type="search" name="q" placeholder="搜索...">
<!-- 与 text 的区别 -->
<input type="text" name="q" placeholder="搜索..."> <!-- 无清除按钮 -->
<input type="search" name="q" placeholder="搜索..."> <!-- 有清除按钮(部分浏览器) -->search 的核心特征
| 特征 | 说明 |
|---|---|
| 输入方式 | 键盘输入 |
| 数据类型 | 字符串 |
| 自动验证 | 无 |
| 移动端键盘 | 搜索键盘(含搜索按钮) |
| 清除按钮 | 有(Webkit/Blink 内核浏览器) |
语法
基本语法
<input
type="search"
name="q"
id="search"
placeholder="搜索关键词..."
required
maxlength="100"
autocomplete="off"
list="searchSuggestions"
>常用属性
search 支持与 text 相同的所有属性。以下是搜索场景中常用的属性:
| 属性 | 值 | 说明 |
|---|---|---|
type | "search" | 指定为搜索输入 |
name | "q" / "keyword" / "search" | 搜索字段名 |
placeholder | 字符串 | 搜索提示文字 |
autocomplete | "off" | 搜索通常关闭自动补全(自己实现) |
list | datalist id | 搜索建议列表 |
maxlength | 正整数 | 限制搜索关键词长度 |
required | - | 某些场景下搜索词为必填 |
详细说明
清除按钮
Webkit/Blink 内核的浏览器(Chrome、Safari、Edge)会在 type="search" 输入框有内容时,自动在右侧显示一个 "X" 形状的清除按钮。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>search 清除按钮</title>
<style>
.search-input {
width: 300px;
padding: 10px 12px;
font-size: 14px;
border: 1px solid #ccc;
border-radius: 20px;
box-sizing: border-box;
}
/* 查看原生清除按钮 */
/* 在 Chrome/Safari 中,输入内容后右侧会出现 X 按钮 */
</style>
</head>
<body>
<h2>search 清除按钮</h2>
<!-- Chrome/Safari/Edge 中,输入文字后会出现 X 按钮 -->
<input type="search" name="q" placeholder="输入内容后查看清除按钮" class="search-input">
<!--
清除按钮的行为:
1. 点击 X 后,输入框的值被清空
2. 触发 input 事件
3. 输入框重新获得焦点
注意:清除按钮只在 Webkit/Blink 内核浏览器中显示
Firefox 默认不显示清除按钮
-->
</body>
</html>自定义清除按钮(兼容所有浏览器)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>自定义清除按钮</title>
<style>
.search-box {
position: relative;
display: inline-block;
width: 350px;
}
.search-box input {
width: 100%;
padding: 10px 36px 10px 12px;
border: 2px solid #ddd;
border-radius: 20px;
font-size: 14px;
box-sizing: border-box;
transition: border-color 0.2s;
}
.search-box input:focus {
outline: none;
border-color: #4a90d9;
}
/* 隐藏 Webkit 原生清除按钮 */
.search-box input::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
}
/* 自定义清除按钮 */
.clear-btn {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
width: 20px;
height: 20px;
border: none;
background: none;
cursor: pointer;
display: none; /* 默认隐藏 */
color: #999;
font-size: 18px;
line-height: 20px;
text-align: center;
border-radius: 50%;
}
.clear-btn:hover {
color: #333;
background-color: #f0f0f0;
}
/* 有内容时显示清除按钮 */
.search-box.has-value .clear-btn {
display: block;
}
</style>
</head>
<body>
<h2>自定义搜索框</h2>
<div class="search-box" id="searchBox">
<input type="search"
id="searchInput"
name="q"
placeholder="搜索内容...">
<button type="button" class="clear-btn" id="clearBtn">×</button>
</div>
<script>
const searchInput = document.getElementById('searchInput');
const clearBtn = document.getElementById('clearBtn');
const searchBox = document.getElementById('searchBox');
// 输入时控制清除按钮的显示
searchInput.addEventListener('input', function() {
searchBox.classList.toggle('has-value', this.value.length > 0);
});
// 点击清除按钮
clearBtn.addEventListener('click', function() {
searchInput.value = '';
searchBox.classList.remove('has-value');
searchInput.focus();
// 触发 input 事件(如果有监听者)
searchInput.dispatchEvent(new Event('input'));
});
// ESC 键清除
searchInput.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
this.value = '';
searchBox.classList.remove('has-value');
}
});
</script>
</body>
</html>移动端键盘优化
type="search" 在移动设备上的主要优势是虚拟键盘右下角显示"搜索"按钮(而非"换行"或"完成"),这符合用户在搜索场景下的操作习惯。
| input type | 移动端键盘右下角按钮 | 适用场景 |
|---|---|---|
text | 换行/Return | 普通文本输入 |
search | 搜索/Go | 搜索框 |
url | 前往/Go | URL 输入 |
email | 发送/Go | 邮箱输入 |
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>移动端搜索键盘</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
.search-bar {
width: 100%;
padding: 12px 16px;
font-size: 16px;
border: 1px solid #ddd;
border-radius: 8px;
box-sizing: border-box;
margin-bottom: 16px;
}
/* 16px 防止 iOS 自动缩放 */
</style>
</head>
<body>
<!--
在手机上打开此页面:
1. 点击搜索框,键盘右下角显示"搜索"按钮
2. 输入关键词后点击"搜索",等同于按回车
-->
<!-- 方式一:type="search"(推荐) -->
<form action="/search" method="get">
<input type="search"
name="q"
class="search-bar"
placeholder="搜索..."
autocomplete="off">
</form>
<!--
方式二:type="text" + inputmode="search"
在需要 text 行为但想要搜索键盘时使用
-->
<form action="/search" method="get">
<input type="text"
name="q"
class="search-bar"
inputmode="search"
placeholder="搜索..."
autocomplete="off">
</form>
</body>
</html>iOS 自动缩放问题
在 iOS Safari 上,当 <input> 的 font-size 小于 16px 时,聚焦输入框会触发页面缩放。搜索框应设置 font-size: 16px 或以上以避免此问题。
搜索输入的事件处理
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>搜索事件处理</title>
<style>
.search-container {
max-width: 600px;
margin: 30px auto;
}
.search-input {
width: 100%;
padding: 12px 16px;
font-size: 16px;
border: 2px solid #ddd;
border-radius: 24px;
box-sizing: border-box;
}
.search-input:focus {
outline: none;
border-color: #4a90d9;
}
.results {
margin-top: 16px;
min-height: 200px;
padding: 16px;
border: 1px solid #e0e0e0;
border-radius: 8px;
}
.result-item {
padding: 10px;
border-bottom: 1px solid #f0f0f0;
}
.result-item:last-child {
border-bottom: none;
}
.loading {
color: #999;
text-align: center;
padding: 20px;
}
.empty {
color: #999;
text-align: center;
padding: 40px 20px;
}
</style>
</head>
<body>
<div class="search-container">
<h2>实时搜索</h2>
<!--
搜索表单使用 GET 方法
提交后 URL 变为 /search?q=关键词
这个 URL 可以被分享、收藏
-->
<form id="searchForm" action="/search" method="get">
<input type="search"
id="searchInput"
name="q"
class="search-input"
placeholder="输入关键词搜索..."
autocomplete="off">
<!-- 隐藏的提交按钮(回车或搜索键触发) -->
<button type="submit" style="display:none;"></button>
</form>
<div class="results" id="results">
<div class="empty">输入关键词开始搜索</div>
</div>
</div>
<script>
const searchInput = document.getElementById('searchInput');
const searchForm = document.getElementById('searchForm');
const resultsDiv = document.getElementById('results');
let debounceTimer = null;
// 实时搜索(带防抖)
searchInput.addEventListener('input', function() {
const keyword = this.value.trim();
// 清除之前的定时器
clearTimeout(debounceTimer);
if (!keyword) {
resultsDiv.innerHTML = '<div class="empty">输入关键词开始搜索</div>';
return;
}
// 300ms 防抖
debounceTimer = setTimeout(() => {
performSearch(keyword);
}, 300);
});
// 回车提交(传统表单提交)
searchForm.addEventListener('submit', function(e) {
e.preventDefault();
const keyword = searchInput.value.trim();
if (keyword) {
performSearch(keyword);
// 更新 URL(不刷新页面)
history.pushState({}, '', '/search?q=' + encodeURIComponent(keyword));
}
});
// 模拟搜索函数
function performSearch(keyword) {
resultsDiv.innerHTML = '<div class="loading">搜索中...</div>';
// 模拟异步搜索
setTimeout(() => {
// 模拟搜索结果
const mockResults = [
{ title: `${keyword} - 相关结果一`, url: '/article/1' },
{ title: `${keyword} - 相关结果二`, url: '/article/2' },
{ title: `深入了解${keyword}`, url: '/article/3' },
];
if (mockResults.length > 0) {
resultsDiv.innerHTML = mockResults.map(item =>
`<div class="result-item">
<a href="${item.url}">${item.title}</a>
</div>`
).join('');
} else {
resultsDiv.innerHTML = '<div class="empty">未找到相关结果</div>';
}
}, 500);
}
// 检查 URL 中是否有搜索参数(页面加载时)
const params = new URLSearchParams(window.location.search);
const urlKeyword = params.get('q');
if (urlKeyword) {
searchInput.value = urlKeyword;
performSearch(urlKeyword);
}
</script>
</body>
</html>关闭 autocomplete
搜索框通常需要关闭浏览器自动补全,因为搜索建议通常由应用自己提供(如搜索历史、热门搜索等)。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>搜索 autocomplete</title>
</head>
<body>
<h2>搜索自动补全</h2>
<!--
搜索框通常关闭浏览器自动补全
因为应用有自己的搜索建议系统
-->
<form action="/search" method="get">
<!-- 关闭自动补全 -->
<input type="search" name="q" autocomplete="off"
placeholder="关闭了浏览器自动补全">
</form>
<!--
但在以下场景可以保留自动补全:
- 站内搜索且用户经常搜索相同内容
- 配合 datalist 提供应用级建议
-->
<form action="/search" method="get">
<!-- 保留自动补全 + datalist -->
<input type="search" name="q" autocomplete="on"
list="recentSearches"
placeholder="保留自动补全 + 应用建议">
<datalist id="recentSearches">
<option value="HTML 教程">
<option value="CSS 布局">
<option value="JavaScript 基础">
</datalist>
</form>
</body>
</html>实战示例
带搜索建议的搜索栏
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>带建议的搜索栏</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
background-color: #f5f5f5;
padding: 20px;
}
.search-header {
max-width: 700px;
margin: 60px auto 20px;
text-align: center;
}
.search-header h1 {
font-size: 28px;
margin-bottom: 24px;
}
.search-wrapper {
position: relative;
max-width: 580px;
margin: 0 auto;
}
.search-wrapper input {
width: 100%;
padding: 14px 44px 14px 20px;
font-size: 16px;
border: 2px solid #ddd;
border-radius: 28px;
transition: all 0.2s;
}
.search-wrapper input:focus {
outline: none;
border-color: #4a90d9;
box-shadow: 0 2px 12px rgba(74, 144, 217, 0.15);
}
/* 隐藏原生清除按钮 */
.search-wrapper input::-webkit-search-cancel-button {
-webkit-appearance: none;
}
.search-btn {
position: absolute;
right: 6px;
top: 6px;
width: 36px;
height: 36px;
border: none;
background-color: #4a90d9;
color: white;
border-radius: 50%;
cursor: pointer;
font-size: 18px;
display: flex;
align-items: center;
justify-content: center;
}
.search-btn:hover {
background-color: #3a7bc8;
}
.suggestions {
position: absolute;
top: 100%;
left: 0;
right: 0;
background: white;
border: 1px solid #e0e0e0;
border-top: none;
border-radius: 0 0 12px 12px;
display: none;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
z-index: 100;
max-height: 300px;
overflow-y: auto;
}
.suggestions.active {
display: block;
}
.suggestion-item {
padding: 10px 20px;
cursor: pointer;
font-size: 14px;
display: flex;
align-items: center;
gap: 10px;
}
.suggestion-item:hover,
.suggestion-item.highlighted {
background-color: #f0f7ff;
}
.suggestion-icon {
color: #999;
font-size: 16px;
}
.suggestion-divider {
padding: 8px 20px 4px;
font-size: 12px;
color: #999;
font-weight: 500;
}
</style>
</head>
<body>
<header class="search-header">
<h1>HTML5 知识库</h1>
<div class="search-wrapper">
<form id="searchForm" action="/search" method="get">
<input type="search"
id="searchInput"
name="q"
placeholder="搜索 HTML、CSS、JavaScript..."
autocomplete="off">
<button type="submit" class="search-btn" aria-label="搜索">
<!-- 搜索图标 SVG -->
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8"/>
<line x1="21" y1="21" x2="16.65" y2="16.65"/>
</svg>
</button>
</form>
<div class="suggestions" id="suggestions"></div>
</div>
</header>
<script>
const searchInput = document.getElementById('searchInput');
const suggestionsDiv = document.getElementById('suggestions');
const searchForm = document.getElementById('searchForm');
// 模拟搜索建议数据
const suggestionsData = {
hot: ['HTML5 教程', 'CSS Grid 布局', 'JavaScript 闭包', 'Flexbox 指南', 'ES6 新特性'],
history: ['input type 属性', '表单验证', '语义化标签']
};
let debounceTimer = null;
let highlightIndex = -1;
searchInput.addEventListener('input', function() {
clearTimeout(debounceTimer);
const query = this.value.trim().toLowerCase();
if (!query) {
// 输入为空时显示热门搜索
showSuggestions('热门搜索', suggestionsData.hot);
return;
}
// 防抖 200ms
debounceTimer = setTimeout(() => {
const filtered = [...suggestionsData.hot, ...suggestionsData.history]
.filter(item => item.toLowerCase().includes(query));
if (filtered.length > 0) {
showSuggestions('搜索建议', filtered);
} else {
suggestionsDiv.classList.remove('active');
}
}, 200);
});
searchInput.addEventListener('focus', function() {
if (!this.value.trim()) {
showSuggestions('热门搜索', suggestionsData.hot);
}
});
// 键盘导航
searchInput.addEventListener('keydown', function(e) {
const items = suggestionsDiv.querySelectorAll('.suggestion-item');
if (!items.length) return;
if (e.key === 'ArrowDown') {
e.preventDefault();
highlightIndex = Math.min(highlightIndex + 1, items.length - 1);
updateHighlight(items);
} else if (e.key === 'ArrowUp') {
e.preventDefault();
highlightIndex = Math.max(highlightIndex - 1, 0);
updateHighlight(items);
} else if (e.key === 'Enter' && highlightIndex >= 0) {
e.preventDefault();
items[highlightIndex].click();
} else if (e.key === 'Escape') {
suggestionsDiv.classList.remove('active');
}
});
function updateHighlight(items) {
items.forEach((item, i) => {
item.classList.toggle('highlighted', i === highlightIndex);
});
}
// 点击外部关闭建议
document.addEventListener('click', function(e) {
if (!e.target.closest('.search-wrapper')) {
suggestionsDiv.classList.remove('active');
}
});
function showSuggestions(title, items) {
highlightIndex = -1;
suggestionsDiv.innerHTML = `
<div class="suggestion-divider">${title}</div>
${items.map(item =>
`<div class="suggestion-item" role="option">
<span class="suggestion-icon">🔍</span>
<span>${item}</span>
</div>`
).join('')}
`;
suggestionsDiv.querySelectorAll('.suggestion-item').forEach(item => {
item.addEventListener('mousedown', function(e) {
e.preventDefault();
searchInput.value = this.querySelector('span:last-child').textContent;
suggestionsDiv.classList.remove('active');
searchForm.submit();
});
});
suggestionsDiv.classList.add('active');
}
</script>
</body>
</html>注意事项
search 与 text 功能几乎相同:
type="search"不会自动验证格式,不会过滤输入。它的优势主要在于语义化和移动端键盘。清除按钮在不同浏览器中表现不同:Chrome/Safari 有清除按钮,Firefox 默认没有。如果需要跨浏览器一致的清除按钮,需要自定义实现。
autocomplete="off" 对搜索框很重要:浏览器自动补全会覆盖应用自己的搜索建议。但注意现代浏览器可能忽略
autocomplete="off"。搜索表单通常使用 GET 方法:搜索的 URL 应该是可分享的(如
/search?q=HTML教程),用户可以复制链接分享搜索结果。iOS 上的 font-size 缩放:确保搜索框的
font-size至少为 16px,防止 iOS Safari 在聚焦时自动缩放页面。
最佳实践
使用
type="search"而非type="text":即使是简单的搜索框,使用正确的 type 可以获得移动端键盘优化和语义化优势。搜索使用 GET 方法:让搜索结果的 URL 包含查询参数,可以被分享和收藏。
实现防抖(debounce):实时搜索时,使用 200~300ms 的防抖延迟,避免频繁发送请求。
提供搜索建议:通过 datalist 或自定义下拉列表提供搜索建议,提升用户体验。
支持键盘导航:搜索建议应支持上下方向键和 Enter 选择。
下一节
继续学习:radio 单选按钮