web-dev-qa-db-fra.com

CSS Textarea qui s’agrandit au fur et à mesure que vous tapez du texte

J'ai un Textarea où les utilisateurs peuvent saisir du texte. Par défaut, il a une hauteur de 17px. Toutefois, si les utilisateurs insèrent une grande quantité de texte, je souhaite que la zone de texte s’agrandisse en conséquence. Est-il possible de faire cela avec CSS? Merci d'avance!!

37
Spencer

Cela ne peut pas être fait avec CSS seul. essayez le plugin jogery autogrow. https://github.com/jaz303/jquery-grab-bag/blob/master/javascripts/jquery.autogrow-textarea.js

Vous pouvez également voir la démo d’autogrow ici http://onehackoranother.com/projects/jquery/jquery-grab-bag/autogrow-textarea.html

Il est léger et facile à utiliser. Voici comment c'est fait. Définissez votre identifiant textarea. Incluez le fichier jquery js avant </body>. Ensuite, entre les balises de script, lancez la commande jquery $("#txtInput").autoGrow();

<body>
    <textarea id="txtInput"></textarea>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript"></script> 

<script>
    $("#txtInput").autogrow();
</script>
</body>
23
Hussein

Ce plugin jQuery est vraiment génial: http://www.jacklmoore.com/autosize

J'ai testé plusieurs d'entre elles et c'est de loin le meilleur. Donne également un exemple d'utilisation d'un effet de transition CSS assez lisse.

20
sirkitree

** Notez que ceci est très similaire à la réponse de Woody ci-dessus, mais voulait développer un peu plus et fournir un exemple de code en cours d'exécution maintenant que Stack nous permet de les intégrer.

Après avoir lu tout cela et essayé quelques plugins, j'ai trouvé que tout cela ne fonctionnait pas comme je l'avais espéré. J'ai fait ce qui suit - il y a un léger tremblement en haut du champ lorsque vous faites défiler avant qu'il ne se développe, mais cela fonctionne pour moi. J'ai utilisé jquery, mais je peux le faire avec javascript tout aussi facilement en récupérant les valeurs de remplissage au lieu d'utiliser la hauteur intérieure:

  • Définir une hauteur minimale sur la zone de texte en css
  • Définissez overflow sur hidden pour le défilement vertical (je voulais simplement développer verticalement)
  • Définissez la hauteur sur la hauteur de défilement sans rembourrage sur chaque événement keyup si la hauteur de défilement est supérieure à hauteur + hauteur (innerHeight).
  • Si la hauteur de défilement n'était pas plus grande, je redéfinis la hauteur sur 1, puis sur la hauteur de défilement sans rembourrage (pour réduire la hauteur). Si vous ne réglez pas initialement une hauteur inférieure, la hauteur de défilement ne sera pas réduite.

$(function() {
  $('#myTextArea').on('keyup paste', function() {
    var $el = $(this),
        offset = $el.innerHeight() - $el.height();

    if ($el.innerHeight < this.scrollHeight) {
      //Grow the field if scroll height is smaller
      $el.height(this.scrollHeight - offset);
    } else {
      //Shrink the field and then re-set it to the scroll height in case it needs to shrink
      $el.height(1);
      $el.height(this.scrollHeight - offset);
    }
  });
});
#myTextArea {
  width: 250px;
  min-height: 35px;
  overflow-y: hidden;
}
<script src="https://code.jquery.com/jquery-2.2.3.min.js"></script>
<textarea id="myTextArea" placeholder="Hit enter a few times, it should expand"></textarea>

15
Stephen Tremaine

Vous n'avez pas besoin d'un plugin pour cela. Cela fonctionne sur les zones de texte de toute taille, hauteur ou taille de ligne et ne fonctionne que lorsque le contenu dépasse la zone de texte. Tout d'abord, définissez le débordement de votre zone de texte cible sur masqué et redimensionnez à zéro, puis ajoutez les fonctionnalités suivantes à la zone de texte que vous souhaitez diffuser automatiquement. Non seulement cela augmentera la taille de textarea au fur et à mesure que l'utilisateur le tape, mais il le réduira aussi automatiquement lorsqu'il supprimera des éléments.

$('textarea').on('paste input', function () {
    if ($(this).outerHeight() > this.scrollHeight){
        $(this).height(1)
    }
    while ($(this).outerHeight() < this.scrollHeight + parseFloat($(this).css("borderTopWidth")) + parseFloat($(this).css("borderBottomWidth"))){
        $(this).height($(this).height() + 1)
    }
});

Cela fonctionne en mesurant si la hauteur de défilement de la zone de texte est plus grande que la hauteur extérieure, ce qui ne le sera que s’il ya plus de texte que la zone de texte ne peut en contenir - et elle prend en compte la taille de la bordure pour une plus grande précision. L'utilisation de coller et saisir signifie que cela augmentera uniquement lorsque l'utilisateur modifiera physiquement la valeur de la zone de texte, par opposition à une pression sur une touche. C'est maigre, mais une zone de texte ne devrait pas augmenter lorsque quelqu'un appuie sur une touche fléchée ou quelque chose du genre.

