๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

์ผ/javascript

๋ชจ๋‹ฌ ํŒ์—… ๋‚ด ๋™์  ํ…Œ์ด๋ธ” UI ์ •๋ ฌ ๋ฌธ์ œ ํ•ด๊ฒฐ

๐Ÿ“Œ ๋ชจ๋‹ฌ ํŒ์—… ๋‚ด ๋™์  ํ…Œ์ด๋ธ” UI ์ •๋ ฌ ๋ฌธ์ œ ํ•ด๊ฒฐ

1. ๋ฌธ์ œ ์ƒํ™ฉ (Problem)

  • ๋ชจ๋‹ฌ ํŒ์—… ๋‚ด๋ถ€์—์„œ div ๊ธฐ๋ฐ˜ ํ…Œ์ด๋ธ” UI ๊ตฌํ˜„
  • .div_th (ํ—ค๋” ์˜์—ญ) ๋†’์ด๊ฐ€ ์„œ๋กœ ๋‹ฌ๋ผ UI๊ฐ€ ๊นจ์ง
  • .div_td ๋‚ด์šฉ ๊ธธ์ด์— ๋”ฐ๋ผ ์ค„๋ฐ”๊ฟˆ์ด ๋น„์ •์ƒ์ ์œผ๋กœ ๋™์ž‘
 
<div class="row multi">
    <div class="cell_div">
    	<div class="div_th">์ด๋ฆ„</div>
    	<div class="div_td"></div>
    </div>
    <div class="cell_div">
    	<div class="div_th">์ข…๋ฅ˜</div>
    	<div class="div_td"></div>
    </div>
</div>

2. ์›์ธ ๋ถ„์„ (Root Cause)

๐Ÿ”น 1) ๋†’์ด ๋ถˆ์ผ์น˜

  • ๊ฐ .div_th๋Š” ์ฝ˜ํ…์ธ  ๊ธธ์ด์— ๋”ฐ๋ผ height๊ฐ€ ์ž๋™ ๊ฒฐ์ •๋จ
  • ๋™์ผ row ๋‚ด์—์„œ๋„ ๋†’์ด๊ฐ€ ๋‹ค๋ฅด๊ฒŒ ๋ Œ๋”๋ง๋จ

๐Ÿ”น 2) ๋†’์ด ์ธก์ • ์‹คํŒจ (0 ๋ฌธ์ œ)

  • ํŒ์—…์ด display: none ์ƒํƒœ์—์„œ ์‹คํ–‰
  • offsetHeight = 0 ๋ฐœ์ƒ

๐Ÿ”น 3) ์ค„๋ฐ”๊ฟˆ ๋ฌธ์ œ

  • ๊ธด ํ…์ŠคํŠธ ๋˜๋Š” ๊ณต๋ฐฑ ์—†๋Š” ๋ฌธ์ž์—ด → overflow ๋ฐœ์ƒ
  • ๊ธฐ๋ณธ CSS๋กœ๋Š” ๊ฐ•์ œ ์ค„๋ฐ”๊ฟˆ์ด ์ œํ•œ๋จ

3. ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• (Solution)

โœ… 3-1. ํŒ์—… ๋ Œ๋”๋ง ์ดํ›„ ๋†’์ด ๋™๊ธฐํ™”

  • Ajax → ๋ฐ์ดํ„ฐ ์‚ฝ์ž… → ํŒ์—… open ์ดํ›„ ์‹คํ–‰
  • setTimeout์œผ๋กœ ๋ Œ๋”๋ง ํƒ€์ด๋ฐ ํ™•๋ณด
 
var searchSuc = function(data){
    if(data.result == "SUCCESS"){
        detailDataInser(data.detail);
        fn_open_popup('detail_popup');

        setTimeout(function() {
            var rows = document.querySelectorAll('.row.multi');

            for (var i = 0; i < rows.length; i++) {
                var ths = rows[i].querySelectorAll('.cell_div .div_th');

                if (ths.length === 2) {
                    // ์ดˆ๊ธฐํ™”
                    for (var j = 0; j < ths.length; j++) {
                        ths[j].style.height = 'auto';
                    }

                    // ๋†’์ด ๋น„๊ต
                    var h1 = ths[0].offsetHeight;
                    var h2 = ths[1].offsetHeight;
                    var max = (h1 > h2) ? h1 : h2;

                    // ์ ์šฉ
                    for (var j = 0; j < ths.length; j++) {
                        ths[j].style.height = max + 'px';
                    }
                }
            }
        }, 50);
    }
};
 

