admin管理员组文章数量:1208153
I'm trying to build a nested accordion structure where each accordion, when clicked, updates both its own and its parent's maxHeight dynamically. However, whenever I open a child accordion, the parent's height is sometimes computed incorrectly. I expect it to be around 288px, for example, but it ends up at 160px, or part of the content is cut off.
Below is a simplified version of my click handler. When a .aside-accordion button is clicked, I set the child accordion's maxHeight, then use a while loop to update any parent .accordion-content elements:
document.addEventListener('click', function(event) {
if (event.target.matches('.aside-accordion')) {
const button = event.target;
const accordionMenu = button.nextElementSibling;
const buttonArrow = button.querySelector('.arrow');
button.classList.toggle('active');
if (button.classList.contains('active')) {
buttonArrow.classList.add('rotate-180');
accordionMenu.style.maxHeight = accordionMenu.scrollHeight + 'px';
} else {
buttonArrow.classList.remove('rotate-180');
accordionMenu.style.maxHeight = 0;
}
let parentContent = accordionMenu.parentElement.closest('.accordion-content');
while (parentContent) {
const parentButton = parentContent.previousElementSibling;
if (parentButton && parentButton.classList.contains('active')) {
// Here I'm assigning the parent's actual height
parentContent.style.maxHeight = parentContent.scrollHeight + 'px';
}
parentContent = parentContent.parentElement.closest('.accordion-content');
}
}
});
Live demo
Expectation: When the child accordion opens, all parent accordions should automatically expand to accommodate the child’s height, so the content is fully visible.
Issue: Sometimes the parent's maxHeight ends up smaller than expected or partially hides the content, requiring a second click to fix it. I'm using transition: max-height 0.3s ease; overflow: hidden; on all accordions.
I've tried using a large hard-coded value (e.g., 999999px) instead of scrollHeight and it “fixes” the issue, but that's obviously not a clean solution. requestAnimationFrame or small setTimeout calls sometimes help, but still produce inconsistent results. I also tested transitionend, but sometimes the content “jumps” on the initial open.
Question: How can I reliably update the parent maxHeight in a nested accordion so that the first click always shows the correct expanded height (without glitches or having to click again)?
I'm trying to build a nested accordion structure where each accordion, when clicked, updates both its own and its parent's maxHeight dynamically. However, whenever I open a child accordion, the parent's height is sometimes computed incorrectly. I expect it to be around 288px, for example, but it ends up at 160px, or part of the content is cut off.
Below is a simplified version of my click handler. When a .aside-accordion button is clicked, I set the child accordion's maxHeight, then use a while loop to update any parent .accordion-content elements:
document.addEventListener('click', function(event) {
if (event.target.matches('.aside-accordion')) {
const button = event.target;
const accordionMenu = button.nextElementSibling;
const buttonArrow = button.querySelector('.arrow');
button.classList.toggle('active');
if (button.classList.contains('active')) {
buttonArrow.classList.add('rotate-180');
accordionMenu.style.maxHeight = accordionMenu.scrollHeight + 'px';
} else {
buttonArrow.classList.remove('rotate-180');
accordionMenu.style.maxHeight = 0;
}
let parentContent = accordionMenu.parentElement.closest('.accordion-content');
while (parentContent) {
const parentButton = parentContent.previousElementSibling;
if (parentButton && parentButton.classList.contains('active')) {
// Here I'm assigning the parent's actual height
parentContent.style.maxHeight = parentContent.scrollHeight + 'px';
}
parentContent = parentContent.parentElement.closest('.accordion-content');
}
}
});
Live demo
Expectation: When the child accordion opens, all parent accordions should automatically expand to accommodate the child’s height, so the content is fully visible.
Issue: Sometimes the parent's maxHeight ends up smaller than expected or partially hides the content, requiring a second click to fix it. I'm using transition: max-height 0.3s ease; overflow: hidden; on all accordions.
I've tried using a large hard-coded value (e.g., 999999px) instead of scrollHeight and it “fixes” the issue, but that's obviously not a clean solution. requestAnimationFrame or small setTimeout calls sometimes help, but still produce inconsistent results. I also tested transitionend, but sometimes the content “jumps” on the initial open.
Question: How can I reliably update the parent maxHeight in a nested accordion so that the first click always shows the correct expanded height (without glitches or having to click again)?
Share Improve this question edited Jan 20 at 20:16 achilles asked Jan 20 at 19:55 achillesachilles 133 bronze badges 3 |2 Answers
Reset to default 0You don't need to manualy change the height every time.
Just set height: auto;
for the active
class in your CSS.
let toggles = document.querySelectorAll('.nav-list');
toggles.forEach(toggle => {
let header = toggle.querySelector('.nav-list > .nav-header');
header.onclick = () => {
toggle.classList.toggle('open');
};
});
*{
box-sizing: border-box;
font-family: 'Helvetica'
}
body{
background-color: #010111;
}
nav{
color: white;
}
.nav-header{
letter-spacing: 0.07rem;
padding-left: .5em
}
.nav-container{
padding-left: 1em;
height: 0;
overflow: hidden;
}
.nav-list.open > .nav-container{
height: auto;
}
.nav-list > .nav-header::after{
content: "\005e";
display: inline-block;
position: relative;
bottom: -.6ex;
right: -.5em;
font-weight: 600;
color: #ddd;
}
.nav-list.open > .nav-header::after{
transform: rotate(180deg);
bottom: .25ex;
}
.nav-item .nav-header{
font-weight: 100;
}
<nav>
<section class="nav-list">
<h5 class="nav-header">Cathegory</h5>
<div class="nav-container">
<section class="nav-item">
<h5 class="nav-header">Item</h5>
</section>
<section class="nav-item">
<h5 class="nav-header">Item</h5>
</section>
<section class="nav-item">
<h5 class="nav-header">Item</h5>
</section>
<section class="nav-list">
<h5 class="nav-header">Sub-Cathegory</h5>
<div class="nav-container">
<section class="nav-item">
<h5 class="nav-header">Item</h5>
</section>
<section class="nav-item">
<h5 class="nav-header">Item</h5>
</section>
</div>
</section>
</div>
</section>
<section class="nav-list">
<h5 class="nav-header">Cathegory</h5>
<div class="nav-container">
<section class="nav-item">
<h5 class="nav-header">Item</h5>
</section>
<section class="nav-item">
<h5 class="nav-header">Item</h5>
</section>
<section class="nav-item">
<h5 class="nav-header">Item</h5>
</section>
<section class="nav-list">
<h5 class="nav-header">Sub-Cathegory</h5>
<div class="nav-container">
<section class="nav-item">
<h5 class="nav-header">Item</h5>
</section>
<section class="nav-item">
<h5 class="nav-header">Item</h5>
</section>
</div>
</section>
</div>
</section>
</nav>
The issue with your implementation likely stems from the fact that setting maxHeight based on scrollHeight can be tricky in nested accordion structures, as the browser may not have fully recalculated the layout before updating the parent elements. Here's a reliable approach to fix the problem:
Key Considerations: Recalculate Heights After DOM Updates When opening a child accordion, the parent's scrollHeight may not yet include the child's new height. You need to wait for the browser to finish recalculating the layout before updating the parent's maxHeight.
Avoid Conflicts With Transitions If transition: max-height is applied while dynamically updating maxHeight, it can cause glitches or jumps. To prevent this, disable the transition temporarily during height recalculations.
The issue with your implementation likely stems from the fact that setting maxHeight based on scrollHeight can be tricky in nested accordion structures, as the browser may not have fully recalculated the layout before updating the parent elements. Here's a reliable approach to fix the problem:
Key Considerations: Recalculate Heights After DOM Updates When opening a child accordion, the parent's scrollHeight may not yet include the child's new height. You need to wait for the browser to finish recalculating the layout before updating the parent's maxHeight.
Avoid Conflicts With Transitions If transition: max-height is applied while dynamically updating maxHeight, it can cause glitches or jumps. To prevent this, disable the transition temporarily during height recalculations.
Solution: Below is the updated implementation, addressing the issues:
document.addEventListener('click', function (event) {
if (event.target.matches('.aside-accordion')) {
const button = event.target;
const accordionMenu = button.nextElementSibling;
const buttonArrow = button.querySelector('.arrow');
button.classList.toggle('active');
if (button.classList.contains('active')) {
buttonArrow.classList.add('rotate-180');
accordionMenu.style.maxHeight = accordionMenu.scrollHeight + 'px';
updateParentHeights(accordionMenu);
} else {
buttonArrow.classList.remove('rotate-180');
accordionMenu.style.maxHeight = 0;
collapseParentHeights(accordionMenu);
}
}
});
function updateParentHeights(childAccordion) {
let parentContent = childAccordion.parentElement.closest('.accordion-content');
while (parentContent) {
const parentButton = parentContent.previousElementSibling;
if (parentButton && parentButton.classList.contains('active')) {
// Temporarily disable transitions for accurate height calculation
parentContent.style.transition = 'none';
parentContent.style.maxHeight = 'none'; // Ensure full height calculation
const updatedHeight = parentContent.scrollHeight + 'px';
parentContent.style.transition = ''; // Re-enable transition
parentContent.style.maxHeight = updatedHeight;
}
parentContent = parentContent.parentElement.closest('.accordion-content');
}
}
function collapseParentHeights(childAccordion) {
let parentContent = childAccordion.parentElement.closest('.accordion-content');
while (parentContent) {
const parentButton = parentContent.previousElementSibling;
if (parentButton && parentButton.classList.contains('active')) {
// Adjust parent height after child collapses
parentContent.style.transition = 'none';
const updatedHeight = parentContent.scrollHeight + 'px';
parentContent.style.transition = '';
parentContent.style.maxHeight = updatedHeight;
}
parentContent = parentContent.parentElement.closest('.accordion-content');
}
}
版权声明:本文标题:javascript - Problem updating parent max-height in nested accordions (measurement is wrong) - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1738669455a2105904.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
accordionMenu.style.maxHeight = accordionMenu.scrollHeight + 'px';
withaccordionMenu.style.maxHeight = 'fit-content';
and it will work fine. You can use the new interpolate-size: allow-keywords; to allow transition – Mehdi Commented Jan 20 at 20:47max-height
entirely and switch to a grid implementation. – Brett Donald Commented Jan 20 at 23:21