A dynamic 3-column layout featuring a fluid design, with the middle div expanding based on the

Sorry for the vague title, I'm struggling to explain my issue clearly, so let me elaborate.

I am using flexbox to create a 3-column layout and want the middle column to expand when either or both of the side panels are collapsed. Here is a screenshot showing the problem:

Currently, all three columns fill the screen width when the panels are open. However, when one of the side panels collapses, the center column does not expand to fill the space as needed.

I suspect that using translateX to toggle the panel visibility may be causing this issue. It seems like the center column doesn't recognize the shift in position of the side panels, hence fails to expand into the available space.

Code snippets:

CSS:

<style>
    body {
        background-color: lightslategrey;
    }
    .red {
        background-color: lightcoral;
    }

    .green {
        background-color: lightgreen;
    }

    .grey {
        background-color: lightslategray;
    }

    * {
        box-sizing: border-box;
    }

    .ls-toggle, .rs-toggle {
        //position: fixed;
        z-index: 1;
        cursor: pointer;
        transition: 0.5s;
    }

    #left-sidebar, #right-sidebar {
        width: 250px;
        height: 100vh;
        transition: 0.5s;
    }

    #left-sidebar.is-closed {
        transform: translateX(-80%);
    }

    #right-sidebar.is-closed {
        transform: translateX(80%);
    }

    .ls-top, .rs-top {
        display: flex;
        width:100%;
        height:35px;
        align-items: center;
        justify-content: flex-end;
        background-color: lightslategrey;
    }

    .rs-top {
        justify-content: flex-start;
    }

    #mw-content {
        width: 100%;
        height: 100vh;
    }
</style>

HTML:

<div class="d-flex">
    <div id="left-sidebar" class="col- red">
        <div class='ls-top grey'>
            <button class="ls-toggle"><i class="fas fa-angle-left fa-2x"></i></button>
        </div>
    </div>

    <div id="mw-content" class="col green">
        <h3> Main Window Content.</h3>
    </div>

    <div id="right-sidebar" class="col- red">
        <div class='rs-top grey'>
            <button class="rs-toggle"><i class="fas fa-angle-right fa-2x"></i></button>
        </div>
    </div>
</div>

JS:

$(document).ready(function () {
        var lsToggleBtn = document.querySelector('.ls-toggle');
        var lsSidebar = document.querySelector('#left-sidebar');
        var rsToggleBtn = document.querySelector('.rs-toggle');
        var rsSidebar = document.querySelector('#right-sidebar');

        lsToggleBtn.addEventListener('click', function () {
            lsToggleBtn.classList.toggle('is-closed');
            lsSidebar.classList.toggle('is-closed');
        });

        rsToggleBtn.addEventListener('click', function () {
            rsToggleBtn.classList.toggle('is-closed');
            rsSidebar.classList.toggle('is-closed');
        });
    });

Attempts made:

  • Added flex: 1 1 auto to main content container (mw-content).
  • Set flex: 0 to l/r sidebar containers & flex: 1 1 auto to main content container
  • Applied width: 100% on main content container
  • Experimented with using translateX on main content container & adjusting width on left sidebar click

I've tried these solutions without success. I admit I struggle with flexbox, so any advice would be greatly appreciated. Thank you! :)

Answer №1

To achieve the desired layout, you must utilize the "position: absolute" property and integrate two additional classList.toggle functions.

$(document).ready(function () {
  var mwContent = document.querySelector('#mw-content');          // !!
  var lsToggleBtn = document.querySelector('.ls-toggle');
  var lsSidebar = document.querySelector('#left-sidebar');
  var rsToggleBtn = document.querySelector('.rs-toggle');
  var rsSidebar = document.querySelector('#right-sidebar');

  lsToggleBtn.addEventListener('click', function () {
    lsToggleBtn.classList.toggle('is-closed');
    lsSidebar.classList.toggle('is-closed');
    mwContent.classList.toggle('ls-pos');         // here
  });

  rsToggleBtn.addEventListener('click', function () {
    rsToggleBtn.classList.toggle('is-closed');
    rsSidebar.classList.toggle('is-closed');
    mwContent.classList.toggle('rs-pos');         // here
  });
});
body {
  background-color: lightslategrey;
  margin: 0;
  overflow: hidden;
}

.red {
  background-color: lightcoral;
}

.green {
  background-color: lightgreen;
}

.grey {
  background-color: lightslategray;
}

* {
  box-sizing: border-box;
}

.d-flex {
  display: flex;
  position: relative;
}