โœ… 3-2. ์ธ์ ‘ ์š”์†Œ๋ผ๋ฆฌ๋งŒ ๋†’์ด ๋น„๊ต

  • ์ „์ฒด๊ฐ€ ์•„๋‹ˆ๋ผ ๊ฐ™์€ row ๋‚ด 2๊ฐœ ์š”์†Œ๋งŒ ๋น„๊ต
  • UI ์ž์—ฐ์Šค๋Ÿฌ์›€ ์œ ์ง€

โœ… 3-3. ํ…์ŠคํŠธ ์ค„๋ฐ”๊ฟˆ ์ฒ˜๋ฆฌ

.div_td {
	white-space: normal;
	word-break: break-word;
}

4. ํ•ต์‹ฌ ๊ฐœ๋… ์ •๋ฆฌ (Key Insights)

๐Ÿ”น DOM ๋ Œ๋”๋ง ํƒ€์ด๋ฐ

  • display: none ์ƒํƒœ → offsetHeight = 0
  • ํ•ด๊ฒฐ: ๋ Œ๋”๋ง ์ดํ›„ ์‹คํ–‰ (setTimeout, requestAnimationFrame)

๐Ÿ”น ๋†’์ด ๊ณ„์‚ฐ ๋ฐฉ์‹

์†์„ฑํŠน์ง•
offsetHeight padding + border ํฌํ•จ (์ผ๋ฐ˜์  ์‚ฌ์šฉ)
clientHeight border ์ œ์™ธ
getBoundingClientRect() ๊ฐ€์žฅ ์ •ํ™• (์†Œ์ˆ˜ ํฌํ•จ)

๐Ÿ”น ์ค„๋ฐ”๊ฟˆ ์ „๋žต

์†์„ฑํŠน์ง•
break-word ์ผ๋ฐ˜์ ์ธ ์ค„๋ฐ”๊ฟˆ (๊ถŒ์žฅ)
break-all ๊ฐ•์ œ ์ค„๋ฐ”๊ฟˆ (๊ฐ€๋…์„ฑ ๋‚ฎ์Œ)
keep-all ํ•œ๊ธ€ ๋‹จ์–ด ์œ ์ง€ (์ค„๋ฐ”๊ฟˆ ์–ต์ œ)

5. ๊ฐœ์„  ํšจ๊ณผ (Result)

  • โœ… UI ์ •๋ ฌ ์ผ๊ด€์„ฑ ํ™•๋ณด
  • โœ… ๋‹ค์–‘ํ•œ ๋ฐ์ดํ„ฐ ๊ธธ์ด ๋Œ€์‘ ๊ฐ€๋Šฅ
  • โœ… ๋ชจ๋‹ฌ ๊ธฐ๋ฐ˜ ๋™์  ๋ Œ๋”๋ง ์•ˆ์ •์„ฑ ํ™•๋ณด
  • โœ… ์‚ฌ์šฉ์ž ๊ฐ€๋…์„ฑ ๊ฐœ์„ 

6. ํ•œ ์ค„ ์š”์•ฝ (Resume Point)

๋ชจ๋‹ฌ ํŒ์—… ๋‚ด ๋™์  ๋ฐ์ดํ„ฐ ๋ Œ๋”๋ง ์‹œ ๋ฐœ์ƒํ•˜๋Š” UI ์ •๋ ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด, ๋ Œ๋”๋ง ํƒ€์ด๋ฐ ์ œ์–ด์™€ DOM ๋†’์ด ๋™๊ธฐํ™” ๋กœ์ง์„ ๊ตฌํ˜„ํ•˜์—ฌ ์ผ๊ด€๋œ ๋ ˆ์ด์•„์›ƒ๊ณผ ๊ฐ€๋…์„ฑ์„ ํ™•๋ณดํ•จ.