Tips for avoiding width miscalculations due to the appearance or disappearance of a vertical scrollbar

I recently created a website featuring a tree explorer in a sidebar. However, I encountered an issue with the width calculation of the explorer when toggling the subtrees. This problem specifically arises on Chrome version 111.0.5563.64 for Ubuntu Desktop and can be replicated using the following code snippet.

var [leftEl, rightEl] = (
  document.getElementById("grid")
).children;

var tree = `\
node /1
  node /1/1
  node /1/2
  node /1/3
    node /1/3/1
    node /1/3/2
    node /1/3/3
node /2
  node /2/1
  node /2/2
  node /2/3
`;

// Event listeners and other code omitted for brevity

#grid {
  height: 100px;
  display: grid;
  grid-template: 1fr / auto 1fr;
}

// CSS styling properties continued...

<div id="grid">
  <div>
    <!-- Example -- >
    <ul>
      <li class="leaf">
        <div class="highlighted">node /1</div>
      </li>
      // More HTML code here...
    </ul>
  </div>
  <div></div>
</div>

The layout consists of two div elements placed side by side in a grid arrangement.

https://i.sstatic.net/CmRVi.png

The yellow div element represents the tree explorer positioned on the left. This particular div needs to be vertically scrollable, as its content may vary in length while maintaining a fixed height.

On the other hand, the blue div on the right adjusts its width dynamically using the fr unit. Its content updates based on hover interactions within the tree explorer section.

The width miscalculation issue occurs when the scrollbar of the explorer appears or disappears. The bug's replication process involves:

  1. Expanding "node /1"

    https://i.sstatic.net/srBdZ.png

    • The yellow div's scrollbar becomes visible
    • A green border indicates text overflow

In trying to resolve this bug, my hypothesis is that the computation sequence relating to container widths might be affected. As per my assumptions, the final state of the scrollbar plays a crucial role at certain stages of calculation. Hence, actions need to be taken to ensure proper consistency during these processes.

  • During specific steps, the configuration of the scrollbar causes inconsistencies in computations leading to the bug.
  • For other scenarios, where scrollbar status remains stable, computation alignments are correct, thus avoiding issues.

To address this challenge, I implemented a temporary solution involving a click event listener to trigger an immediate update of the blue div. Although effective, this approach introduces visual glitches and unnecessary reflows, potentially impacting overall performance. Therefore, I am seeking alternative solutions, preferably in pure CSS or HTML, to rectify this bug more efficiently.

Answer №1

There seems to be an issue with the div surrounding the p tags. To resolve this, you can do the following:

1: wrap.style.width = "0px"

Add this JavaScript code inside case 2, and then add:

2: wrap.style.width = ""

to case 0 in order to fix the border on state 4. However, it may still not display correctly on state 2.

To address this, include:

3: overflow-y: scroll;

for #grid div:first-child and:

4: overflow: hidden;

for #grid to hide the horizontal scrollbar while making the vertical scrollbar visible on the first state. Then, add:

5: gridEl.style.overflow = "visible"

in your JS code to make it visible again.

Furthermore, by adding:

6: #wrap {
      display: none;
   }

In your CSS, you can eliminate the initial scrollbar. Followed by including:

7: wrap.style.display = "block"

In your JS which will allow it to be displayed after that. The changes mentioned above have been incorporated into your code below:

... (Code has been truncated for brevity)

Answer №2

Melik's answer provided me with a fascinating solution:

19 | When I clicked on <div id="leftEl"></div>, Melik's code executed:
20 |   if (target !== this) if (target.tagName === "DIV") {
   …
28 |     After some calculations, the scrollbar style was adjusted based on content height and container height:
29 |       this.style.overflowY = "scroll";
30 |     } else {
31 |       this.style.overflowY = "hidden";
32 |     }
33 |   }
34 | });

The trick was to anticipate and set the scrollbar state before the next layout calculation, allowing for smoother computation. Surprisingly, it was discovered that the `scrollHeight` property was already up-to-date at that point, as evidenced by the console log. This revelation eliminated the need for a timer in the initial implementation.

A snippet of HTML and JavaScript showcased how the grid elements were interacted with using event listeners:
A CSS styling block detailed the appearance and behavior of the grid and list elements:
An example structure within the grid was presented, along with its visual representation:

Despite the refined solution, an accuracy issue persisted. Occasionally, even when the difference between `scrollHeight` and `offsetHeight` equaled 1, the scrollbar handle was absent. In essence, the scrollbar visually indicated full occupancy but behaved as if the content height was less than or equal to the container height (quite puzzling).

Diving into floating-point computations confirmed that the discrepancy between content height and container height fell within the range of 0 to 1. Armed with this insight, attempts to replicate the bug proved fruitless. Consequently, as a last resort, hiding the scrollbar under such conditions resulted in the desired outcome.

19 | Refinements were made to the click event handler logic: 
20 |   if (target !== this) if (target.tagName === "DIV") {
   …
28 |     By fetching computed styles, the actual height of the element was determined:
29 |     var style = getComputedStyle(this);
30 |     var height = parseFloat(style.height);
31 |     If the calculated difference was marginal (< 1), the scrollbar was concealed:
32 |     this.style.overflowY = "hidden";
33 |     Otherwise, the scrollbar remained visible:
34 |     this.style.overflowY = "scroll";
35 |   }
36 | });

