Registreren

    Informatie

    Het is heel gemakkelijk om lid te worden. Door je gegevens op te geven op de registratie pagina ontvang je automatisch een email met je inlog gegevens.

  • Registreer je hier

Aanmelden

    Informatie

    Omdat je niet aangemeld bent is het gebruikerspaneel niet beschikbaar. Vul hiernaast je gegevens in om gebruik te maken van het gebruikerspaneel.

Aanmeldformulier


Verlengbare tekstvelden netjes gemaakt

JavaScript is een scripttaal die veel gebruikt wordt om webpagina's interactief te maken en webapplicaties te ontwikkelen.

De syntaxis van JavaScript vertoont overeenkomsten met de programmeertaal Java. Omdat beide talen het meest zichtbaar zijn op en rond de browser, maar vooral door de naamgeving, worden ze vaak met elkaar verward. De gelijkenis houdt daar echter op, want JavaScript heeft inhoudelijk meer gemeen met functionele programmeertalen, het biedt prototype-gebaseerde overerving en niet, zoals Java en de meeste objectgeoriënteerde talen, klasse-gebaseerde overerving.

Verlengbare tekstvelden netjes gemaakt

Berichtdoor Zunflappie » 03 Nov 2011 23:05

Dit is een vertaling van Expanding Text Areas Made Elegant - A List Apart.
Rechten blijven op naam van Neil Jenkins en A List Part.

Een verlengbaar tekstveld is een tekst-invoerveld met meerdere regels die zich in hoogte aanpassen naar haar inhoud. Dit gebruikers-element wordt meestal gevonden bij zowel desktop als mobiele toepassingen, zoals het SMS-compositieveld op de iPhone. Voorbeelden kunnen ook op het internet gevonden worden, inclusief Facebook, waar het veel gebruikt wordt. Het is een goede keus als je niet weet hoe veel tekst de gebruiker wilt schrijven en jij de opmaak intact wilt houden. Zo is het vooral handig op pagina's op moderne telefoons.

Ondanks alle mogelijkheden, is er geen manier om dit te maken met alleen HTML en CSS. Terwijl normale block-level elementen (zoals een div als voorbeeld) uitrekken naar hun inhoud, doet de nederige textarea dit niet. Zelfs niet als we het met display: block; opmaken.
Aangezien de textarea de enige manier is om meerdere lijnen tekst van de gebruiker te ontvangen (anders dan gebruik te maken van contenteditable), is een klein beetje Javascript nodig om dit te doen.

Zoekend op het internet kan je meerdere pogingen vinden die een tekstveld verlengbaar willen maken. Maar die kampen met de volgende problemen:

  • De hoogte is berekend door te raden waar de woord-afbreking zal zijn gebaseerd op het aantal kolommen-attribuut (als in cols). Dit werkt niet als je de breedte van het tekstveld met CSS opgeeft, of simpelweg geen cols-attribuut opgeeft.
  • De hoogte wordt herberekend via de keyup-actie. Mogelijkerwijs ook op kopiëren/plakken-acties. Dit werkt niet als het tekstveld een variabele breedte heeft of het venster wordt herschaald.
  • De benodigde hoogte is berekend via het scrollHeight-attribuut. Terwijl dit attribuut niet is gespecificeerd door het W3C (het is geïntroduceerd met Internet Explorer) en dus zoals verwacht, verschillende uitwerkingen heeft op verschillende browsers. Hierdoor is een warrige en browser-aftastende code nodig.

De beste oplossing die ik ben tegengekomen gebruikt een afzonderlijk pre{/i]-element absoluut gepositioneerd buiten het scherm, hetzelfde opgemaakt als de [i]textarea. Laten we deze de 'spiegel-element' noemen. Door gebruik te maken van setTimeOut wordt het, zeg elke 200 ms, vergeleken met het tekstvlak. En elke keer als er een nieuwe waarde is gevonden, wordt de inhoud van het spiegel-element bijgewerkt. Deze hoogte wordt dus automatisch aangepast aan diens inhoud, zoals een normaal block-level-element. Hierna wordt de hoogte hiervan berekend via offsetHeight en daarna toegepast op het tekstveld.

Deze methode werk, maar het vergelijkingen is inefficiënt. Zeker als je meerdere tekstvelden hebt. Zeker wanneer je tekstvelden een flexibele breedte hebbenk moet je ook nog controleren of de breedte niet is veranderd (wat een duur gebruik van offsetWidth is). Het berekenen van de precieze breedte kan moeilijk zijn aangezien er normaal gesproken altijd wat 'extra ruimte' is om te typen.
Hier ga ik een betere manier laten zien voor dit probleem. Een oplossing die de textarea herschaald met een klein stukje Javascript-code en wat wonderbaarlijke CSS.

