テキストエリアをパスワードフィールドのように見せようとしています。Webkit ブラウザでは、以下の属性を見つけて作成しました
-webkit-text-security : circle
ただし、他のブラウザでは機能しません。これに対するクロスブラウザの代替手段はありますか...?
テキストエリアをパスワードフィールドのように見せようとしています。Webkit ブラウザでは、以下の属性を見つけて作成しました
-webkit-text-security : circle
ただし、他のブラウザでは機能しません。これに対するクロスブラウザの代替手段はありますか...?
これには JS を使用し、変数を定義してそこに textarea の値を格納し、textarea の内容を任意の特殊文字に置き換えることができます。フォームの送信や検証などに使用できるJS変数に実際の値があります。
このために、keydown
イベントの関数を作成できます。
次のような jQuery プラグインを使用できます: http://blog.decaf.de/2009/07/iphone-like-password-fields-using-jquery/
実行できますが、実装は簡単ではありません。アイデアは、非表示のpassword=true
入力要素をパスワードでマスクされたバージョンのテキストエリアの状態/プロキシとして使用し、JS を使用してパスワードでマスクされた (偽の) テキストエリアを表示/非表示の実際のテキストエリアに切り替えることです。
注意すべき点:同様の質問に関するintgrのコメントには、次のように記載されています。
残念ながら、これはすぐに醜くなります。通常のパスワード フィールドでは、途中での変更、コピー、カット、ペースト、ドラッグ アンド ドロップ、およびおそらく私が考えられなかった他の動作も許可されます。これらすべてを忠実にエミュレートすることは、たとえ可能であったとしても、おそらく苦労する価値はありません。
私の実装では、パスワードでマスクされた (偽の) テキスト領域でクリックまたは矢印キーを使用してテキスト ナビゲーションをプログラムで無効にすることにより、この複雑さを回避しています。ただし、実際のテキストエリアはその中でナビゲートおよび編集できるため、UX に関して失われることはほとんどありません。
以下の私の実装をチェックしてください:
// element handles
const inp = document.getElementById("input-el");
const fta = document.getElementById("fake-textarea-el");
const ftac = document.getElementById("fake-textarea-el-content");
const rta = document.getElementById("real-textarea-el");
const toggle = document.getElementById("pw-toggle");
// initial text element height
const initialHeightPx = fta.clientHeight + 'px';
// show/hide content flag
let hideContent = true;
// util for minimum textarea height workaround
function textWidth(text) {
const tag = document.createElement('div');
tag.classList.add('hidden');
tag.style.whiteSpace = 'nowrap';
tag.innerHTML = text;
document.body.appendChild(tag);
const result = tag.clientWidth;
document.body.removeChild(tag);
return result;
}
function setTextArea(content = '') {
// update all text elements
ftac.innerHTML = content.replace(/./g, '•');
inp.value = content;
rta.value = content;
// workaround to use CSS height for minimum
// textarea height
let newHeight = initialHeightPx;
if (textWidth(content) > rta.clientWidth) {
rta.style.height = 'auto';
newHeight = rta.scrollHeight + 'px';
}
rta.style.height = newHeight;
}
function handleInput(e) {
const {target: {value}} = e;
setTextArea(value);
}
inp.oninput = handleInput;
rta.oninput = handleInput;
fta.onfocus = e => {
inp.focus();
fta.classList.add('has-focus');
ftac.classList.remove('has-selectall');
}
inp.onblur = e => {
// deselect input contents
inp.selectionStart = inp.selectionEnd = -1;
fta.classList.remove('has-focus');
ftac.classList.remove('has-selectall');
}
inp.onkeydown = e => {
const {charCode, keyCode, target: {value}} = e;
const code = keyCode || charCode;
// prevent arrow keys
if (code >= 37 && code <= 40) {
e.preventDefault();
}
// handle ctrl/meta key combinations
if ((e.metaKey || e.ctrlKey)) {
switch (e.key) {
case 'a':
e.preventDefault();
inp.setSelectionRange(0, inp.value.length)
fta.classList.remove('has-focus');
ftac.classList.add('has-selectall');
break;
default:
}
} else if (ftac.classList.contains('has-selectall')) {
fta.classList.add('has-focus');
ftac.classList.remove('has-selectall');
}
}
// handle show/hide toggle
toggle.onclick = e => {
hideContent = !hideContent;
if (hideContent) {
rta.classList.add('hidden');
fta.classList.remove('hidden');
toggle.innerHTML = 'Show';
} else {
fta.classList.add('hidden');
rta.classList.remove('hidden');
toggle.innerHTML = 'Hide';
}
}
/* SETUP BEGIN */
* {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
main {
align-items: center;
display: flex;
height: 100vh;
justify-content: center;
}
button {
height: 24px;
margin: 18px;
width: 60px;
}
/* SETUP END */
#fake-textarea-el, #real-textarea-el {
border: none; /* remove user-agent textarea border */
box-shadow: 0 0 0 1px black;
box-sizing: border-box;
display: block;
height: 24px;
line-height: 18px;
margin: 0;
padding: 2px;
resize: none;
width: 150px;
word-wrap: break-word;
}
#fake-textarea-el {
height: auto;
min-height: 24px;
}
.hidden {
position: absolute;
bottom: 0px;
z-index: -1000;
opacity: 0;
pointer-events: none;
}
.has-selectall {
/* default selection bg on MacOS + Chrome */
background: #ACCEF7;
}
.cursor {
border-right: 1px solid transparent;
height: 1rem;
}
.has-focus .cursor {
animation: cursorBlink 1.14s forwards infinite;
}
@keyframes cursorBlink {
0% {
border-color: transparent;
}
50% {
border-color: transparent;
}
51% {
border-color: black;
}
100% {
border-color: black;
}
}
<main>
<input id="input-el" class="hidden" type="password" />
<div id="fake-textarea-el" contenteditable>
<span id="fake-textarea-el-content"></span><span class="cursor"></span>
</div>
<textarea id="real-textarea-el" class="hidden"></textarea>
<button id="pw-toggle">Show</button>
</main>