How to seamlessly adjust the height from 0 to auto

My goal is to smoothly transition from height: 0; to height: auto; and reveal the content inside a <div></div>. One effective method I've come across involves using the max-height property. Here's an example of how it can be implemented:

#menu #list {
  max-height: 0;
  transition: max-height 0.15s ease-out;
  overflow: hidden;
  background: #d5d5d5;
}

#menu:hover #list {
  max-height: 500px;
  transition: max-height 0.25s ease-in;
}
<div id="menu">
  <a>hover over me</a>
  <ul id="list">
    <li>item</li>
    <li>item</li>
    <li>item</li>
    <li>item</li>
    <li>item</li>
  </ul>
</div>

While this method works well, there is a challenge when dealing with dynamic data retrieved from a database. The number of items within the list can vary greatly, making setting a fixed max-height impractical. Adjusting max-height based on the number of items through JavaScript would be complex and not ideal for responsive design.

I am seeking a solution that can accommodate both large and small amounts of items in a <ul> while maintaining smooth transitions. Ideally, a purely CSS-based solution would be perfect, but I am open to incorporating JavaScript if necessary.

Answer №1

To achieve this effect, JavaScript can be utilized.

Specify the transition to target the height property. Upon hovering (using mouseenter), set the height value based on the content's scrollHeight.

Once the transition is finished, adjust the height to auto so that any future changes in height are automatically accommodated (e.g., adding another item while the list is still open). This results in a smooth transition between 0 and auto.

On mouseleave, reset the height back to the scrollHeight (as transitioning from auto isn't feasible), allow the browser to repaint (using setTimeout with a 0 delay or requestAnimationFrame), and then return to 0.

const list = document.getElementById('list');
const trigger = document.getElementById('trigger');
let timeout;

trigger.addEventListener('mouseenter', () => {
  list.style.height = `${list.scrollHeight}px`;
  // Remove the hardcoded height at the end of the transition
  // so that further changes to the height will be automatically
  // reflected
  clearTimeout(timeout);
  timeout = setTimeout(() => list.style.height = 'auto', 150); // Should match the transition delay
});

trigger.addEventListener('mouseleave', () => {
  clearTimeout(timeout);
  list.style.height = `${list.scrollHeight}px`; // Set it to the height again
  timeout = setTimeout(() => list.style.height = 0, 0); // Wait for paint
});
#list {
  height: 0;
  transition: height 0.15s ease-out;
  overflow: hidden;
  background: #d5d5d5;
}
<div id="menu">
  <a id="trigger">hover over me</a>
  <ul id="list">
    <li>item</li>
    <li>item</li>
    <li>item</li>
    <li>item</li>
    <li>item</li>
  </ul>
</div>

Answer №2

To achieve this effect, you can utilize JavaScript. By using the childElementCount property, you can determine the number of li elements within a specific ul element and dynamically adjust the maxHeight accordingly.

let ul = document.querySelector("#list")

document.querySelector("#menu").onmouseover = function (){
  ul.style.maxHeight = 100*ul.childElementCount + "px";
};

document.querySelector("#menu").onmouseleave = function (){
  ul.style.maxHeight = 0;
};
#menu #list {
  max-height: 0;
  transition: max-height 0.15s ease-out;
  overflow: hidden;
  background: #d5d5d5;
}

#menu:hover #list {
  transition: max-height 0.25s ease-in;
}
<div id="menu">
  <a>hover over me</a>
  <ul id="list">
    <li>item</li>
    <li>item</li>
    <li>item</li>
    <li>item</li>
    <li>item</li>
    <li>item</li>
    <li>item</li>
    <li>item</li>
    <li>item</li>
    <li>item</li>
  </ul>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Display identical text using JavaScript filter

