最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Can I change the design of the textarea resize handle in CSS? - Stack Overflow

programmeradmin4浏览0评论

Normally, the textarea can be resized both ways by dragging a little triangular handle in the bottom right corner. Once I disable horizontal resizing by setting textarea { resize: vertical; }, the textarea can only be resized up or down while dragging the same little triangle-shaped handle. But it doesn't seem very intuitive as the trianglular handle suggests that I should be able to resize the textarea along both axes.

I noticed that StackOverflow has a modified resize handle on this very textarea I am typing my question into. It intuitively implies only vertical resizing and it looks cute. If you click Ask Question, you will see it at the bottom of the textarea box. My guess is it is modified using jQuery. But can the looks of the resize handle be changed using simple CSS?

Normally, the textarea can be resized both ways by dragging a little triangular handle in the bottom right corner. Once I disable horizontal resizing by setting textarea { resize: vertical; }, the textarea can only be resized up or down while dragging the same little triangle-shaped handle. But it doesn't seem very intuitive as the trianglular handle suggests that I should be able to resize the textarea along both axes.

I noticed that StackOverflow has a modified resize handle on this very textarea I am typing my question into. It intuitively implies only vertical resizing and it looks cute. If you click Ask Question, you will see it at the bottom of the textarea box. My guess is it is modified using jQuery. But can the looks of the resize handle be changed using simple CSS?

Share Improve this question edited Mar 8, 2022 at 14:25 isherwood 61.2k16 gold badges121 silver badges170 bronze badges asked Apr 20, 2016 at 13:10 Arthur TarasovArthur Tarasov 3,8119 gold badges50 silver badges60 bronze badges 4
  • it's just a guess but I think they removed the handle and created their own.. From what I know you can't modify the default one since that is browser specific. – Spluf Commented Apr 20, 2016 at 13:13
  • 2 I've just discovered that trying to right click the Stack Overflow rezise control is incredibly frustrating! – James Donnelly Commented Apr 20, 2016 at 13:18
  • 1 kindly check jsfiddle/m81wkfe7 and replace the image and adjust the position as per your need – RRR Commented Apr 20, 2016 at 14:33
  • A simple solution: stackoverflow./a/63398119/1405507 – Rich Commented Aug 14, 2020 at 8:11
Add a ment  | 

2 Answers 2

Reset to default 3

Actually, the HTML part for SO answer textarea is:

<div class="wmd-container">
    <div class="wmd-button-bar" id="wmd-button-bar"> .... </div>
    <textarea data-min-length="" tabindex="101" rows="15" cols="92" name="post-text" class="wmd-input processed" id="wmd-input"></textarea>
    <div class="grippie" style="margin-right: 0px;"></div>
</div>

The div .grippie is just a SVG image with an handler set to listen on your click&drag action, using the cursor offset in height to set the height of the textarea dinamically.

Check this if you want to know more about it

This is not pure CSS, but vanilla JavaScript function for making any textarea vertically resizable by dragging the bottom edge.

// make textareas resizable by dragging the bottom edge
 
function init_textareas() {
  use_bottom_edge(document.getElementById("nonlorem"));
  use_bottom_edge(document.getElementById("abitlorem"));
  use_bottom_edge(document.getElementById("morelorem"));
}

var mouseup_listener = null;
var mousemove_listener = null;
var onresize_listener = null;

var initial_y_ergo_resizing = null;
var initial_height = null;
var extra = 0;

function use_bottom_edge(target_ta) {
  resize = document.createElement("SPAN");
  resize.classList.add("resize");
  target_ta.parentNode.insertBefore(resize, target_ta.nextSibling);
  target_ta.classList.add("resizeTarget");
  target_ta.style.resize="vertical"; // try "none" to remove handle
  cs = getComputedStyle(target_ta);
  extra = 3 + (parseFloat(cs.getPropertyValue('margin-bottom')) + parseFloat(cs.getPropertyValue('padding-bottom')))/2;
  resize.style.top = target_ta.offsetTop + target_ta.getBoundingClientRect().height - extra + 'px';
  resize.addEventListener('mousedown', resize_onmousedown);
  resize.addEventListener('pointerdown', resize_onpointerdown);
  
  if (mouseup_listener == null) 
    document.addEventListener('mouseup', mouseup_listener=resize_onmouseup);
  if (mousemove_listener == null)
    document.addEventListener('mousemove', mousemove_listener=resize_onmousemove);
  if (onresize_listener == null)
    window.addEventListener('resize', onresize_listener=position_all_resizers);
}

function resize_onmousedown(e) {
  e.preventDefault();
  target_ta = e.target.previousSibling;
  initial_y_ergo_resizing = e.pageY;
  initial_height = target_ta.getBoundingClientRect().height;
}

function resize_onpointerdown(e) {
  e.target.setPointerCapture(e.pointerId);
}

function resize_onmousemove(e) {
  if (initial_y_ergo_resizing != null) {
    e.preventDefault();
    resize = e.target;
    target_ta = resize.previousSibling;
    current_height = initial_height + e.pageY - initial_y_ergo_resizing - 2*extra;
    if (current_height > 20) {
      target_ta.style.height = current_height + "px";
      resize.style.top = target_ta.offsetTop + target_ta.getBoundingClientRect().height - extra + 'px';
    }
  }
}

function resize_onmouseup(e) {
  if (e.target.classList.contains("resize")) {
    e.preventDefault();
    initial_y_ergo_resizing = null;
    position_all_resizers();
  } else if (e.target.classList.contains("resizeTarget")) {
    position_all_resizers();
  }
}

function position_all_resizers() {
  resize_array = document.getElementsByClassName("resize");
  for (resize of resize_array) {
    target_ta = resize.previousSibling;
    if (target_ta.offsetParent != null) {
      resize.style.top = target_ta.offsetTop + target_ta.getBoundingClientRect().height - extra + 'px';
      resize.style.display = "block";
    } else {
      resize.style.display = "none";
    }
  }
}
.resize, .resize:hover {
  cursor: ns-resize;
  width: 100%;
  height: 7px;
  background-color: transparent; /* try "red" for ghost bars */
  position: absolute;
  display: block;
  opacity: 0.3;
}

p {
  position: relative; /* to keep bars attached to textarea */
  float: left;
  clear: both;
}
<body onload="init_textareas()">
<p><textarea id="nonlorem">This is lorem ipsum free textarea.</textarea></p>
<p><textarea id="abitlorem">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</textarea></p>
<p><textarea id="morelorem">Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea modo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</textarea></p>
</body>

I simply add absolute positioned transparent "ghost bar" after each textarea, change mouse pointer on hover, lock it on mouse down and use mouse listeners to modify the size of textarea according to change of y-axis value. Since there can be more than one textarea, on page layout changes I have to go through all of them and modify positions of ghost bars.

There is some trickery in exactly positioning the ghost bars and I presume they always e in pairs with a textarea, so I can use nextSibling/previousSibling to address them. The code also supports adding ghost bars to textareas that are currently not visible (in collapsed region of the page, for example). I personally like keeping the handle in the bottom right corner as an indicator that textarea can be resized. In practice one quite quickly realizes from mouse cursor changes, that whole bottom edge can be used as resize handle.

You can find similar JavaScript solution with touch support and styled handle here.

发布评论

评论列表(0)

  1. 暂无评论