De techniek is een verbetering op het buiten het gezichtsveld geplaatste 'spiegel-element'. De eerste verbetering die we maken is gerelateerd aan hoe we de invoer controleren. De change-actie is niet ideaal aangezien deze alleen werkt als de cursor buiten het tekstveld komt. De keyup-actie werkt altijd, maar reageert ook als er geen veranderingen zijn, zoals bij het verplaatsen van de cursor. En het reageert niet als de gebruiker iets knipt of plakt. Wat we willen is een actie die simpelweg reageert als de inhoud van het tekstveld wijzigt. Gelukkig, die actie bestaat en is uitermate bruikbaar, ook al wordt deze zo weinig genoemd dat men hem niet lijkt te kennen. De actie heet simpelweg input, en we gebruiken het als elke andere actie:

Code: Alles selecteren
textarea.addEventListener('input', function (event) {
    /* Code om uit te voeren */
}, false )


Dus is onze eerste verbetering is te stoppen met setTimeout en in plaats daarvan de veel efficiëntere input te gaan gebruiken. Deze is ook cross-browser ondersteunt, zelfs Internet Explorer 9 en hoger ondersteunen het. Uiteraard is er wel een IE-foutje: het reageert niet als je tekst verwijderd, dus het tekstveld krimpt niet tot er nieuwe tekst wordt toegevoegd. Als dit je zorgt baart kan je alsnog teruggrijpen op de keyup-actie voor Internet Explorer.

Voor IE8 kunnen we de onpropertychange-actie gebruiken, welke ook reageert als de inhoud wijzigt. Deze actie is ook beschikbaar op lagere versies dan 8, maar er zullen een aantal kleine wijzigingen in de CSS nodig zijn om het goed te laten werken. Ik laat de werking voor IE 6 of IE7 aan lezers over die ongelukkig genoeg voor deze antieke browsers ondersteuning dienen te geven.

Nu we geen gebruik meer maken van een controle-interval, het tekstveld zal niet herschalen indien deze een flexibele breedte heeft of het venster wordt herschaald. Dat brengt ons tot de volgende verbetering: we laten het tekstveld automatisch door de browser herschalen. Maar ik hoor u al roepen: "Ik dacht dat u zei dat dat onmogelijk was". Nou, niet helemaal. We krijgen het niet met alleen HTML en CSS voor elkaar. Maar alles wat Javascript hoeft te doen is de inhoud van het tekstveld in ons 'spiegel-element' te kopieren. Het hoeft niets te meten of een exacte hoogte op te gven. De truc is om het tekstveld bovenop het spiegel-element te zetten, beide in een relatief geplaatste div. Het tekstveld is absoluut geplaatst met een breedte en hoogte van 100% om de div volledig te vullen. Het spiegel-element is statisch geplaatst zodat het zal groeien naarmate de inhoud meer wordt. De omvattende div zal dan verlengd worden naar het formaat van het spiegel-element, waardoor het tekstveld automatisch ook zla meegroeien.
En dus zal het tekstveld automatisch meegroeien naar haar eigen inhoud.

Genoeg uitleg, geef me gewoon de code
Oké dan! Ik wilde dat net doen. Het is mooie, simpele code. De HTML-code ziet er als volgt uit:

Code: Alles selecteren
<div class="expandingArea">
  <pre><span></span><br></pre>
  <textarea></textarea>
</div>


Het pre-element is ons spiegel-element. We hebben wel een <br> aan het einde nodig om er voor te zorgen dat spaties aan het einde correct gekopieerd worden door de browser en dus niet verdwijnen. Het span-element is nodig omdat we daarin de daadwerkelijk tekst van het tekstveld gaan plakken.

Hierbij de CSS. Eerst een kleine reset (die je waarschijnlijk al hebt):

Code: Alles selecteren
textarea, pre
{
  margin: 0;
  padding: 0;
  outline: 0;
  border: 0;
}


Omvattende elementen zijn voorzien van de expandingArea-klasse. Je kan een rand of marge en dergelijke opgeven. Hier geef je op hoe jij jouw tekstveld wilt opmaken. Ik heb een simpele 1px brede, grijze rand toegevoegd. Je kan een min-height opgeven. Deze werkt als verwacht:

Code: Alles selecteren
.expandingArea {
  position: relative;
  border: 1px solid #888;
  background: #fff;
}


Je kan elke marge, padding, lijnhoogte of letteropmaak gebruiken die jij wilt, zolang het tekstveld en het spiegel-element maar hetzeldfe zijn.

Code: Alles selecteren
.expandingArea > textarea,
.expandingArea > pre {
  padding: 5px;
  background: transparent;
  font: 400 13px/16px helvetica, arial, sans-serif;
  /* Make the text soft-wrap */
  white-space: pre-wrap;
  word-wrap: break-word;
}
.expandingArea > textarea {
  /* The border-box box model is used to allow
   * padding whilst still keeping the overall width
   * at exactly that of the containing element.
   */
  -webkit-box-sizing: border-box;
     -moz-box-sizing: border-box;
      -ms-box-sizing: border-box;
          box-sizing: border-box;
  width: 100%;
  /* This height is used when JS is disabled */
  height: 100px;
}
.expandingArea.active > textarea {
  /* Hide any scrollbars */
  overflow: hidden;
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  /* Remove WebKit user-resize widget */
  resize: none;
}
.expandingArea > pre {
  display: none;
}
.expandingArea.active > pre {
  display: block;
  /* Hide the text; just using it for sizing */
  visibility: hidden;
}


