Styling with CSS: Scroll content within a parent container when hovering over a fixed child element

I have a container with internal scrolling. Inside, there is content that can be scrolled through, along with a sidebar child element set as position: fixed;.

When I hover over the parent and scroll, the contents scroll properly. But, if I hover inside the fixed child (still within the parent's boundaries) and try to scroll, it does not respond:

<style>
  body,
  html {
    margin: 0;
  }
  
  #container {
    position: relative;
    width: 100%;
    height: 100vh;
    overflow-y: auto;
  }
  
  #sidebar {
    position: fixed;
    right: 10px;
    width: 100px;
    top: 10px;
    height: calc(100% - 20px);
    background-color: red;
  }
</style>

<div id='container'>

  <div id='sidebar'>
    <a href='https://google.com/'>Clickable Link</a>
    Scrolling doesn't work when hovering here.
  </div>

  <p>Lorem ipsum.</p>
  <p>Lorem ipsum.</p>
  <p>Lorem ipsum.</p>
  ... and so on. Scrolling works when hovering here.

</div>

I am looking for a way to allow the scroll event to propagate from the fixed child to its parent with overflow, enabling the user to scroll the main container even while hovering over the child. Is this achievable?

I've attempted using JavaScript to capture scroll events on the child and pass them up to the parent, but unfortunately no scroll events are detected (probably because the child has nothing to scroll internally). Different positioning configurations of the parent element (position:relative;, position:absolute;, position:fixed;) were also tried without success. The issue seems to occur specifically with a fixed child, and changing it to absolute is not an option.

If possible, I would prefer a solution that doesn't involve JavaScript. Suggestions for HTML-only, HTML and CSS, or JavaScript-only solutions would be appreciated.


I'm familiar with this question, but the proposed workaround doesn't function as expected since scrolling while hovering over the fixed child doesn't trigger a scroll event for either the child or parent. The alternative suggestion of moving the child outside the parent isn't feasible in my case.


Edit: Harsh Karanpuria recommended adding pointer-events:none; to the sidebar. While this achieved the desired scrolling behavior, it rendered elements in the sidebar unclickable, which is not ideal. Subsequently, I tried setting child elements of the sidebar as pointer-events: all;, which allowed clicking them but once again disabled scrolling when hovering over those grandchildren.

Answer №1

To accomplish this, all you need to do is include the following code snippet:

#sidebar {
    ...
    pointer-events: none;
    ...
}

Answer №2

Avoid Using <code>position: fixed;
, Try position: sticky;

I firmly advise against using position: fixed; for your layout needs. Instead, consider utilizing position: sticky;. No need to complicate things with event propagation tricks when CSS provides a better alternative.

According to the CSS3 Positioned Layout Module, the purpose of fixed positioning is clear:

Fixed positioning absolutely places and attaches the box to the viewport or page frame, ensuring it remains visible at all times.

Your understanding that child elements with fixed positioning are still constrained within their parent's boundaries may be visually accurate, but simply adding a margin to the parent element can create enough separation:

<style>
  body,
  html {
    margin: 0;
  }
  
  #container {
    /* <Changes> */
    background-color: skyblue;
    margin-top: 10vh;
    /* </Changes> */
    position: relative;
    width: 100%;
    height: 100vh;
    overflow-y: auto;
  }
  
  #sidebar {
    position: fixed;
    right: 10px;
    width: 100px;
    top: 10px;
    height: calc(100% - 20px);
    background-color: red;
  }
</style>

<div id='container'>

  <div id='sidebar'>
    <a href='https://google.com/'>Clickable Link</a>
    When hovering here, scrolling does NOT work.
  </div>

  <p>Lorem ipsum.</p>
  <p>Lorem ipsum.</p>
  <p>Lorem ipsum.</p>
  ...scroll works in this area only.

</div>

The issue where events on children with position: fixed don't bubble up as usual to the parent element is not explicitly explained in W3C specs. However, bear in mind that scroll events will propagate to the viewport instead of bubbling to the parent container normally.

