Добавьте текстовый суффикс к ‹input type=number›

В настоящее время у меня есть несколько таких входов:

<input type="number" id="milliseconds">

Это поле ввода используется для представления значения в миллисекундах. Однако у меня есть несколько числовых входов, которые принимают значение в дБ или процентах.

<input type="number" id="decibel">
<input type="number" id="percentages">

Что я хотел бы сделать, так это добавить суффикс типа в поле ввода, чтобы пользователи знали, какое значение представляет ввод. Что-то вроде этого:

введите описание изображения здесь

(Это изображение отредактировано, чтобы показать, какой результат я хочу получить, я также скрыл стрелки вверх и вниз из типа ввода).

Я пытался найти это в Google, но, похоже, ничего об этом не нашел. Кто-нибудь знает, возможно ли это, и как вы можете сделать что-то подобное?


person R. De Caluwe    schedule 12.04.2018    source источник
comment
размещение блока рядом с вводом (как текстовый узел) не вариант?   -  person Fabrizio Calderan    schedule 12.04.2018
comment
Попробуйте placeholder w3schools.com/tags/att_input_placeholder.asp   -  person Adam    schedule 12.04.2018
comment
Это было бы возможно, но мне пришлось бы перепроектировать некоторые части моего пользовательского интерфейса, которых я хотел бы избежать, насколько это возможно :). Но если сделать что-то подобное невозможно, у меня не было бы другого выбора.   -  person R. De Caluwe    schedule 12.04.2018
comment
@Adam Адам, я посмотрел на это, и хотя он показывает текст, когда значение пусто, мне все равно понадобится этот суффикс после изменения значения, которого заполнитель не делает. Спасибо за ваше предложение!   -  person R. De Caluwe    schedule 12.04.2018
comment
Поскольку у вас есть идентификатор, специфичный для каждого типа единиц, существует гораздо больше шансов, что функция Javascript поможет. Я думаю, вы могли бы использовать js-функцию number_format с добавлением 5-го параметра. Если вы не хотите использовать Javascript, подойдет ли вам функция PHP?   -  person fictimaph    schedule 12.04.2018
comment
@fictimaph Спасибо за ваше предложение! Я использую Javascript в своем приложении для извлечения значений и других типов данных из моих полей ввода. Несмотря на то, что ваше предложение хорошее, я хотел бы только знать, могу ли я добавить суффикс в поле ввода числа. Ваше предложение сделало бы мое приложение слишком сложным для такой «базовой» функции. Я бы лучше немного переделал свой пользовательский интерфейс :) Все равно спасибо!   -  person R. De Caluwe    schedule 12.04.2018
comment
Пожалуйста ! Функция Javascript, заменяющая каждый ввод числа, учитывая, что идентификатор был возможен, вызывая его после загрузки страницы. Затем его можно использовать для отображения данных и входных данных. Но на самом деле решение CSS просто идеально.   -  person fictimaph    schedule 12.04.2018


Ответы (5)


Вы можете использовать оболочку <div> для каждого элемента ввода и позиционировать модуль как псевдоэлемент ::after на content соответствующих единиц.

Этот подход хорошо работает, поскольку псевдоэлементы с абсолютным позиционированием не влияют на существующие макеты. Тем не менее, недостатком этого подхода является то, что вы должны убедиться, что пользовательский ввод не такой длинный, как текстовое поле, иначе блок будет неприятно показан выше. Для фиксированной длины пользовательского ввода это должно работать нормально.

/* prepare wrapper element */
div {
  display: inline-block;
  position: relative;
}

/* position the unit to the right of the wrapper */
div::after {
  position: absolute;
  top: 2px;
  right: .5em;
  transition: all .05s ease-in-out;
}

/* move unit more to the left on hover or focus within
   for arrow buttons will appear to the right of number inputs */
div:hover::after,
div:focus-within::after {
  right: 1.5em;
}