My search filter highlight is currently displaying [object Object] instead of <mark>match values</mark> when replacing the values. This is the code I am using: this.countries.response.filter((val) => { const position = val.value.toLowerCa ...

Setting default values for Vue prop of type "Object"

When setting default values for objects or arrays in Vue components, it is recommended to use a factory function (source). For example: foobar: { type: Object, default() { return {} } } // OR foobar: { type: Object, default: () => ({}) ...

Using the flexslider to override CSS styles in an <li> element

I have implemented the flexslider by whoothemes on my responsive website to showcase tiles. However, I am facing an issue with setting a specific width for the tiles on various devices. Upon inspecting with Chrome, I see this code: <li style="width: 21 ...

Regular expression: Find the backslash character that is not being used to escape another character

I have a multitude of JavaScript and PHP files that require thorough checking to ensure that I have used only a single \ to separate words in path names. It is important for me to identify every instance where I might have accidentally used .\som ...

Add a fresh record only if it contains information and there are no existing duplicates present

Is it possible to create a note with both a title and text, under certain conditions? The title must not be empty The title cannot already exist in the system When attempting to check for duplicates within my array, the boolean value always returns true ...

PHP email script encounters error message despite receiving a network response code of 200

I found this PHP code online and it seems to be correct, but I keep encountering an error message every time I attempt to send a test email. However, the network message indicates that the email was sent successfully. Please refer to the provided images an ...

Encountering problem when trying to upload several images at once using a single input in CodeIgniter with

I'm attempting to use CodeIgniter and AJAX to upload multiple images using a single input field. Here's the code I have so far: HTML: <input type="file" name="files[]" id="file" multiple /> AJAX: $("#addItems").on("submit",function(e) { ...

Does LABJS include a feature for executing a callback function in the event of a timeout during loading?

When using LabJS to asynchronously load scripts with a chain of dependencies, if one of the scripts breaks (due to download failure or connection timeout), it seems that the remaining scripts in the chain will not be executed. Is there a way to define a ...

Generating multiple arrays within a multidimensional array using Javascript in a dynamic way

I have a single variable called $arrayQuantity that holds a changing value. This value determines how many item arrays should be created within the $itemsContainer array when the page is loaded. For example: //In this example, I want to create 3 `item` ...

React-spring is exclusively compatible with the Canvas element within react-three-fiber

It's strange, but my react-spring animations only seem to function when there is a Canvas component from react-three-fiber present. import React from 'react'; import { Canvas } from "@react-three/fiber"; import { useSpring, animate ...

Retrieve the output from PHP in JSON format and then utilize jQuery to parse it

I am currently working on a jQuery function $.post(file.php), where the data is being sent to "file.php" and returned in JSON format using json_encode(). Although I am able to successfully retrieve the result, I am unsure how to separate the individual i ...

Maintain the functionality, but disable all stylesheets and scripts

I have 4 separate pages, each with their own distinct stylesheets and scripts that I switch between using ajax and historyPopState. The issue is that downloading them repeatedly can be inefficient. I am seeking a solution to keep the stylesheets and scri ...

Passing props from Vue3 to a component being rendered through RouterView

I'm facing an issue with the following code snippet: <template> <router-view /> </template> <script setup lang="ts"> ... const product: Ref<IProduct|undefined>: ref(); ... </script> The challenge is ...

Deciphering HTML with the Eyes

So, I find myself in a bit of a bind trying to come up with a title for this question. I have stumbled upon some HTML files that seem so complex, they could only have been crafted by the one and only Lord Lucifer himself. These files contain segments like ...

Extract solely the content from a span element that meets specific width requirements

Currently, I am facing an issue with a dynamically filled span that gets content added to it. Once the content reaches the width of 500px, I need to be able to read only the content within the first 300px. This content can consist of either one line or mul ...

How to integrate a new DOM element into a React Native app with the simple click of a button

Is it possible to add a <Text> element with the click of a button in react native? If so, how can this be achieved? Here is my current code: import React, { Component } from 'react' import { StyleSheet, Text, View, Button } from &apos ...

Is it possible to hide a portion of a jQuery UI draggable element using display:none while maintaining the cursor position?

My challenge involves having draggable elements with images that need to be dropped into folders. In order to maximize screen space and keep more draggables visible at once, I have decided to hide the images using CSS during the drag operation. However, I ...

Activate Vuetify to toggle a data object in an array list when the mouse hovers over

I'm currently working on a project where I need to toggle a Vuetify badge element for each item in an array when the containing div is hovered over. While I've been able to achieve a similar effect using CSS in a v-for loop with an array list, I ...

Conceal the href element within a designated UL using JavaScript

Is there a way to only hide the href element in a specific UL element, rather than hiding all href elements with the same class name? Let's consider an example HTML code: <ul class="UL_tag"> <li>Text 1</li> <li>Text 2< ...

How come Vue.js is not showing the image I uploaded?

Even though I can successfully print the image URL, I'm facing an issue where the img tag is not displaying it, despite my belief that I've bound it correctly. <html> <head> <title>VueJS Split Demo</title> <script t ...