As stated in the W3C CSS Positioned Layout Module Level 3 § 2:

[position: fixed:] Similar to absolute positioning, but the box is sized and placed relative to a fixed positioned containing block (typically the viewport in continuous media). This scheme ensures that the box remains fixed concerning this reference area: whether attached to the viewport or replicated on paginated document pages, known as fixed positioning – a subset of absolute positioning.

The primary role of position: fixed elements is to remain fixed to the viewport rather than its parent container. The adequate solution to your dilemma lies in employing position:sticky.

Implementing position:sticky Alongside display: flex

<style>
  body,
  html {
    margin: 0;
  }
  
  #container {
    /* <Changes> */
    background-color: skyblue;
    display: flex;
    max-height: 40vh; /* Demo scrolling constraint. */
    /* </Changes> */
    position: relative;
    width: 100%;
    height: 100vh;
    overflow-y: auto;
  }
  
  #sidebar {
    position: sticky;
    right: 0px;
    top: 0px;
    min-width: 100px;
    background-color: red;
  }
</style>

<div id='container'>
  <!-- Changes -->
  <div id="content">
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    ...allowing scroll in this section. Long lines won't overlap sidebar.
  </div>
  <div id='sidebar'>
    <a href='https://google.com/'>Clickable Link</a>
    Scrolling also functions while hovering here.
  </div>
</div>

To avoid content overlap, the HTML has been slightly modified by enclosing the <p> tags within div#content and adjusting the sequence of content and sidebar placement. Alternatively, you could alter the flex-direction without reordering the elements. The main idea remains consistent: a parent container, inner content, and inner sidebar.

This layout differs from the original question where the sidebar can't overlap the content. If desired, you can improve this further by implementing display: grid.

Utilizing position:sticky with display: grid

Create a grid area dedicated solely to the sidebar as follows:

<style>
  body,
  html {
    margin: 0;
  }
  
  #container {
    /* <Changes> */
    background-color: skyblue;
    display: grid;
    grid-template-columns: 1fr min-content;
    
    max-height: 40vh; /* Demo scrolling constraint. */
    /* </Changes> */
    position: relative;
    width: 100%;
    height: 100vh;
    overflow-y: auto;
  }
  
  #content {
    grid-row: 1 / span 2;
    grid-column: 1 / span 2;
  }
  
  #sidebar {
    grid-row: 1;
    grid-column: 2;
    position: sticky;
    right: 0px;
    top: 0px;
    min-width: 100px;
    min-height: 110px;
    background-color: red;
  }
  
</style>

<div id='container'>
  <div id="content">
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    <p>Lorem ipsum.</p>
    ...content overlapped by the sidebar during scroll.
  </div>
  <div id='sidebar'>
    <a href='https://google.com/'>Clickable Link</a>
    Scroll interactions available while hovering here.
  </div>
</div>

Adjusting grid-column and grid-row manually on the #sidebar and #content tags enables content overlap.

Further Reading References:

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

Steps to eliminate the active state of a button after clicking on an input

I am currently working on a component that consists of 4 preset buttons and a customized range input. The issue I am facing is that while I can toggle the active state on the buttons when they are clicked, I want to remove the active state from all the but ...

Selectors that can be applied to multiple IDs with identical functions

I have a script for popups that I want to be able to use multiple instances of. For example, I would like to have 5 popups on one page without having to change the JavaScript code. While everything in the script works fine, I am struggling to make it work ...

The fopen() function requires a valid path as its first parameter

Encountered a new error that I have never seen before! Feeling very confused... I'm currently only testing this specific section of code to achieve what I want: <?php if(isset($_GET['id'])) { $index = $_GET['id']; $nick ...

Expanding the background further than the parent's width using HTML and CSS

I am looking to extend the background color or image to mimic the appearance of the example at the bottom in this jsfiddle Same code but showcased here: Example1: <div class="fixed_width"> <div class="header">Header</div> <div ...

