보이지 않는 요소의 offsetWidth 값 문제

✒️ 2025-05-08 21:10 내용 수정


문제 상황

offsetWidth_problem 1.png

offsetWidth_problem 2.png

offsetWidth_problem 3.png

<!-- html -->
<div id="contents">
	<div class="content">
		<div class="thumbnail">
			<!-- 썸네일 -->
		</div>
		<div class="details">
			<div class="meta">
				<!-- 비디오 내용 -->
			</div>
			<div>
				<button class="menu-toggle-btn">버튼</button>
			</div>
		</div>
	</div>
	
	<div class="menu-list"></div>
</div>
/* css */
.menu-list { 
    visibility: hidden;
    display: block;
}

.menu-list.active {
    visibility: visible;
}
// javascript
function show_menu(card_video_id, video_menu_div) {
    // 비디오 카드 위치 정보 가져오기
    const card = document.querySelector(`.content[data-video-id="${card_video_id}"]`);
    const toggle_btn = card.querySelector(".menu-toggle-btn");
    const button_rect = toggle_btn.getBoundingClientRect();
    const contents_div = document.querySelector("#contents").getBoundingClientRect();
    const meta_box = card.querySelector(".meta").getBoundingClientRect();

    // contents의 문서 내 왼쪽 좌표
    const contents_div_left = contents_div.left;

    // 메뉴바 크기
    const menu_width = video_menu_div.offsetWidth;
    const menu_height = video_menu_div.offsetHeight;

    // 기준 위치 (스크롤 포함 절대좌표)
    let top = button_rect.top + window.scrollY - (58 + 12);
    let left = button_rect.left - contents_div_left;

    // 뷰포트 크기
    const viewport_width = window.innerWidth;
    const viewport_height = window.innerHeight;

    // 메뉴가 화면 오른쪽을 넘으면 왼쪽으로 보정
    if (left + menu_width + contents_div_left >= viewport_width) {
        left = (viewport_width - menu_width - 24 - contents_div_left);
    }
    
    // 메뉴가 화면 하단을 넘으면 위쪽으로 띄움
    if (top + menu_height >= viewport_height + window.scrollY) {
        top -= (menu_height + 60);
    }

    video_menu_div.style.position = 'absolute';
    // 버튼 하단에 현재 스크롤 위치까지 고려한 좌표로 메뉴 리스트 위치 설정
    video_menu_div.style.top = `${top}px`;
    video_menu_div.style.left = `${left}px`;
    video_menu_div.classList.add("active");
}

원인 분석 및 해결 방법

원인 분석

해결 방법

// 메뉴를 DOM에 추가
contents.appendChild(video_menu_div);

// 다음 이벤트 루프(렌더 후)에서 위치 설정
requestAnimationFrame(() => {
    show_menu(card.dataset.videoId, video_menu_div);
    video_menu_div.dataset.activeButton = button_video_id;
});
.menu-list { 
    visibility: hidden;
    /* 보이지 않더라도 미리 설정*/
    position: absolute;
    display: block;
}

.menu-list.active {
    visibility: visible;
}