2017年2月28日火曜日

innerHTMLを変更する時は描画ルールとタイミングを考慮しないとはみ出る

<input style="width:100%">なエレメントをinnerHTMLで作成する場合、inputの中身を書き換えるタイミングに注意しないとinputのwidthを100%にしているのに親要素の幅を無視してレイアウトを狂わせてしまう場合があります。

レイアウトが崩れる例と崩れない例のサンプルを作成しました。

以下ソース
<html>
<title>input</title>
<style type=text/css>
.max{width:100%;height:100%;}
button{float:left;}
</style>
<body style="overflow:hidden;">
<table class=max>
<tr height=1>
<td style="text-align:center">
<button id=btn0>はみ出る</button>
<button id=btn1>はみ出る</button>
<button id=btn2>はみ出る</button>
<button id=btn3>はみ出ない</button>
<button id=btn4>はみ出ない</button>
</td>
</tr>
<tr><td><div id=div class=max style="overflow:auto;border:solid 1px #000;"></div></td></tr>
</table>
</body>
<script>
resizeTo(100,300)
ce = function(name){return document.createElement(name)}
ins= function(elem){div.insertBefore(elem)}
btn0.onclick = function(){
var str = ''
for(i=0;i<100;i++){ str += i }
div.innerHTML = '<input value="'+str+'" style="width:100%">'
}
btn1.onclick = function(){
var str = ''
for(i=0;i<100;i++){ str += i }
div.innerHTML = '<input style="width:100%">'
div.firstChild.value = str
}
btn2.onclick = function(){
var str = ''
for(i=0;i<100;i++){ str += i }
div.innerHTML = '<input style="width:100%">'
;(function(){div.firstChild.value = str})()
}
btn3.onclick = function(){
var str = ''
for(i=0;i<100;i++){ str += i }
div.innerHTML = '<input style="width:100%">'
setTimeout(function(){div.firstChild.value = str},0)
}
btn4.onclick = function(){
var inp=ce('input'), str='', i
for(i=0;i<100;i++){ str += i }
inp.style.width = '100%'
inp.value = str
ins(inp)
}
</script>
</html>




実行画面

↑崩れない例

↓崩れた例


innerHTMLを書き換えたfunctionが終了した時点で変更が反映され、レイアウトが決まりますが、その時点でinputのvalueに文字列が入っているとinputはvalueの長さに応じて広げられてしまうようです。

それを回避するためには、レイアウトが決まるまではvalueはカラにしておき、setTimeoutによって時間差でvalueを代入するか、最初からinnerHTMLを使わずにcreateElementなどを使えば良いようです。

0 件のコメント:

コメントを投稿