Vertical Dragging Division of Space

I am looking to create a draggable division that separates two areas vertically, similar to the images below: https://i.sstatic.net/AC9Gt.pnghttps://i.sstatic.net/xA4cX.png

I found an online example of draggable divs and customized it to suit my needs. I managed to modify it as desired. Can anyone provide some tips on how to further tailor it?


JSFiddle Link : https://jsfiddle.net/casperhongkong/omekvtka/14/


HTML

<div class="container">
  <div class="area1">
Area 1
  </div>
  <div class="drag">

  </div>
  <div class="area2">
Area 2
  </div>
</div>

CSS

.container {
  position: fixed;
  top: 51px;
  right: 0px;
  bottom: 0px;
  left: 0px;
  background-color: #272822;
  border: 1px solid #222;
 // margin: 0 auto;
  //display: inline-block;
}

.area1 {
  position: absolute;
  height: 100%;
  width: 30%;
  background-color: #ddd;
  display: inline-block;
}

.drag {
  position: fixed;

  width: 5px;
  height: 100%;
  background-color: #444;
  display: inline-block;
}

.area2 {
  position: absolute;
  right: 0;
  height: 100%;
  width: 30%;
  background-color: #ddd;
  display: inline-block;
}

JavaScript

$(document).ready(function() {

  $('.drag').on('mousedown', function(e) {
    var $area1 = $('.area1'),
        $area2 = $('.area2'),
        startWidth_a1 = $area1.width(),
        startWidth_a2 = $area2.width(),
        pX = e.pageX;

    $(document).on('mouseup', function(e) {
      $(document).off('mouseup').off('mousemove');
    });

    $(document).on('mousemove', function(me) {
      var mx = (me.pageX - pX);
      $area1.css({
        width: startWidth_a1 - mx;
      });
      $area2.css({
        //left: mx / 2,
        width: startWidth_a2 - mx,
        //top: my
      });
    });

  });
});

Answer №1

If you're looking to implement this functionality in JavaScript, I suggest using a library as it can be more complex than a few lines of code. @fauxserious recommended Split.js as an excellent option.

While it is possible to achieve this with pure HTML/CSS, there are some limitations as discussed here.

HTML:

<div class="split-view">
    <div class="resize-x panel" style="width: 216px;">
      Panel A
    </div>
    <div class="panel">
      Panel B
    </div>
</div>

CSS:

/* Panels: */
.panel{ 
    padding: 1em; 
    border-width: 6px; 
    border-style: solid; 
    height: 4em; 
}

/* Resizing */
.resize-x { 
    resize: horizontal;
    overflow: auto;
}

/* Split View */
.split-view {
    margin: 1em 0; 
    width: 100%;
    clear: both;
    display: table;
}

.split-view .panel {
    display: table-cell;
}

Answer №2

After studying @afischer's table-cell method, I discovered an innovative approach.
To integrate accordions into the left side panel, some adjustments were necessary.

The sticky headers within the accordions demanded overflow visibility,
while resize functionality required anything but visible overflow:
https://caniuse.com/#feat=css-sticky.

Simultaneously, no elements were needed in the right side panel.

As a solution, I utilized resize on the right panel and rotated it by 180 degrees to position the draggable side towards the center, moving the draggable corner to the top (visible without scrolling).

Additionally, I added highlighting to the draggable corner.

/* Panels: */
.panel{ 
  padding: 1em; 
  border-width: 6px; 
  border-style: solid; 
  height: 4em; 
}

/* Resizing */
.resize-x { 
  resize: horizontal;
  overflow: auto;
  transform: rotate(180deg);
  border-right: solid gray 1px;
}

/* Split View */
.split-view {
  margin: 1em 0; 
  width: 100%;
  clear: both;
  display: table;
}

.split-view .panel {
  display: table-cell;
}

.resize-x::-webkit-resizer {
    border-width: 8px;
    border-style: solid;
    border-color: transparent orangered orangered transparent;
  }
<div class="split-view">
    <div
      class="panel"
      style="width: 216px;">
        Panel A
    </div>
    <div class="panel resize-x">
      Panel B
    </div>
</div>

Unfortunately, two issues arose with the above setup:

  • Firefox was unable to handle the combination of table-cell and resize
  • Only a small portion of the grabber was responsive, making it easy to scroll out

Here is another solution that addresses these problems:

  • No usage of the resize CSS property
  • Full-height responsive grabber

This solution combines a flexbox layout with an input range slider.

The key is utilizing different pointer-event values on the slider's background and grabber:

  • The slider spans the entire view, with its background set as transparent for events (pointer-events: none), while the drag bar itself captures events (pointer-events: auto).

