Adjust the size of two sections using a slider to modify their width proportions

I am currently working on designing a component that allows for adjusting the width proportions of two blocks by using a slider to move them left and right: https://i.sstatic.net/Q85ab.png

Check out the CodePen and demo.

.outer {
  display: flex;
  flex-direction: row;
}

.block {
  height: 200px;
  width: -webkit-calc(50% - 5px);
  width: -moz-calc(50% - 5px);
  width: calc(50% - 5px);
}

.block-1 {
  background-color: red;
}

.block-2 {
  background-color: green;
}

.slider {
  line-height: 100%;
  width: 10px;
  background-color: #dee2e6;
  border: none;
  cursor: e-resize;
}
<div id="app">
  <div class="outer">
    <div class="block block-1">
      Block 1
    </div>
    <div class="slider">
      S<br>l<br>i<br>d<br>e<br>r
    </div>
    <div class="block block-2">
      Block 2
    </div>
  </div>
</div>

I've attempted utilizing the draggable-vue-directive to change the block widths based on the slider's position.

Unfortunately, it didn't work as expected because the draggable-vue-directive set the slider to position:fixed, causing alignment issues with the blocks.

How can I enable horizontal dragging for the .slider block without using position:fixed?

What is the correct way to resize Block1 and Block2 when the slider is moved?

Please note: I am not using jQuery

Answer №1

Modify your flexbox in conjunction with resize - the drawback being that the level of customization for the slider is limited:

  • Include resize: horizontal to one of the flex items
  • Add flex: 1 to the other flex item (so that this flex item automatically adjusts in response to the changing width of the other flex item as it is resized)

View demo below:

.outer {
  display: flex;
  flex-direction: row;
}

.block {
  height: 100px;
  width: 50%; /* 50% would suffice*/
}

.block-1 {
  background-color: red;
  resize: horizontal; /* resize horizontal */
  overflow: hidden; /* resize works for overflow other than visible */
}

.block-2 {
  background-color: green;
  flex: 1; /* adjust automatically */
}
<div id="app">
  <div class="outer">
    <div class="block block-1">
      Block 1
    </div>
    <div class="block block-2">
      Block 2
    </div>
  </div>
</div>


To tackle this without relying on the resize approach mentioned above, let's utilize vanilla JS:

  • Implement a mousedown listener that tracks a mousemove listener updating the width of block-1 (and resetting the mouseup event)
  • Consider adding min-width: 0 to override min-width: auto of the block-2 element

View demo below:

let block = document.querySelector(".block-1"),
  slider = document.querySelector(".slider");

slider.onmousedown = function dragMouseDown(e) {
  let dragX = e.clientX;
  document.onmousemove = function onMouseMove(e) {
    block.style.width = block.offsetWidth + e.clientX - dragX + "px";
    dragX = e.clientX;
  }
  // remove mouse-move listener on mouse-up
  document.onmouseup = () => document.onmousemove = document.onmouseup = null;
}
.outer {
  display: flex;
  flex-direction: row;
}

.block {
  height: 100px;
  width: 50%; /* 50% would suffice*/
}

.block-1 {
  background-color: red;
}

.block-2 {
  background-color: green;
  flex: 1; /* adjust automatically */
  min-width: 0; /* allow flexing beyond auto width */
  overflow: hidden; /* hide overflow on small width */
}

.slider {
  line-height: 100%;
  width: 10px;
  background-color: #dee2e6;
  border: none;
  cursor: col-resize;
  user-select: none; /* disable selection */
  text-align: center;
}
<div id="app">
  <div class="outer">
    <div class="block block-1">
      Block 1
    </div>
    <div class="slider">
      S<br>l<br>i<br>d<br>e<br>r
    </div>
    <div class="block block-2">
      Block 2
    </div>
  </div>
</div>


Solution

You can easily adapt the above into Vue without any custom Vue plugins - here are the modifications:

  • @mousedown listener on slider which triggers the slider

  • utilization of refs to update the width of block-1

View demo below:

new Vue({
  el: '#app',
  data: {
    block1W: '50%'
  },
  methods: {
    drag: function(e) {
      let dragX = e.clientX;
      let block = this.$refs.block1;
      document.onmousemove = function onMouseMove(e) {
        block.style.width = block.offsetWidth + e.clientX - dragX + "px";
        dragX = e.clientX;
      }
      // remove mouse-move listener on mouse-up
      document.onmouseup = () => document.onmousemove = document.onmouseup = null;
    }
  }
});
.outer {
  display: flex;
  flex-direction: row;
}

.block {
  height: 100px;
  width: 50%; /* 50% would suffice*/
}

.block-1 {
  background-color: red;
}

.block-2 {
  background-color: green;
  flex: 1; /* adjust automatically */
  min-width: 0; /* allow flexing beyond auto width */
  overflow: hidden; /* hide overflow on small width */
}