/* handle Firefox (arrows always shown) */
@supports (-moz-appearance:none) {
  div::after {
    right: 1.5em;
  }
}

/* set the unit abbreviation for each unit class */
.ms::after {
  content: 'ms';
}
.db::after {
  content: 'db';
}
.percent::after {
  content: '%';
}
<div class="ms">
  <input type="number" id="milliseconds" />
</div>
<hr />
<div class="db">
  <input type="number" id="decibel" />
</div>
<hr />
<div class="percent">
  <input type="number" id="percentages">
</div>

Если вы хотите поддерживать браузеры, в которых эти стрелки вообще не отображаются, используйте @supports или медиазапросы .

person andreas    schedule 12.04.2018
comment
Ого, я на самом деле никогда не думал об использовании решения CSS для этого, хотя я только что понял, что использовал тег CSS в своем вопросе :) Но ваше решение отлично сработает для этой проблемы, поскольку пользовательский ввод никогда не превысит заданное количество символов. (максимум 2 или 3). Большое спасибо за ваше предложение, отметим это как ответ! :) - person R. De Caluwe; 12.04.2018
comment
Что ж, я рад, что смог помочь! - person andreas; 12.04.2018
comment
В CSS есть опция content, это здорово, не знал! - person fictimaph; 12.04.2018
comment
Добавлена ​​ссылка на MDN для псевдоэлемента ::after. Для этих элементов вы можете использовать правило content. - person andreas; 12.04.2018
comment
Вы можете использовать заполнение, чтобы текст ввода не перекрывался с меткой суффикса. Или вы можете использовать контейнер в стиле поля ввода (с рамкой и т. д.) и элемент ввода внутри него без рамок. - person Slava Fomin II; 30.10.2018
comment
Вместо использования только :hover::after также добавьте :focus-within::after - person N7D; 03.12.2019
comment
@ N7d Спасибо за это дополнение! Я обновил свой ответ соответственно. - person andreas; 03.12.2019
comment
Это прекрасно работает в Chrome и Edge на настольных компьютерах, но: 1. Firefox на настольных компьютерах всегда показывает кнопки вверх и вниз, даже если ввод не выбран, поэтому вам следует добавить @supports ( -moz-appearance:none ){div::after {right: 1.5em;}} (@supports ( -moz-appearance:none ) обнаруживает Firefox) и 2. Мобильные браузеры вообще не отображают кнопки вверх и вниз, поэтому div:hover::after, div:focus-within::after следует окружить @media(min-device-width:481px). - person Donald Duck; 03.07.2020
comment
Спасибо @DonaldDuck за это ценное дополнение, я соответственно обновил свой ответ. - person andreas; 05.07.2020

Другим интересным подходом было бы использование небольшого количества JavaScript для того, чтобы суффикс действительно прикреплялся к входному тексту (что, вероятно, выглядит лучше):

const inputElement = document.getElementById('my-input');
const suffixElement = document.getElementById('my-suffix');


inputElement.addEventListener('input', updateSuffix);

updateSuffix();

function updateSuffix() {
  const width = getTextWidth(inputElement.value, '12px arial');
  suffixElement.style.left = width + 'px';
}


/**
 * Uses canvas.measureText to compute and return the width of the given text of given font in pixels.
 * 
 * @param {String} text The text to be rendered.
 * @param {String} font The css font descriptor that text is to be rendered with (e.g. "bold 14px verdana").
 * 
 * @see https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393
 */
function getTextWidth(text, font) {
    // re-use canvas object for better performance
    var canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas"));
    var context = canvas.getContext("2d");
    context.font = font;
    var metrics = context.measureText(text);
    return metrics.width;
}
#my-input-container {
  display: inline-block;
  position: relative;
  font: 12px arial;
}

#my-input {
  font: inherit;
}

#my-suffix {
  position: absolute;
  left: 0;
  top: 3px;
  color: #555;
  padding-left: 5px;
  font: inherit;
}
<div id="my-input-container">
  <input type="number" id="my-input" value="1500">
  <span id="my-suffix">ms.</span>