Il serait peut-être prudent d'ajouter une option No JS qui réactive le débordement et le redimensionnement pour ceux qui ne disposent pas de Javascript, sinon ils seront bloqués avec une petite boîte.

12
Woody Payne

Je sais que c'est un peu tard, mais je dois dire qu'il existe un moyen d'utiliser <div> avec l'attribut contenteditable pour simuler le comportement souhaité.

.textareaElement {
  width: 300px;
  min-height: 17px;
  border: 1px solid #ccc;
  max-height: 150px;
  overflow-x: hidden;
  overflow-y: auto;
}
<div class="textareaElement" contenteditable></div>

Il suffit de définir votre hauteur minimale et maximale, avec les valeurs de dépassement appropriées, et vous avez une zone de texte extensible CSS entièrement fonctionnelle, qui est également bien supportée.

 enter image description here

10
Moo

Utilisez JavaScript pour cela.

Ce script vérifie la longueur de la zone de texte après chaque frappe de touche (copypasta from here ):

  <textarea name="x" onKeyUp="SetNewSize(this);" cols="5" rows="4"></textarea>
    <script language="javascript">
    function SetNewSize(textarea){
      if (textarea.value.length > 5){
        textarea.cols = 50;
        textarea.rows = 50;
      }  else{
         textarea.cols = 10;
         textarea.rows = 15;
      }
    }
  </script>
4
Nikita Barsukov

Cela semble être beaucoup plus efficace et gère la hauteur maximale

$(ctrl).on('paste input', function () {
    var dyLineHeight, dyMax, dyHeight;        
    if ($(this).outerHeight() > this.scrollHeight)
        $(this).height($(this).outerHeight() - parseFloat($(this).css("borderBottomWidth")) - parseFloat($(this).css("borderTopWidth")));
    dyLineHeight = Math.max(3, parseInt($(this).css("line-height")));
    dyMax = parseInt($(this).css("max-height"));
    while ($(this).outerHeight() < this.scrollHeight + parseFloat($(this).css("borderTopWidth")) + parseFloat($(this).css("borderBottomWidth")))
        {
        dyHeight = $(this).height();
        if (dyHeight >= dyMax)
            break;
        $(this).height(dyHeight + dyLineHeight)
        }
});
1
Glenn Kreisel

Développer du texte au fur et à mesure de la frappe

Tapez quelque chose dans textarea pour voir l’effet

<script>    
function increseRows(selector)
{
    $(selector).attr("rows", $(selector).val().split("\n").length+1||2);
}
</script>

expanding textarea as you type

1

Je recherchais une solution JS pure (pas de jQuery dans les projets) et finissais par écrire ma propre solution. C'est très rapide, pas de problèmes de compatibilité et ne nécessite aucune bibliothèque supplémentaire. 

Un détail à prendre en compte est que vous devez redimensionner la case avant que le nouveau caractère apparaisse, mais réduisez la taille après la disparition du caractère (après avoir appuyé sur la touche Retour arrière ou Supprimer).

function updateSize(e) {
  let text = e.target.value + String.fromCharCode(event.keyCode);
  e.target.rows = text.split(/\r\n|\r|\n/).length;
}

function keyDownUpdateSize(e) {
  if (event.keyCode != 8 && event.keyCode != 46)
    updateSize(e);
}

function keyUpUpdateSize(e) {
  if (event.keyCode == 8 || event.keyCode == 46)
    updateSize(e);
}

    
  
document.querySelector(selector_to_your_textarea).addEventListener("keydown", keyDownUpdateSize);
document.querySelector(selector_to_your_textarea).addEventListener("keyup", keyUpUpdateSize);

1
Marek Kirejczyk

Ancienne question mais vous pouvez faire quelque chose comme ça:

html:

<textarea class="text-area" rows="1"></textarea>

jquery:

var baseH; // base scroll height

$('body')
    .one('focus.textarea', '.text-area', function(e) {
        baseH = this.scrollHeight;
    })
    .on('input.textarea', '.text-area', function(e) {
        if(baseH < this.scrollHeight) {
            $(this).height(0).height(this.scrollHeight);
        }
        else {
            $(this).height(0).height(baseH);
        }
    });

De cette façon, le redimensionnement automatique s’appliquera à n’importe quelle zone de texte de la classe "zone de texte". Réduit également lorsque le texte est supprimé.

jsfiddle:

https://jsfiddle.net/rotaercz/46rhcqyn/

1
rotaercz

J'utilise ce qui suit (avec jQuery bien sûr):

$(function () {
    'use strict';
    $("textarea").on('change keyup paste input', function () {
        $(this).attr("rows", Math.max($(this).val().split("\n").length || 1, $(this).attr("rows") || 1));
        $(this).css("width", $(this).css("width"));
    }).trigger('change');
});

