DEV Community

Frank Etoundi
Frank Etoundi

Posted on

2 1

Resizing a div using CSS resize, but the resizing is done at a fixed dimension (snap grid)

TLDR; View the working example on jsfiddle.net

Let's create a solution that resizes a div at fixed 50px increments of its parent container, with smooth transitions, debouncing and ResizeObserver for monitoring.

HTML Setup:

<div class="container">
  <div class="resizable"></div>
</div>
Enter fullscreen mode Exit fullscreen mode

CSS Setup:

.container {
  width: 500px;
  height: 400px;
  border: 2px solid #ccc;
  position: relative;
  overflow: hidden;
}

.resizable {
  width: 250px;
  height: 200px;
  background: #3498db;
  position: absolute;
  resize: both; /* This enables the resizing */
  overflow: auto;
  min-width: 50px;
  min-height: 50px;
  max-width: 100%;
  max-height: 100%;
  transition: all 0.1s ease-out; /* This is important to ensure a smooth drag */
}
Enter fullscreen mode Exit fullscreen mode
  • resize: both enables resizing in both directions
  • transition: all 0.1s ease-out adds smooth transitions to reduce visual glitching
  • min-width/height: 10% and max-width/height: 100% set the boundaries
  • overflow: auto handles content overflow
  • Container has overflow: hidden to prevent content spilling

Javascript Setup:

const resizable = document.querySelector(".resizable")
const container = document.querySelector(".container")

const snapPercent = 20 // Change to fit your needs
const snapPixel = 50 // Change to fit your needs
const usePixels = false // Change this to false to use percentage.

// Function to snap to fixed pixels increments
function snapToGridPixel(size, parentSize) {
  const snappedSize = Math.round(size / snapPixel) * snapPixel
  const value = Math.max(snapPixel, Math.min(snappedSize, parentSize))
  return Math.min(value, parentSize) + "px"
}

// Function to snap to fixed percentage increments
function snapToGridPercentage(size, parentSize) {
  const percentage = (size / parentSize) * 100
  const snappedPercentage = Math.round(percentage / snapPercent) * snapPercent
  return Math.max(snapPercent, Math.min(100, snappedPercentage)) + "%"
}

function snapToGrid(size, parentSize) {
  return usePixels
    ? snapToGridPixel(size, parentSize)
    : snapToGridPercentage(size, parentSize)
}

// Debounce function
function debounce(func, delay) {
  let timeoutId
  return function (...args) {
    clearTimeout(timeoutId)
    timeoutId = setTimeout(() => {
      func.apply(this, args)
    }, delay)
  }
}

// Debounced resize handler
const handleResize = debounce((entries) => {
  for (let entry of entries) {
    const { width, height } = entry.contentRect
    const parentWidth = container.offsetWidth
    const parentHeight = container.offsetHeight

    // Snap to fixed increments
    const newWidth = snapToGrid(width, parentWidth)
    const newHeight = snapToGrid(height, parentHeight)

    // Apply the snapped sizes with max bounds
    resizable.style.width = newWidth
    resizable.style.height = newHeight
  }
}, 100) // 100ms delay

// ResizeObserver with debounced handler
const resizeObserver = new ResizeObserver(handleResize)

// Start observing the resizable element
resizeObserver.observe(resizable)
Enter fullscreen mode Exit fullscreen mode

Let's break down the key components:

JavaScript with ResizeObserver:

  • snapToGrid function calculates the nearest 10% increment
  • Converts current size to percentage of parent
  • Rounds to nearest 20% using Math.round(percentage / 20) * 20
  • Clamps values between 20% and 100%
  • ResizeObserver continuously monitors size changes and applies snapping

The ResizeObserver ensures that whenever the user resizes the div, it immediately snaps to the nearest 10% increment, while the CSS transition makes the snapping motion smooth rather than instantaneous.

Debouncing

Debouncing ensures that a function only runs after a certain period of inactivity. It delays execution until after the triggering event has stopped firing for a specified amount of time.

Why Use Debouncing?

  • Performance: Prevents excessive function calls that could slow down your application
  • Efficiency: Reduces unnecessary computations or API calls
  • User Experience: Ensures actions complete only when the user has finished interacting

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more