【问题标题】:Add a text suffix to <input type="number">为 <input type="number"> 添加文本后缀
【发布时间】:2018-09-22 15:06:11
【问题描述】:

我目前有很多这样的输入:

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

此输入字段用于表示以毫秒为单位的值。 但是,我确实有多个数字输入,它们以 dB 或百分比为单位。

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

我想做的是在输入字段中添加一个类型后缀,让用户知道输入代表什么类型的值。像这样的:

(此图像经过编辑以显示我想要的结果,我也隐藏了输入类型中的向上和向下箭头)。

我已尝试用 Google 搜索,但似乎找不到任何相关信息。有谁知道这是否可能,以及如何完成这样的事情?

【问题讨论】:

  • 将单元放在输入旁边(作为文本节点)不是一种选择?
  • 这是可能的,但我必须重新设计我希望尽可能避免的 UI 的某些部分 :)。但如果不可能做这样的事情,我别无选择。
  • @Adam 我看了这个,即使它在值为空时显示文本,但在更改占位符不做的值后,我仍然需要该后缀。不过感谢您的建议!
  • 由于您对每种单位都有特定的 id,因此 Javascript 函数可以解决问题的可能性更大。我认为您可以使用 number_format js function 并添加第 5 个参数“单位”。如果您不想使用 Javascript,那么 PHP 函数是否适合您?

标签: css html input suffix


【解决方案1】:

您可以为每个输入元素使用包装器&lt;div&gt;,并将单元定位为伪元素::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>

如果您想支持完全不显示这些箭头的浏览器,请使用@supportsmedia queries

【讨论】:

  • 哦,哇,我实际上从未想过为此使用 CSS 解决方案,尽管我刚刚意识到我在我的问题中使用了 CSS 标签 :) 但是您的解决方案非常适合这个问题,因为用户输入永远不会超过前缀数量的字符(最多 2 或 3 个)。非常感谢您的建议,将其标记为答案! :)
  • 我很高兴能帮上忙!
  • CSS中有content选项,太好了,不知道!
  • 不仅使用:hover::after,还添加:focus-within::after
  • 这在桌面计算机上的 Chrome 和 Edge 中效果很好,但是: 1. 桌面计算机上的 Firefox 总是显示向上和向下按钮,即使没有选择输入,所以你应该添加 @supports ( -moz-appearance:none ){div::after {right: 1.5em;}} (@supports ( -moz-appearance:none ) detects Firefox),以及 2. 移动浏览器根本不会显示向上和向下按钮,所以你应该用 @media(min-device-width:481px) 包围 div:hover::after, div:focus-within::after
【解决方案2】:

另一种有趣的方法是使用一点 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>

但是,这只是概念验证。您将需要进一步处理它以使其可以投入生产,例如让它成为一个可重用的插件。

此外,您还需要处理输入元素溢出的情况。

【讨论】:

  • 我喜欢这个。因为它允许轻松更新后缀。
【解决方案3】:

如果您可以选择在输入中添加元素,那么您可以试试这个:

.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>

【讨论】:

    【解决方案4】:

    我有一个案例,设计团队希望后缀随值浮动。我们正在使用数字宽度非常不均匀的自定义字体。我想出了一个想法,即使用一个幽灵来跟踪输入宽度,并使用包装器元素用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>

    【讨论】:

    • 这看起来也不错!但是,使用 onchange 事件监听器不是更容易吗?这可能会减少整体错误,因为等待键事件可能因用户(或键盘到键盘)而异?
    猜你喜欢
    • 2014-02-08
    • 2016-05-09
    • 2012-10-09
    • 2016-05-24
    • 1970-01-01
    • 2016-02-11
    • 1970-01-01
    • 2020-02-16
    • 1970-01-01
    相关资源
    最近更新 更多