Notez qu'il répond à divers événements, n'augmente que le nombre de lignes (c'est-à-dire qu'il ne diminue pas), déclenche une modification initiale (par exemple, redimensionner lorsque vous revenez à un formulaire comportant beaucoup de lignes).

1
DigitalDan

Utilisez Javascript. textarea se comporte comme une textarea, et vous voulez changer cela (vous voulez que cela se comporte comme une div), vous devez donc pirater le comportement que vous souhaitez.

Voici une solution que j'ai trouvée quelque part il y a quelques mois mais que je n'ai pas encore retrouvée. Il se peut que ma propre saveur soit ajoutée dans:

Balisage:

<div>
  <textarea class='my-textarea' />
  <div className='my-textarea autogrow' style="display: 'none';" />
</div>

Modes:

.my-textarea {
  border: 1px solid #bbb;
  font-family: Helvetica;
  font-size: 15px;
  overflow: hidden;
  padding: 5px;
  resize: none;
}

// Needs same styles as the textarea except overflow.
.autogrow {
  overflow: auto !important;
}

Obtenez cet écouteur d'événement sur l'événement change de textarea:

function growTextarea(e) {
  const { value } = e.target
  const textarea = e.target
  const { grower } = this

  grower.style.display = 'block'
  grower.innerHTML = value.length ? value : 'x'
  textarea.style.height = grower.offsetHeight + 'px'
  grower.style.display = 'none'
}

Comment ça marche? En gros, l'expansion d'une div est ce que vous voulez que l'expansion de textarea se comporte. Vous créez donc une div avec tous les mêmes styles que textarea et placez la valeur de textarea dans la div. Ensuite, vous obtenez la hauteur de la div et définissez la hauteur de textarea à celle.

En utilisant display none et block, la div apparaît et disparaît pour vous permettre de mesurer sa hauteur. Vous ne le verrez jamais réellement dans le navigateur.

J'espère que cela fonctionne pour toi!

P.S. J'utilise React et j'ai donc dû modifier ma solution pour qu'elle soit agnostique au niveau du framework. Donc, il peut y avoir des bugs ou des erreurs de syntaxe. Par exemple. vous devrez peut-être interroger le document pour trouver le div du producteur.

0
A.Williams

Si vous utilisez Angular2/4, il existe une excellente directive ici qui fonctionne. 

Consultez la liste des problèmes à résoudre lorsque vous chargez des données de manière dynamique dans la zone de texte. Autre que ce problème, il fonctionne bien avec les formulaires ReactiveForms et Template.

Pour référence, voici le code de la directive:

import { Input, AfterViewInit, ElementRef, HostListener, Directive} from '@angular/core';

@Directive({
    selector: 'textarea[autosize]'
})

export class Autosize implements AfterViewInit {

    private el: HTMLElement;
    private _minHeight: string;
    private _maxHeight: string;
    private _lastHeight: number;
    private _clientWidth: number;

    @Input('minHeight')
    get minHeight() { 
      return this._minHeight;
    }
    set minHeight(val: string) {
      this._minHeight = val;
      this.updateMinHeight();
    }

    @Input('maxHeight')
    get maxHeight() {
      return this._maxHeight; 
    }
    set maxHeight(val: string) {
      this._maxHeight = val;
      this.updateMaxHeight();
    }

 @HostListener('window:resize', ['$event.target'])
    onResize(textArea: HTMLTextAreaElement) {
      //Only apply adjustment if element width had changed.
      if (this.el.clientWidth === this._clientWidth) return;
      this._clientWidth = this.element.nativeElement.clientWidth;
      this.adjust();
    }

 @HostListener('input',['$event.target'])
  onInput(textArea: HTMLTextAreaElement): void {
    this.adjust();  
  }

  constructor(public element: ElementRef){
    this.el = element.nativeElement;
    this._clientWidth = this.el.clientWidth;
  }

  ngAfterViewInit(): void{
    // set element resize allowed manually by user
    const style = window.getComputedStyle(this.el, null);
    if (style.resize === 'both') {
            this.el.style.resize = 'horizontal';
        }
    else if (style.resize === 'vertical') {
            this.el.style.resize = 'none';
    }
    // run first adjust
    this.adjust();
  }

  adjust(): void{
    // perform height adjustments after input changes, if height is different
    if (this.el.style.height == this.element.nativeElement.scrollHeight + "px") return;
    this.el.style.overflowX = 'hidden';
    this.el.style.height = 'auto';
    this.el.style.height = this.el.scrollHeight + "px";
  }

  updateMinHeight(): void{
    // Set textarea min height if input defined
    this.el.style.minHeight = this._minHeight + 'px';
  }

  updateMaxHeight(): void{
    // Set textarea max height if input defined
    this.el.style.maxHeight = this._maxHeight + 'px';
  }

}
0
rmcsharry