</div>

Однако это всего лишь доказательство концепции. Вам нужно будет немного поработать над этим, чтобы сделать его готовым к производству, например. сделать его многоразовым плагином.

Кроме того, вам нужно будет обработать случай, когда элемент ввода переполняется.

person Slava Fomin II    schedule 30.10.2018
comment
Мне нравится этот. Потому что это позволяет легко обновлять суффикс. - person MrHIDEn; 30.03.2020

Если у вас есть возможность добавлять элементы для ввода, вы можете попробовать следующее:

.container {
  max-width: 208px;    /*adjust it*/
  margin: auto;
  position: relative;
  display: inline-block;
}

#milliseconds {
  padding-right: 35px;
}

.ms {
  position: absolute;
  top: 0;
  right: 10px;
}
<div class="container">
  <input type="text" id="milliseconds">
  <span class="ms">ms</span>
</div>

person Akanksha Sharma    schedule 12.04.2018

У меня есть случай, когда команда дизайнеров хочет, чтобы суффикс плавал вместе со значениями. Мы используем собственный шрифт с очень неравномерной шириной чисел. У меня возникла идея использовать призрак, чтобы следить за шириной ввода и фиксировать переполнение с помощью max-width с помощью элемента-обертки. Это все еще немного в процессе работы и глючит (без начальной заливки и т. д.).

const fillBuffer = (e) => {
  // Clear the buffer if input gets wiped
  if (e.target.value.length === 0) {
    e.target.parentElement.querySelector('.suffix span').textContent = "";
    return;
  }

  // Using a filler char will prevent the suffix to be overwritten with the input
  const extraFiller = e.target.value.length ? '1' : '';

  e.target.parentElement.querySelector('.suffix span').textContent = e.target.value + extraFiller;
}

// Attach the listeners
document.querySelectorAll('input').forEach((el) => {
  el.addEventListener('keydown', fillBuffer);
  el.addEventListener('keyup', fillBuffer);
});
* {
  font-size: 1em;
  font-family: Papyrus, sans-serif;
  box-sizing: border-box;
}

body {
  padding: 1em;
}

.input-wrapper {
  margin-bottom: 0.5em;
}

.input-wrapper.with-suffix {
  position: relative;
  max-width: 150px;
  overflow: hidden;
}

.input-wrapper.with-suffix input {
  margin: 0;
  width: 100%;
  outline: 0;
  padding-left: 4px;
  padding-right: 16px;
}

.input-wrapper.with-suffix .suffix {
  position: absolute;
  padding-left: 6px;
  top: 2px;
  pointer-events: none;
  width: 100%;
}

.input-wrapper.with-suffix .suffix span {
  user-select: none;
  pointer-events: none;
}

.input-wrapper.with-suffix .suffix .filler {
  display: inline-block;
  white-space: pre; /* Allow more than two whitespaces to be rendered */
  color: rgba(0, 0, 0, 0.0);
  background: rgba(255, 0, 0, 0.3);
  max-width: calc(100% - 16px);
}
<div class="input-wrapper with-suffix">
  <input type="text" value="5000">
  <div class="suffix"><span class="filler">5000</span><span>€</span></div>
</div>
  
  
<div class="input-wrapper with-suffix">
  <input type="text" value="5000">
  <div class="suffix"><span class="filler">5000</span><span>€</span></div>
</div>

person sampoh    schedule 05.02.2021
comment
Это тоже неплохо выглядит! Однако не будет ли проще использовать прослушиватель событий onchange? Это может уменьшить количество ошибок в целом, поскольку ожидание ключевых событий может отличаться от пользователя к пользователю (или от клавиатуры к клавиатуре)? - person R. De Caluwe; 25.06.2021

Если возможно, используйте ANT Design, у них есть API, поэтому нам нужно только написать addOnBefore и addOnAfter.

https://ant.design/components/input/

person meet mehta    schedule 08.09.2020