Al laatste gebruiken we het volgende Javascript. Uit gemak heb ik de gebruikelijke functie-detectie weggelaten die behoort uit te voeren voordat u querySelector() of querySelectorAll() gebruikt.
Het juiste gebruik van correct terugval, gebruikers zonder Javascript krijgen een 'gewoon' tekstveld met een vaste hoogte (welke opgegeven is in de CSS). Deze zal schuifbalken krijgen wanneer de inhoud te lang wordt.

Code: Alles selecteren
function makeExpandingArea(container) {
var area = container.querySelector('textarea');
var span = container.querySelector('span');
if (area.addEventListener) {
   area.addEventListener('input', function() {
     span.textContent = area.value;
   }, false);
   span.textContent = area.value;
} else if (area.attachEvent) {
   // IE8 compatibility
   area.attachEvent('onpropertychange', function() {
     span.innerText = area.value;
   });
   span.innerText = area.value;
}
// Enable extra CSS
container.className += ' active';
}

var areas = document.querySelectorAll('.expandingArea');
var l = areas.length;

while (l--) {
makeExpandingArea(areas[l]);
}


Een opmerking over de netheid. U kunt dit makkelijk opzetten met een enkele actie-reactie op het document-node om meerdere tekstvelden efficient te gebruiken. Maar alleen als u IE8 of lager niet hoeft te ondersteunen, omdat Microsoft, in haar oneindige wijsheid, haar onpropertychange zelf niet ondersteund.

Het verplichte voorbeeld
[onder constructie]

Sluitende opmerkingen
Door de manier waarop Opera voor Mac OS X tekstvelden tekent, is het mogelijk een kleine flikkering te zien zal zijn wanneer er een nieuwe regel wordt toegevoegd aan het tekstveld. Dit kunt u voorkomen door het tekstveld altijd een regel extra te geven bij Opera voor Mac. Voeg enkel de volgende code toe aan de rest van de makeExpandingArea-functie. Helaas is er geen feature-detectie mogelijk voor dit.

Code: Alles selecteren
if ( window.opera && /Mac OS X/.test( navigator.appVersion ) ) {
  container.querySelector( 'pre' )
           .appendChild(
    document.createElement( 'br' )
  );
}




Ten slotte, omdat het tekstveld precies boven de <i>pre</i> wordt geplaatst, kunt u deze uit te breiden met hippe dingen als syntax-highlighting terwijl u typt. Als u de inhoud ontleedt en in stukjes opdeelt vóór het toevoegen aan het spiegel-element, kunt meerdere kleuren voor meerdere delen gebruiken. U dient de sisibility: hidden te verwijderen uit de CSS voor het spiegelelement en in plaats daarvan color: transparent toe te voegen aan het tekstveld. We gebruiken deze techniek in My Opera Mail om namen te zoeken in de velden Aan/CC/BCC. Het addertje onder het gras is dat alle browsers dan Opera de kleur van de cursor gelijk maken aan de tekst, zodat deze wegvalt zodra de kleur transparant wordt. Ik geloof niet dat dat er enige W3C-standaarden dit dekken (laat me alstublief weten als dit wel het geval is). Maar het besturingssysteem-standaard (gebaseerd op de tekstverwerking die daar mee meekomen) lijken het negatieve kleuren te gebruiken terwijl Mac altijd zwart wordt weergegeven, ongeacht de achtergrondkleur. Maar totdat andere browser het licht zullen zien en dit gedrag zullen repaeren kunt rustig deze syntax toepassen en uitschakelen als de gebruiker de tekst bewerkt. Of de achtergrondkleur veranderen.

En dat is alles! Ik hoop dat u genoten heeft van dit artikel en mogelijkerwijs wat van deze nieuwe techniek kunt gaan gebruiken. Het is netjes en efficiënt en werkt zowel op moderne (deksktop-)browsers als op mobiele telefoons.
Veel succes!




Vertaling naar Nederlands door Eddy Erkelens.
Nabewerkt door ....
.
'K Ben er weer!
Gebruikers-avatar
Zunflappie
Teamlid
 
Berichten: 48
Geregistreerd: 06 Mrt 2006 12:48

Re: Verlengbare tekstvelden netjes gemaakt

Berichtdoor Theo » 04 Nov 2011 14:29

Bedankt voor de vertaling, erg handige tutorial.
Sluit mooi aan op web2.0 en gebruiksvriendelijkheid van websites.
I rather feel pain than nothing at all
Theo
Oprichter
 
Berichten: 1795
Geregistreerd: 11 Jun 2005 17:43
Woonplaats: in_array()


Terug naar JS



Wie is er online?

Gebruikers in dit forum: Geen geregistreerde gebruikers en 1 gast


cron