It involves minimal Javascript, and since I have implemented the production version in Nuxt.js, I chose to use Vue.js here instead of vanilla JS.

new Vue({
        el: '#vue',

        data: {
          windowWidth: null,
          splitWidth: null,
        },

        mounted() {
          this.windowWidth = window.innerWidth;
          // For arbitrary initial position:
          this.splitWidth = this.windowWidth * 2/3;
        },

        computed: {
          flexRatio() {
            return this.splitWidth / this.windowWidth;
          }
        }

      })
body {
        margin:0;
      }

      main {
        display: flex;
        width: 100%;
        height: 100vh;
      }

      article {
        display: flex;
      }

      section {
        width: 100%;
        height: 100%;
        text-align: justify;
        padding: 20px;
      }

      .section-left {
        background-color: darkseagreen;
      }

      .section-right {
        background-color: orangered;
      }

      #split-grabber {
        pointer-events: none;
        position: fixed;
        top: 0; right: 0; bottom: 0; left: 0;
        -webkit-appearance: none;
      /* Safari allows dragging behind scroll bar.
        We fix it by shrinking its width on the right side via both
        its range value      :max="windowWidth - 12"
        and its width (CSS)   width: calc(100% - 12px)
        ...synchronously  */
        width: calc(100% - 12px);
        height: 100vh;
        background: transparent;
        outline: none;
        margin: 0;
      }

      #split-grabber::-webkit-slider-thumb {
        z-index: 1;
        pointer-events: auto;
        -webkit-appearance: none;
        appearance: none;
        width: 5px;
        height: 100vh;
        background: lightgray;
        box-shadow: 1px 2px 2px 0px gray;
        cursor: col-resize;
      }

      #split-grabber::-moz-range-thumb {
        z-index: 1;
        pointer-events: auto;
        -webkit-appearance: none;
        appearance: none;
        width: 5px;
        height: 100vh;
        background: lightgray;
        box-shadow: 1px 2px 2px 0px gray;
        cursor: col-resize;
      }
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<main id="vue">
      <!-- Safari allows dragging behind scroll bar
      We fix it by shrinking its width on the right side via both
      its range value      :max="windowWidth - 12"
      and its width (CSS)   width: calc(100% - 12px)
      ...synchronously  -->
      <input
        id="split-grabber"
        type="range" 
        v-model="splitWidth"
        :max="windowWidth - 12"
      >
      <article
      class="article"
      :style="{'flex': flexRatio}"
      >
        <section
        class="section section-left">
          splitWidth:{{ splitWidth }}px<br>
          “There was a rich man who always dressed in the finest clothes and lived in luxury every day.
          And a very poor man named Lazarus, whose body was covered with sores, was laid at the rich man’s gate.
          He wanted to eat only the small pieces of food that fell from the rich man’s table. And the dogs would come and lick his sores.
          Later, Lazarus died, and the angels carried him to the arms of Abraham. The rich man died, too, and was buried.
          In the place of the dead, he was in much pain. The rich man saw Abraham far away with Lazarus at his side.
          He called, ‘Father Abraham, have mercy on me! Send Lazarus to dip his finger in water and cool my tongue, because I am suffering in this fire!’
        </section>  
      </article>
      <article
        class="article"
        :style="{'flex': 1-flexRatio}"  
      >
        <section class="section section-right">
          But Abraham said, ‘Child, remember when you were alive you had the good things in life, but bad things happened to Lazarus. Now he is comforted here, and you are suffering.
          Besides, there is a big pit between you and us, so no one can cross over to you, and no one can leave there and come here.’
          The rich man said, ‘Father, then please send Lazarus to my father’s house.
          I have five brothers, and Lazarus could warn them so that they will not come to this place of pain.’
          But Abraham said, ‘They have the law of Moses and the writings of the prophets; let them learn from them.’
          The rich man said, ‘No, father Abraham! If someone goes to them from the dead, they would believe and change their hearts and lives.’
          But Abraham said to him, ‘If they will not listen to Moses and the prophets, they will not listen to someone who comes back from the dead.’”        
        </section>
      </article>
    </main>

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

What could be the reason my jQuery IF statement is not functioning properly?