The alternative approach, while not ideal, circumvented dependency on the task queue. Nonetheless, thoughts lingered on potential CSS or HTML solutions for a more elegant fix.

With lingering uncertainties, the decision was made to reserve judgment until further exploration, warranting further consideration for optimal resolution.

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

Issues with sending empty strings to an API in Vue Js

My code below is designed to update data using a Node Js REST API. The remaining field contains an equation using v-model=remaininginst to calculate and store the result in remaininginst. However, when I check the console.log, I am getting NaN empty data s ...

CSS Animations as an Alternative to jQuery's fadeIn(), fadeOut(), and fadeTo() Functions

I currently have the following code snippet: $('#button1').click(function(){ $('#header_bg').fadeTo(15, 0, function() { document.getElementById('header_bg').style.fill = '#FF0000'; }).fadeTo(&ap ...

Getting the value of dynamically generated buttons when they are clicked in PHP - a simple guide

In my PHP code, I have successfully created dynamic buttons. However, I am facing an issue where I need to retrieve the value of a specific button when it is clicked, and populate all the information in a form. Below is the code snippet for handling the b ...

Configuring multiple views directories in Express fails to function as expected

Looking to define multiple views directories in Express. Working with Express version 4.16.3, Node.js version v10.15, and EJS version 2.5.9. app.set('views', [path.join(__dirname, 'views'), path.join(__dirname, 'public/static/&apo ...

Resizing an image texture using three.js

Utilize image textures, The image is not a power of two in size, so it has been resized to 4096x2048. This message is displayed in the console. Is there a way to disable this message or prevent the image from being resized? ...

What is the best way to arrange form inputs in a single row?

My form consists of three input boxes. While the first two inputs are single line, the third is a description field with 10 rows set as default. However, for some reason, this third box is not aligned properly with the other two. Please refer to the screen ...

Begin the animation again by hitting the start button, using the burst-engine and canvas

I have successfully created a simple animation using Burst Engine and HTML5. My goal is to make the start button trigger the animation to restart if pressed twice. Currently, when I press it, the animation just starts and nothing else happens. I suspect t ...

Customizing Google Maps API v3: Utilizing Custom Images as symbolPath Instead of Default Symbols

Recently, I discovered the fascinating feature called Symbol Animation in Google API's documentation. All aspects of my code are functioning optimally; however, I am curious to know if it is possible to substitute an image for a symbol in the followi ...

What is the correct location to store the bower.json file?

I'm currently using bower 1.2.2 to handle my client-side libraries for the first time with a new node app. I'm unsure whether I should initialize bower in the main project root alongside gruntfile.js and package.json, or within the static directo ...

What is the best way to prevent blank space when splitting a div into two parts?

Currently in the process of working on a school project that involves creating a website with an integrated database. The foundation for this project is an existing website from a previous assignment, created using PHP/HTML. The layout of my prior website ...

Is Node.js categorized as multithreading due to its utilization of worker threads?

Throughout my life, I was under the impression that Node.js and JavaScript operated as a single threaded language. It was always said that Node.js wasn't ideal for CPU intensive tasks due to its single threaded nature. Multithreading, on the other han ...

Attempting to preserve the CSS transform effect as I switch between menu options

Whenever I stop hovering over my element, it reverts back to its original position. However, I want it to remain in place when I am navigating through the "sousmenu" menu and only return to its original position when I am not hovering over the "sousmenu". ...

Blog Writer: Picture quality compromised when adjusting size

Issue with blurry images after resizing. The problem is noticeable in the three main images located under the Header section. To preview the blog, click on this link: Click Here Your assistance in solving this issue would be greatly appreciated. Thank yo ...

The display of website content across various screens

I'm relatively new to creating websites using scripts, CSS, etc. But I feel like I'm getting the hang of it pretty well... Now I've reached a point where I want my site to look good on different screen resolutions. Currently, I have somethin ...

Text wrapped automatically to display multiple lines with spacing between each highlighted line

Question about CSS formatting and spacing. I need to automatically break sentences into new lines based on the width of the container. For example, a sentence like: This is a sentence should be displayed as: This is<br>a sentence I am trying ...

What happens when an AJAX request doesn't have a success field?

Is it possible to execute an ajax call without specifying a success function? $.ajax({ type: "POST", url: "/project/test/auto", data: data, // no success function defined here }); My reasoning for this is that I have PHP code that insert ...

A guide to accessing REST services in AngularJS using basic authentication

I currently have a REST service up and running on my server. Using Chrome Postman, I am able to access this service with Basic Authentication. However, I now want to build a user interface in AngularJS to display the data received from the REST service. T ...

Triple the Charts: Highcharts Vue Component combines three dynamic charts into one powerful visual tool

looking for help with creating a complex chart Hello, I have a task of creating what seems to be 3 charts in one design. I am able to create the two scattered charts, but the column charts are proving to be challenging. Thanks to Wojciech Chmiel, I manage ...

Using an alias to call a function defined in a separate module in TypeScript

The following code snippet is from the v4.js file located inside the uuid folder within Angular's node_modules: var rng = require('./lib/rng'); var bytesToUuid = require('./lib/bytesToUuid'); function v4(options, buf, offset) { ...

Dragging and Dropping Electron Files into an Inactive Window

I am exploring the implementation of drag and drop functionality within an electron window, utilizing the suggested approach of sandboxing processes. This involves isolating ipcMain from ipcRenderer and creating a bridge through a preload.js script (refer ...