Как сверстать панель поиска файлов
Эта статья основана на одном из практических заданий verstaem.online.
Вы можете читать материал как обычное руководство или сначала попробовать выполнить задание самостоятельно, а затем сравнить свое решение с подробным разбором.
Перейти к заданиюВ этой статье мы создадим панель поиска файлов с полем ввода, кнопкой фильтрации и кнопкой загрузки. На ее примере разберем, как выстраивать элементы в одну строку, распределять свободное пространство между ними и оформлять компактные кнопки для пользовательского интерфейса.
Создаем HTML-разметку
Сначала создадим базовую HTML-разметку с помощью Emmet. Для этого достаточно ввести ! и нажать Tab. Обратите внимание на атрибут lang. Поскольку основной контент страницы написан на русском языке, здесь используем значение ru.
<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Панель поиска файлов</title>
</head>
<body>
</body>
</html>
Переходим к блоку. Поскольку здесь у нас поиск, стоит использовать в качестве обертки не <div>, а <form>. Несмотря на то, что задание не подразумевает отправку формы куда-либо, наша задача — делать разметку по правилам.
Далее немного спорный момент — это реализация инпута и иконки поиска. Здесь можно пойти двумя путями, и каждый из путей имеет свои нюансы:
- Мы можем сделать иконку поиска как
backgroundдля инпута. Это самый простой вариант, при котором и разметка будет проще и чище - Мы можем сделать иконку поиска как
<svg>изображение. Разметка будет не такая чистая, зато мы даем доступ к изменению цвета.
Я решил выбрать именно второй вариант, но если вы выбрали первый — это не ошибка. Я же решил, что если в будущем в этот поиск кто-то захочет добавить состояние :focus, и менять при нем фон инпута и цвет иконки одновременно — наш подход уже под это готов. Поэтому <input> мы оборачиваем в <label>, и рядом кладем <svg>. Ну, а рядом с <label> будут лежать две кнопки.
<form class="search-panel">
<label class="search-panel__label">
<svg
class="search-panel__icon"
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M17.5 17.5L13.8833 13.8833"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M9.16667 15.8333C12.8486 15.8333 15.8333 12.8486 15.8333 9.16667C15.8333 5.48477 12.8486 2.5 9.16667 2.5C5.48477 2.5 2.5 5.48477 2.5 9.16667C2.5 12.8486 5.48477 15.8333 9.16667 15.8333Z"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<input
type="search"
class="search-panel__input"
placeholder="Поиск файлов..."
/>
</label>
<button
class="search-panel__btn search-panel__btn--filters"
type="button"
>
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.66665 13.3333C6.66659 13.4572 6.70106 13.5787 6.76618 13.6841C6.8313 13.7895 6.9245 13.8746 7.03532 13.93L8.36865 14.5967C8.47031 14.6475 8.58328 14.6714 8.69681 14.6663C8.81035 14.6612 8.92068 14.6271 9.01734 14.5673C9.11399 14.5075 9.19376 14.424 9.24906 14.3247C9.30437 14.2254 9.33337 14.1137 9.33332 14V9.33333C9.33347 9.00292 9.45629 8.68433 9.67798 8.43933L14.4933 3.11333C14.5796 3.01771 14.6364 2.89912 14.6567 2.77192C14.6771 2.64472 14.6601 2.51435 14.6079 2.39658C14.5557 2.27881 14.4705 2.17868 14.3627 2.1083C14.2548 2.03792 14.1288 2.0003 14 2H1.99998C1.87105 2.00005 1.74491 2.03748 1.63682 2.10776C1.52873 2.17804 1.44334 2.27815 1.39099 2.39598C1.33864 2.5138 1.32157 2.64427 1.34187 2.77159C1.36216 2.89892 1.41893 3.01762 1.50532 3.11333L6.32198 8.43933C6.54367 8.68433 6.6665 9.00292 6.66665 9.33333V13.3333Z"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
Фильтры
</button>
<button class="search-panel__btn search-panel__btn--upload" type="button">
Загрузить
</button>
</form>
Обратите внимание на три момента:
- У кнопок задан атрибут
typeсо значениемbutton. Это сделано намеренно, чтобы кнопка внутри формы перестала отправлять ее. В этом макете нет кнопки отправки, но кнопка «Фильтры» и «Загрузить» не должны отправлять форму поиска. - У этих же кнопок добавлены дополнительные классы. Все потому, что структурно кнопки идентичны, и отличаются лишь цветами. С помощью дополнитльных классов мы и изменим внешний вид.
- У
<svg>убран атрибутstroke. Это обязательно нужно сделать, чтобы была возможность менять цвет с помощью CSS.
Добавляем стили
Подключим файл стилей через <link> и зададим несколько базовых правил. Для этого задания достаточно переопределить box-sizing, сбросить отступ у <body> и подключить шрифт Inter, который используется в макете.
* {
box-sizing: border-box;
}
@font-face {
font-family: "Inter";
src: url("../fonts/InterRegular.woff2");
font-display: swap;
font-weight: 400;
}
@font-face {
font-family: "Inter";
src: url("../fonts/InterMedium.woff2");
font-display: swap;
font-weight: 500;
}
body {
margin: 0;
padding: 20px;
font-family: "Inter", sans-serif;
background: #f3f4f6;
}
Обращаю ваше внимание на подключение шрифтов. Мы указываем одинаковый font-family, но разный font-weight. Это и позволит нам отличать начертания шрифта между собой.
Далее зададим стили для всего блока в целом. Забираем все из макета и добавляем к этому flexbox вместе с gap.
.search-panel {
display: flex;
align-items: center;
margin: 0 auto;
max-width: 1080px;
border: 1px solid #e5e7eb;
border-radius: 32px;
padding: 16px;
background: #fff;
gap: 12px;
}
Далее нам нужно научить наш <input> (а точнее, его обертку <label>) растягиваться на все возможное доступное пространство. И в этом нам поможет flex: 1. Также добавим position: relative, чтобы разместить иконку поиска поверх <input>.
.search-panel__label {
position: relative;
flex: 1;
}
Теперь переходим к <input>. Забираем стили из макета. Помимо них стоит задать пару важных стилей:
height: 56px;— несмотря на то, что задавать фиксированную высоту в верстке как правило нельзя, здесь мы имеем поле ввода, и оно никак не подстрадает от фиксации высоты.padding-left: 48px,padding-right: 16px— мы делаем «безопасные отступы». Слева большой, потому что там будет иконка поиска, а справа — чтобы при вводе большого количества текста, он не начал прилипать к краю.
.search-panel__input {
border: 1px solid #edf2f7;
border-radius: 16px;
padding-left: 48px;
padding-right: 16px;
width: 100%;
height: 56px;
font-family: inherit;
font-weight: 400;
font-size: 16px;
color: #6b7280;
background: #f9fafb;
}
Теперь — иконка поиска. Используем position, чтобы разместить элемент там, где нам нужно. И обратите внимание на запись top и translate. Сперва мы сдвигаем элемент на 50% сверху низ, а затем возвращаем его назад на его же половину. Таким образом он встает ровно по центру. Запомните, что translate работает относительно самого элемента.
.search-panel__icon {
position: absolute;
left: 16px;
top: 50%;
width: 20px;
height: 20px;
stroke: #6B7280;
translate: 0 -50%;
}
Следующий этап — кнопки. Сперва создадим базу для обеих кнопок, то есть вынесем туда все то, что у кнопок совпадает. И заодно зададим стили для иконки внутри, используя currentColor. Таким образом, цвет иконки будет всегда совпадать с цветом текста в кнопке, что нам и требуется по макету.
.search-panel__btn {
display: inline-flex;
align-items: center;
justify-content: center;
border: none;
border-radius: 16px;
padding: 16px;
font-family: inherit;
font-weight: 500;
font-size: 16px;
cursor: pointer;
transition: background 0.3s;
gap: 4px;
}
.search-panel__btn svg {
display: block;
width: 16px;
height: 16px;
stroke: currentColor;
}
Как видите, в этом и других заданиях постоянно добавляю для интерактивных элементов (кнопки, ссылки) transition, чтобы затем сделать эффект наведения. Причем даже если в задании это не требуется. Это, как по мне, правило хорошего тона. Даже если дизайнер не озаботился этим, вы можете улучшить интерфейс, сделав интерактивные элементы более живыми. Поэтому ниже мы добавим разные цвета для кнопок, а также эффект наведения.
.search-panel__btn--filters {
color: #2563eb;
background: #eef2ff;
}
.search-panel__btn--upload {
color: #fff;
background: #111827;
}
.search-panel__btn--filters:hover {
background: #cad1e8;
}
.search-panel__btn--upload:hover {
background: #2e3c5b;
}
Теперь вы умеете создавать панель поиска файлов с полем ввода и кнопками действий. Подобные интерфейсы часто встречаются в файловых менеджерах, облачных хранилищах и административных панелях.