Наверняка вы видели на различных веб-сайтах и приложениях поле для ввода пароля и кнопку, которая меняет его видимость. Хотя это простая задача для опытных разработчиков, мы хотели бы написать эту заметку для всех, кто может быть еще не сталкивался с ней или только недавно выбрал профессию веб-разработчика.
Разметка
Для начала давайте разберемся с разметкой. Первое, что нужно понять - чтобы разместить кнопку внутри поля ввода, нужно позиционировать ее относительно какого-либо элемента, но поле ввода само по себе не подходит для этого. Поэтому нам нужен дополнительный элемент обёртка, которому мы присвоим определенный класс, например, my-password
. Внутри этого элемента мы разместим само поле ввода.
<div class="my-password">
<input type="password" name="password">
</div>
Далее добавим саму кнопку, которая будет отвечать за переключение видимости.
<div class="my-password">
<input type="password" name="password">
<button class="my-password-toggle"></button>
</div>
С разметкой мы закончили, теперь приступим к стилизации.
Стилизация
Начнём с обёртки и нам нужно для неё указать всего лишь одно свойство.
.my-password {
position: relative;
}
Свойство position
отвечает за определение типа позиционирования элемента и значение relative
позволит нам раположить его дочерние элементы относительно него.
Теперь нам нужно определить стили для нашей кнопки, и для начала сбросим предустановленыые браузерами стили.
.my-password-toggle {
border: none;
background: none;
}
Укажем расположение и размеры. Абсолютное позиционирование относительно обёртки, прижимаем к верху, правой стороне и нижней части, а также добавим внутренние отступы со всех сторон.
.my-password-toggle {
border: none;
background: none;
position: absolute; // [!code ++]
top: 0; // [!code ++]
right: 0; // [!code ++]
bottom: 0; // [!code ++]
padding: 10px; // [!code ++]
}
Воспользуемся свойствами flexbox для того, чтобы содержимое кнопки было выровнено по центру, также свойством которое отвечает за тип курсора при наведении.
.my-password-toggle {
border: none;
background: none;
position: absolute;
top: 0;
right: 0;
bottom: 0;
padding: 10px;
display: flex; // [!code ++]
align-items: center; // [!code ++]
justify-content: center; // [!code ++]
cursor: pointer; // [!code ++]
}
Иконку будем устанавливать с помощью псевдоэлемента ::after
и тут всё еще проще. Указываем объязательное свойство content
с пустым значением, т.к. без него элемент не будет отображаться. Определим размеры и т.к. мы планируем разместить иконки с помощью свойства background-image
, то мы заранее укажем общие свойства background-repeat
и background-size
.
.my-password-toggle::after {
content: '';
width: 20px;
height: 20px;
background-repeat: no-repeat;
background-size: contain;
}
И тут самый интересный момент, где сфокусирована вся логика нашей реализации.
.my-password input[type=password] + .my-password-toggle::after {
background-image: url('eye.svg');
}
.my-password input[type=text] + .my-password-toggle::after {
background-image: url('eye-off.svg');
}
Если вы вдруг не поняли, хотя это очень простой селектор, который позволяет браузеру самому изменять иконку в зависимости от типа поля, и нам останется с помощью JavaScript изменять тип поля.
Скрипт
Последний шаг - написать скрипт который реализует переключение типа поля. Определим переменную в которую поместим все наши элементы обёртки.
const passwords = document.querySelectorAll('.my-password');
Пройдемся по ним и определим переменную, в которой будем хранить поле, и сразу же проверим, существует ли оно вообще. Если нет, то прерываем работу функции.
const passwords = document.querySelectorAll('.my-password');
passwords.forEach((el) => {
const input = el.querySelector('input');
if (!(input instanceof HTMLInputElement)) {
return;
}
});
Теперь нужно получить кнопку и также поместить её в переменную.
const passwords = document.querySelectorAll('.my-password');
passwords.forEach((el) => {
const input = el.querySelector('input');
if (!(input instanceof HTMLInputElement)) {
return;
}
const toggleBtn = el.querySelector('.my-password-toggle');
});
Наконец, нам нужно повесить на событие нажатия кнопки функцию, которая будет переключать тип поля.
const passwords = document.querySelectorAll('.my-password');
passwords.forEach((el) => {
const input = el.querySelector('input');
if (!(input instanceof HTMLInputElement)) {
return;
}
const toggleBtn = el.querySelector('.my-password-toggle');
toggleBtn?.addEventListener('click', (e) => {
e.preventDefault();
input.type = input.type === 'text' ? 'password' : 'text';
});
});
Не бойтесь такой записи ?.
это всего-лишь оператор опциональной последовательности, которая избавляет от лишней проверки. А в остальном все просто, отменяем действие по умолчанию с помощью preventDefault()
и меняем тип поля, если тип text
, то на password
, иначе text
.
Заключение
Спасибо всем за внимание!
<div class="my-password">
<input type="password" name="password">
<button class="my-password-toggle"></button>
</div>
.my-password {
position: relative;
}
.my-password-toggle {
background: none;
border: none;
position: absolute;
top: 0;
right: 0;
bottom: 0;
padding: 10px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.my-password-toggle::after {
content: '';
width: 20px;
height: 20px;
background-repeat: no-repeat;
background-size: contain;
}
.my-password input[type=password] + .my-password-toggle::after {
background-image: url('eye.svg');
}
.my-password input[type=text] + .my-password-toggle::after {
background-image: url('eye-off.svg');
}
const passwords = document.querySelectorAll('.my-password');
passwords.forEach((el) => {
const input = el.querySelector('input');
if (!(input instanceof HTMLInputElement)) {
return;
}
const toggleBtn = el.querySelector('.my-password-toggle');
toggleBtn?.addEventListener('click', (e) => {
e.preventDefault();
input.type = input.type === 'text' ? 'password' : 'text';
});
});