Audio support across multiple channels on iOS and Android web browsers

After stumbling upon a helpful link to a page here on StackOverflow discussing "Creating Audio using Javascript in <audio>", and also finding a resource on another website detailing how to play audio on multiple channels, I have come across a questio ...

Automatically update the selection in an md-select dropdown

I am dealing with the following HTML structure <md-select id="testSelect" ng-model="objElements" ng-change="onElementChange()" name="objElements" placeholder="Select Stuff"> <md-option id="testOption" ng-r ...

Utilize AJAX to fetch additional data upon clicking the ID row in PHP

I am looking to display additional PHP data when a row with $row->student id is clicked. Upon clicking the row->studentid, the data should be shown as an AJAX response in the showmore div. Below is a section of the index.php code. <div class ...

Creating a responsive navigation bar with Bootstrap步 is simple and effective

Thank you for taking the time to review my current code. The main issue I am encountering pertains to the responsiveness of the navbar. Whenever I zoom in or out, certain elements tend to lose their alignment and aesthetic appeal. Specifically, the navbar ...

Utilizing conditional statements in Vue.js for dynamic rendering

Looking for some assistance, thank you. I am struggling with writing the correct condition in Vue for my task. I have two values: content.Image & header.Background Essentially, what I need to do is check if there is a JPEG assigned to content.Image ...

Explore jQuery to locate a specific anchor element that has a matching URL and then apply a new class

I am looking to highlight both the parent and child items in a navigation menu by returning URLs as an array based on the current page. The structure of my basic navigation is as follows: <div id="cssmenu"> <div id="menu-button"></div&g ...

Relative Vs Absolute Positioning: Which One to Choose?

Can you explain the distinction between position: relative and position: absolute in CSS? Additionally, when is it appropriate to utilize each one? ...

Struggling to vertically center a div using the Sticky footer method?

I'm working on implementing the Sticky Footer technique on my website, but I'm running into an issue with aligning my content both horizontally and vertically within the #main section. The problem arises from the fact that the bottom padding is s ...

Using a <div> to contain <mat-card> in Angular Material

Can you achieve the following: Show components with specified width in a row instead of the usual column layout Enclose the cards within another defined container I've been attempting to accomplish this but without success so far.... While materia ...

Issue with loading CSS in Magento transactional emails

I designed a custom email template specifically for order cancelations. The email is functioning properly, with the header and footer displaying correctly. However, the existing CSS is not being applied to the email template. While default headers and fo ...

The dimensions of the parent element do not match the width and height of the image

My friend requested that I look into an issue on his website. In the portfolio section, there is a border around the div and a rollover effect when hovering over the images. However, there is a strange problem where the box containing the image and data is ...

Is the if statement I used correct for this character limit counter implementation?

I am currently working on a code snippet that aims to include a character limit counter. When the counter reaches 0, I want it to display "Over!" in red text, but return to counting when the user deletes characters. Although this is my current code, I sus ...

The custom radio button options are not currently in view

I'm interested in personalizing my radio buttons to have a unique appearance. Here is the CSS and HTML code I am using: HTML: <div class="buttonSlider"> <input type="radio" value=".."></input> <input type="radio" value=" ...

Struggling to manipulate the transparency of an image contained within a div element

I am struggling to achieve the desired effect of having an opaque image inside a transparent div. I have tried setting the opacity for both the image and the div, but it doesn't seem to be working as expected. Here is my jsFiddle Link for reference: ...

Is there a way to align a button in the center of the browser's footer?

Removing these two elements will enable the image to display properly, however, it does not stay aligned with the footer when viewed in a browser. Here is a preview of how it looks: Below is the CSS code along with the HTML: <style> body { ...

Styling in sass gets even more powerful when using custom selectors that are

Using these mixins makes it easy to work with BEM syntax in sass 3.3.2: =b($name) .#{$name} @content =e($name) &__#{$name} @content =m($name) &--#{$name} @content +b(menu) +e(item) color: grey +e(item) +m(alert) ...