.ls-toggle,
.rs-toggle {
  cursor: pointer;
  transition: 0.5s;
}

#left-sidebar {
  position: absolute;
  left: 0;
  width: 250px;
  height: 100vh;
  transition: 0.5s;
}

#right-sidebar {
  position: absolute;
  right: 0;
  width: 250px;
  height: 100vh;
  transition: 0.5s;
}

#left-sidebar.is-closed {
  transform: translateX(-80%);
}

#right-sidebar.is-closed {
  transform: translateX(80%);
}

.ls-top,
.rs-top {
  display: flex;
  width: 100%;
  height: 35px;
  align-items: center;
  justify-content: flex-end;
  background-color: lightslategrey;
}

.rs-top {
  justify-content: flex-start;
}

#mw-content {
  position: absolute;
  right: 250px;
  left: 250px;
  height: 100vh;
  transition: 0.5s;
}

.ls-pos {
  left: 50px !important;
  transition: 0.5s;
}

.rs-pos {
  right: 50px !important;
  transition: 0.5s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


  <div class="d-flex">
    <div id="left-sidebar" class="col red">
      <div class='ls-top grey'>
        <button class="ls-toggle"><i class="fas fa-angle-left fa-2x"></i></button>
      </div>
    </div>

    <div id="mw-content" class="col green">
      <h3> Main Window Content.</h3>
    </div>

    <div id="right-sidebar" class="col red">
      <div class='rs-top grey'>
        <button class="rs-toggle"><i class="fas fa-angle-right fa-2x"></i></button>
      </div>
    </div>
  </div>

Answer №2

Here is an illustration demonstrating how vanilla JavaScript can be utilized to achieve this functionality.

The process involves two distinct functions - one designed to monitor the collapsing of section elements and resize the central section accordingly. This function keeps track of clicks, adding the IDs of clicked sections to an array. By checking this array conditionally, if it includes the IDs of the two outer sections, we adjust the size of the middle section using style.transform => scale(). The second function serves to reset the collapsible elements.

For more detailed information, please refer to the code snippet provided below.

let clicked = [];
const middle = document.querySelector('#sect2')

let section = document.querySelectorAll('.sect')
let reset = document.querySelector('#reset')

// Resize function on Collapse
const resizeOnCollapse = (elements) => {
  // iterating over the three sections
  elements.forEach(sec => {
    // Ensuring that the middle section cannot collapse
    if (sec.id !== 'sect2') {
      // Event listener to detect clicks on the outer sections
        sec.addEventListener('click', (event) => {
          // Appending the clicked elements to the array
          clicked.push(event.target.id)
          event.target.style.width = '0px'; // Set width to 0 for collapsing effect
          // Conditional statement to check if both outer sections are included in the array
          if (clicked.includes('sect1') && clicked.includes('sect3')) {
            // Resizing the middle section using transform: scale()
            middle.style.transform = 'scale(1.2)'
            middle.style.transition = 'transform .5s ease-out' // Adding transition animation
         }
       })
     }
   })
}

// Function to reset elements and the array 
const resetElements = (element, sections) => {
    element.addEventListener('input', () => {
      clicked = []; // Resetting the array
      sections.forEach((section) => {
        section.style.width = '30vw'; // Resetting width to undo collapse
        section.style.transform = 'scale(1)'; // Resetting transform rule to scale(1)
      })
    })
}

// Invoking the functions
resetElements(reset, section)
resizeOnCollapse(section)
#main {
  display: flex;
  justify-content: space-around;
}

.sect {
  width: 30vw;
  height: 80vh;
}

#sect1 {
  background-color: red;
}

#sect2 {
  background-color: blue;
}

#sect3 {
  background-color: green;
}
<button id="reset">reset</button>
<div id="main">
  <div id="sect1" class="sect">
  </div>
  <div id="sect2" class="sect">
  </div>
  <div id="sect3" class="sect">
  </div>
</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

Effortlessly transforming a massive JSON into an Array using ReactJS

I have a large JSON dataset containing information on over 2000 cities. I want to use this data in my React app, but first I need to convert it into an array. A similar question has been asked before, but I couldn't find any answers that fit my specif ...

`Inconsistencies in state management across components`

Creating a calendar with the ability to add notes for each day is my main goal. The structure of my components is organized as follows: App component serves as the common component that renders the main Build component. The Build component utilizes CellBui ...

Tips and tricks for manipulating base64 images in Node.js

I have a unique challenge - I want to manipulate a base64 picture by adding just one extra pixel. My goal is to send a base64 image string (e.g. data:image/png;base64,iVBORw0KG...) from my express server. Let's say the image is 100x100px and I need to ...