I have a basic IF statement set up to change the background color of a div when true. $(".inner").click(function(){ console.log($(this).css('background-color')); if($(this).css('background-col ...

Tips for keeping a div visible while hovering over a link using only CSS

Apologies for any language errors in advance. I will do my best to explain my issue accurately: In my CSS, I have created a hidden div that is displayed none by default. When I hover over a link in the navigation bar, I change the display to block, creati ...

Embed jQuery in the Meteor server-side code

During my search, I came across the following links: https://groups.google.com/forum/#!topic/meteor-core/ZlPPrH7SqrE Server-side jquery How can one parse HTML server-side with Meteor? Despite my efforts, I have not yet found a way to incorporate jQuery ...

Tips for emphasizing active tabs in Angular 6

**I have everything displaying perfectly, but I am wondering how to highlight the active tab without using any third-party components. Any assistance would be greatly appreciated. Thank you.** <ul class="tabs"> <li [ngClass]=" {'active-tab ...

"Encountering issues with createReadStream function when handling large files, performance is significantly

Currently, I am utilizing the DropBox API for file uploads. The process involves several steps: Begin by uploading the file from a form to a local directory on the server. Read the file from the local directory using fs.createReadStream. Transfer the fil ...

Compel the browser to launch a fresh tab

I'm currently working on an app that involves uploading files. One issue I'm facing is that the file system pop up doesn't close after the upload, causing a quarter of the screen to be covered while the test keeps running in the background. ...

Different ways to update background hues in Reactstrap

I am currently working on styling an application with reactstrap, and I'm facing a challenge in changing the background color of the navigation bar from white to black. I tried setting the color attribute to "dark" in the nav tabs tag, but it didn&apo ...

Finding an element that lacks both a class and an id, and is not consistently present - what's the trick?

Currently, I am faced with a predicament in my code where a <li> element only appears under specific conditions, making it difficult to apply positioning. This element lacks an id and class attribute, which prevents me from targeting it accurately us ...

How can you use CSS to style an image's title attribute?

I am trying to customize the text displayed when hovering over an image. Despite my efforts, the code I used doesn't seem to be working properly: <body> <img src="img.jpg" title="<span class='title'>title</span>" &g ...

Reasons for dividing by 1 in JavaScript

While completing a basic programming assignment from my teacher, I encountered an interesting issue in Javascript. I found that when dividing a number by 1, it returns an unexpected value. Can anyone provide an explanation for this? I have created a jsfidd ...

The method for organizing boxes on the stack exchange website's list page

I can't help but wonder about a unique and innovative feature on this stackexchange page that showcases all the stackexchange sites in a grid layout. Upon clicking on a site box, it expands in size while the surrounding boxes adjust their positions t ...

Is it necessary to remove event bindings and disable plugins before navigating away from a page in Jquery Mobile or Jquery?

I've incorporated multiple plugins into a Jquery Mobile website and am searching for the most effective method to "tidy up" when transitioning away from a page that remains in the DOM. The question at hand is whether I should attempt to unbind/off/un ...

Drawing an image on an Ionic 4 canvas using the drawImage method, following a change

I've been working on an app that displays an image on a canvas, with the image source coming from the parent page. Everything seems to be functioning correctly, but when I try changing the imageSrc via a button click, the canvas ends up blank. Oddly ...

Content Security Policy in Firefox Extension blocking local DataTables js

After downloading the js for DataTables, I attempted to load it onto my Firefox extension but encountered a Content Security Policy block: Content Security Policy: The page’s settings blocked the loading of a resource at self (“default-src moz-ext ...

Creating a Vue single-page application (SPA) and concealing the .vue files upon rendering in the

I have a Single Page App built using Vue.js and hosted on a node.js server. While the app is still in development, it will eventually be accessed by external customers. Due to the sensitive data involved, we want to prevent users from seeing the .vue files ...

The code, which is the same, placed in a different location on another page - fails to function

On the index.php page, I have successfully implemented the following code snippet at the bottom: <script type='text/javascript'> $("#tbAlegro").click(function() { window.location = 'alegro.php'; }); </script> However, ...

Avoid loading the background image by utilizing CSS to set the background image

Whenever I attempt to assign a background image using CSS, it triggers a console error. This is my CSS code: body { background-image: url("background.png"); background-repeat: no-repeat; } The error message displayed is: GET http://localhost/myWeb/ ...

Learn the process of appending an item to a list using Vue.js

Recently starting with vue.js and facing an issue: data: { ws: null, newMsg: '', username: null, usersList: '' }, created: function() { var self = this; this.ws = new We ...

Designs created using ASCII characters in HTML that are not under my control

Hey there! I've been attempting to incorporate some ASCII art onto a website that I don't have control over. When I input text into their editor, it is then enveloped in <p> tags which makes adding ASCII art quite challenging. Firstly, I ca ...

Switch up the CSS file based on the URL route

My project consists of the following files: App.vue, changcolor.vue, config.json, main.js, index.html, xyz.css, abc.css. I need a solution where based on the URL, the appropriate CSS file is applied. For instance, if the URL is "xyz.local.com" then xyz.cs ...