.slider {
  line-height: 100%;
  width: 10px;
  background-color: #dee2e6;
  border: none;
  cursor: col-resize;
  user-select: none; /* disable selection */
  text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <div class="outer">
    <div class="block block-1" ref="block1" :style="{'width': block1W}">
      Block 1
    </div>
    <div class="slider" @mousedown="drag">
      S<br>l<br>i<br>d<br>e<br>r
    </div>
    <div class="block block-2">
      Block 2
    </div>
  </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

changing a Vue.js boolean value through a template

Out of necessity (don't inquire further), I find myself resetting a variable in VueJS through a template. So, here's what it looks like in my VueJS code: const someApp = new Vue({ delimiters: ['[[', ']]'], el: '#some-app ...

Exploring Angular and Node.js to Retrieve Image Dimensions

I'm struggling to figure out the most effective method for determining the image dimensions or naturalWidth of images based on their URL, usually found in the src attribute of an <img> tag. My objective is to input a URL of a news article and u ...

(Display a loading animation while resolving in Angular-ui-router)

Here is a two part inquiry: When utilizing the resolve property within $stateProvider.state() to retrieve specific server data before controller loading, is there a method to display a loading animation during this process? I am facing an issue wit ...

Navigating a complex web: Djikstra algorithm applied to a multigraph

Encountering an issue while implementing Dijkstra's algorithm on a multigraph. The graph consists of nodes representing stops with information and connections to other stops (edges). However, the challenge arises when there are multiple bus options be ...

Bootstrap datetimepicker is not showing the calendar for selecting a date, making it impossible to choose a specific date

I am facing an issue with integrating the bootstrap datetimepicker with Datatables to filter the data based on selected dates. The problem is that only an input bar is displayed on the page, and there is no calendar or calendar symbol visible. I suspect it ...

Solutions for organizing backend data arrays by date and month

I'm currently in the process of developing a MERN-based animal shelter web app, and I'm facing challenges with grouping data by date month. Here's the schema I am using for the rescued date: const animalSchema = new mongoose.Schema({ date ...

Gridlines Collapse upon Rendering in the Griddle Subgrids

Griddle has the capability to support subgrids. In one of the fields, I have a customized component for row selection that triggers a state change. This state change leads to a re-rendering of the component, causing the collapse of the subgrid. However, I ...

Creating a responsive and expandable table using HTML and JavaScript

I need help with making my html table resizable in a vertical direction. The cells can overflow if there isn't enough space, so I want to allow users to stretch the table by dragging and extending the bottom edge. Can anyone provide guidance on how to ...

``Trouble with React Dropdown menu option selection"

I am encountering challenges with implementing a dropdown menu list for my react app. The issue at hand is that I have an API where one of the keys (key3) has values separated by commas that I wish to display in my dropdown list. The structure of the API ...

Disable button not necessary when validating checkboxes

I'm working on a simple function that involves 3 checkboxes. The goal is to disable the button if all checkboxes are unchecked, and enable it only when all three checkboxes are checked. function checkAll() { var checkbox1 = document.getElem ...

The image link in HTML and CSS is no longer functioning properly following the relocation of the image

I am having an issue with positioning my image under my name on my website. When I try to move the image down, the link no longer works properly. Interestingly, moving the image left or right does not cause any issues. It's only when trying to move it ...

Utilizing a callback within a conditional statement in VueJS: A step-by-step guide

Trying to customize focus styling in vueJS has been a challenge for me. I found a function that identifies the focused element, but integrating it into conditional rendering proved difficult. As a workaround, I attempted to use a callback, but I'm str ...

Highlighted text with CSS

For this exercise, I was provided with the following HTML code: <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Selected text</title> </head> <body> <div class ...

Unlock the power of two-way data binding in Vuex using the mapGetter helper

Understanding how Vuex utilizes two-way data binding involves using set() and get() methods on the computed property of the component. This means returning the store state or relevant getter in the get() method, then committing a mutation in the set method ...

What is the best way to receive the result of an asynchronous function as an input and showcase it using express?

I have recently started learning about node and express My goal is to create an API that can fetch data from an external source and use that data for my application Is there a way to retrieve the result of an asynchronous method and display it using the ...

Is it possible to protect assets aside from JavaScript in Nodewebkit?

After coming across a post about securing the source code in a node-webkit desktop application on Stack Overflow, I began contemplating ways to safeguard my font files. Would using a snapshot approach, similar to the one mentioned in the post, be a viable ...

When a button is clicked, the v-bind class is no longer applied

Recently, I encountered a puzzling issue that has left me scratching my head. When I pass the class name as a prop to the child component and click the button, all layout styling is lost. However, this problem doesn't occur when I hardcode the class n ...

How to use AngularJS to parse JSON containing backslashes

Here is the JSON data stored in $scope.projectData: [{ "\"Space\"": "\"L1 (1 floor)\"", "\"Subject\"": "\"Corridor Distance\"", "\"Label\"": "\"Corridor Distance\"", "\"Color&bso ...

My function invocations seem to be malfunctioning

Originally, I wrote code without using functions to prototype and it worked perfectly fine: $(function() { $(".PortfolioFade img") .mouseover(function() { popup('PORTFOLIO'); var src = $(this).attr("src").rep ...

Tips on resolving the issue of passing a string value as a number in a JS function parameter when working with

In my application, I am utilizing both AngularJS and Bootstrap 4 Accordion elements. Within each card of the accordion, there is system information displayed which includes a version number pulled from a systemData object array using ng-repeat. The version ...