Tips for triggering an error using promise.all in the absence of any returned data?

I'm dealing with an issue in my project where I need to handle errors if the API response returns no data. How can I accomplish this using Promise.all? export const fruitsColor = async () : Promise => { const response = await fetch(`....`); if( ...

Javascript Parameter

Each time I enter scroll(0,10,200,10); into my code, it seems to output the strings "xxpos" or "yypos" instead of the actual values. I attempted to remove the apostrophes around them, but unfortunately, that did not resolve the issue. scroll = function( ...

Avoid loading external scripts from third-party sources such as JavaScript libraries, Bing Maps API, and Lighthouse performance tool

Issue: The Bing maps API I incorporated into my assignment is loading unnecessary CSS and scripts, causing a noticeable decrease in my lighthouse scores. Is there a way to prevent third-party code (such as Bing Ads) from loading when fetching the maps for ...

Having difficulty displaying a partial view within a view while making an AJAX call

Trying to figure out what's missing in my code. I have a view with some radio buttons and I want to display a different partial view when a radio button is selected. Here's the snippet of my code: Controller public ActionResult Method(string va ...

Using jQuery to handle nested div elements and triggering a click event only once when the inner div is clicked

I have a situation where I have nested divs. When the inner div (closeme) is clicked, I do not want the click event of the outer div (container) to be triggered. How can I achieve this? html <div id="container"> content <div id="closeme">< ...

Please do not exceed two words in the input field

I need to restrict the input field to only allow up to two words to be entered. It's not about the number of characters, but rather the number of words. Can this restriction be achieved using jQuery Validation? If not, is there a way to implement it u ...

unable to retrieve access-token and uid from the response headers

I am attempting to extract access-token and uid from the response headers of a post request, as shown in the screenshot at this https://i.sstatic.net/8w8pV.png Here is how I am approaching this task from the service side: signup(postObj: any){ let url = e ...

How can I create a Material ui Card with a border-less design?

After reviewing the information provided, I noticed that you can set the option to have it as variant="outlined" or raised However, I am curious if there is a method to create the card without any visible borders at all? ...

How to efficiently calculate totals in an HTML table using JavaScript/jQuery

I have a gridview that displays product details and includes a quantity textbox that is not linked to any database. For each row, I want it to show the cost (price * quantity) and the total cost for all rows in a label below. However, I am encountering a f ...

Tips for making a central CSS gradient

I am looking to create a background gradient similar to the one shown in the image (Load more news) and also add a border style. Any suggestions on how to achieve this would be greatly appreciated. ...

Toggle checkbox feature in Bootstrap not functioning properly when placed within ng-view

When attempting to embed a bootstrap toggle checkbox within <ng-view></ng-view>, an issue arises where a regular HTML checkbox is displayed instead of the expected bootstrap toggle. Strangely, the same checkbox functions as a bootstrap toggle w ...

Animating with CSS3 triggered by JavaScript

Can you help me with an issue I'm having? When attempting to rotate the blue square using a function, it only works once. After that, the page needs to be reloaded in order for the rotation function to work again. Additionally, after rotating 120 degr ...

Updating the object does not result in the interpolation value being updated as well

I am facing an issue with this v-for loop: <tr v-for="(product, index) in products" v-bind:key="products.id"> <div v-on:click="decrementQtd(index)" class="action-qtd-button-left"> <strong>-</strong> </div> < ...

IE compatibility mode causing ckeditor dropdown to be hidden

When using the CKEditor editor bar inside a green div with another div below it, I noticed that when clicking on "font" or any other option that opens a dropdown menu, it gets hidden behind the bottom div. This issue seems to occur in browsers like Chrome ...

Rearrange the elements in an array containing objects

I am working with an array of objects: const array = [ { id: "5a2524432b68c725c06ac987", customOrder: 1, name: "One", }, { id: "5a2524432b68sgs25c06ac987", customOrder: 2, name: "Two", }, { id: "5a252wfew32b68c725c06a ...

Is there a way to save a Morris.js chart as a PDF file

I have successfully created a Morris.js Bar Chart using data from PHP and MySQL. Now, I am looking for a way to export this chart into a PDF format. I have attempted to do so using the FPDF library but I am struggling with the implementation. Can anyone ...

What could be causing the lack of updates to my component in this todo list?

Based on my understanding, invoking an action in MobX should trigger a rerender for the observer. However, when I call the handleSubmit method in my AddTask component, it doesn't cause the TaskList observer to rerender. Should I also wrap AddTask in a ...