От автора: я недавно попросил дизайнера создать стиль для элемента ввода текста, похожий на панель поиска в TripAdvisor. Мне он очень понравился. И теперь я хочу поделиться готовым решением в виде пошагового руководства, чтобы вы могли создать его самостоятельно.
В данном случае для реализации стиля подсветка текста CSS недостаточно, поэтому мы будем использовать еще и JavaScript. Так что, я исхожу из того, что у вас есть базовые знания по SCSS и React. Вот полный код на CodePen:
Давайте создадим это!
Сначала мы создадим простой компонент React и перенесем его в DOM:

Практический курс по верстке адаптивного сайта с нуля!
Изучите курс и узнайте, как верстать современные сайты на HTML5 и CSS3
Узнать подробнее
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class App extends React.Component { render() { return ( <div className='input-wrapper'> <input placeholder='Search...' spellCheck={false} /> </div> ); } } ReactDOM.render( <App />, document.getElementById('root') ); |
Добавим к нему CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
$input-font-size: 30px; $input-line-height: 70px; $font-family: Roboto Slab, sans-serif; body { background-color: #222222; } .input-wrapper { width: 500px; margin: 50px auto; } input { height: 60px; width: 100%; min-width: 100%; padding: 0; border-radius: 0; line-height: $input-line-height; background-color: transparent; color: white; font-size: $input-font-size; border: none; outline: none; border-bottom: 3px solid #333333; font-family: $font-family; } |
Добавим HTML-контейнер для ReactDOM, чтобы отобразить его:
1 |
<div id="root"></div> |
В результате мы получим базовый элемент ввода с нижней границей.
Теперь давайте оживим границу!
Трудность с реализацией подсветки заключается в том, что она должна изменять границу на уровне с вводимым текстом. Она также должна работать с любыми font-family и font-size.
Поскольку ширина элемента ввода фиксирована, нам нужен другой прием, чтобы определить, где заканчивается текст в любой конкретный момент времени.
Предположим, мы можем использовать второй элемент с динамической шириной — в нашем примере это будет элемент span с классом input-highlight. Затем мы скопируем вводимый текст и поместим его внутри span. Я задал контролируемый ввод текста, предоставив свойство value. Теперь наш компонент React выглядит следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class App extends React.Component { render() { return ( <div className='input-wrapper'> <input placeholder='Search...' spellCheck={false} value='basic input, bottom border' /> <span className='input-highlight'> basic input, bottom border </span> </div> ); } } |
Добавьте следующие правила CSS для input-highlight. Примечание: здесь мы используем переменные SCSS, чтобы свойство font имело одинаковые значения для input и для span:

Практический курс по верстке адаптивного сайта с нуля!
Изучите курс и узнайте, как верстать современные сайты на HTML5 и CSS3
Узнать подробнее
1 2 3 4 5 6 |
.input-highlight { font-size: $input-font-size; line-height: $input-line-height; font-family: $font-family; max-width: 100%; } |
И мы получим следующее:
Затем добавим верхнюю границу для span и расположим ее так, чтобы эта граница накладывалась на нижнюю границу input. Кроме того, поскольку для input-highlight теперь задано position: absolute, для родительского элемента нам нужно задать правило position: relative.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
.input-highlight { font-size: $input-font-size; line-height: $input-line-height; font-family: $font-family; max-width: 100%; border-top: 3px solid white; position: absolute; left: 0; bottom: 0; height: 0; } .input-wrapper { width: 500px; margin: 50px auto; position: relative; } |
Элемент span заканчивается там, где заканчивается текст. Это делает его идеальной мерой длины вводимого текста! Теперь, легкая часть: давайте используем JavaScript для обновления текста в элементе span при каждом изменении вводимого содержимого. Мы будем использовать state React, чтобы одновременно обновлять значение как input, так и span. Вот наш обновленный компонент:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
class App extends React.Component { constructor() { super(); this.state = { inputValue: '' }; this.onInputChange = this.onInputChange.bind(this); } onInputChange(e) { const { value } = e.target; this.setState({ inputValue: value }); } render() { const { inputValue } = this.state; return ( <div className='input-wrapper'> <input onChange={this.onInputChange} placeholder='Search...' value={inputValue} spellCheck={false} /> <span className='input-highlight'> { inputValue.replace(/ /g, "\u00a0") } </span> </div> ); } } |
Часть .replace(/ /g, «\u00a0») необходима для того, чтобы React правильно обрабатывал пробелы. Затем мы скроем span, добавив следующие строки в селектор CSS input-highlight:
1 2 3 |
color: transparent; user-select: none; overflow: hidden; |
Нам нужно overflow: hidden для span, чтобы ограничить высоту контейнера (иначе это приведет к растяжению контейнера по горизонтали — спасибо Prasanna и Andrea за то, что они указали это в комментариях!)
Подводя черту
Все уже работает довольно хорошо. Последнее штрих — мы добавим для подсветки другой onFocus цвет. Чтобы достичь этого, нам нужен способ задать для span стиль, который применяется, когда input выделен фокусом ввода. input и span — это элементы одного уровня, поэтому мы будем использовать селектор CSS +. Вот полный код для селектора input, включая селектор + для input-highlight:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
input { height: 60px; width: 100%; min-width: 100%; padding: 0; border-radius: 0; line-height: $input-line-height; background-color: transparent; color: white; font-size: $input-font-size; border: none; outline: none; border-bottom: 3px solid #333333; font-family: $font-family; &:focus { + .input-highlight { border-top: 3px solid #fbc91b; } } } |
Благодарю за внимание! Если вам понравился этот пост, поделитесь ссылкой со своими друзьями.
Автор: Petr Gazarov
Источник: //medium.freecodecamp.org/
Редакция: Команда webformyself.

Практический курс по верстке адаптивного сайта с нуля!
Изучите курс и узнайте, как верстать современные сайты на HTML5 и CSS3
Узнать подробнее