Verzögerung HTML5: Ungültige Pseudoklasse bis zum ersten Ereignis


73

Ich habe kürzlich festgestellt, dass die :invalidPseudoklasse für requiredFormularelemente gilt, sobald die Seite geladen wird. Wenn Sie beispielsweise diesen Code haben:

<style>
input:invalid { background-color: pink; color: white; }
input:valid { background-color: white; color: black; }
</style><input name="foo" required />

Dann wird Ihre Seite mit einem leeren rosa Eingabeelement geladen. Die in HTML5 integrierte Validierung ist großartig, aber ich glaube nicht, dass die meisten Benutzer erwarten, dass das Formular validiert wird, bevor sie überhaupt die Möglichkeit hatten, Werte einzugeben. Gibt es eine Möglichkeit, die Anwendung der Pseudoklasse bis zum ersten Ereignis zu verzögern, das dieses Element betrifft (Formular senden, verwischen, ändern, was auch immer angemessen ist)? Ist dies ohne JavaScript möglich?


Ich kann keinen Kommentar abgeben, daher werde ich diese Ergänzung zu @ user3284463 hinzufügen. Die makeDirtyDirty-Klasse sollte nicht umgeschaltet werden, sie sollte bei zukünftigen (blau, ungültig, gültig) Ereignisfunktionen bleiben. MakeDirty (e) {if (! E.target .classList.contains ('schmutzig')) e.target.classList.add ('schmutzig'); }
Abir Stolov

Idealerweise möchte ich, dass CSS Folgendes zulässt: Auf Formularelementen besucht, um dies zu erreichen.
Matty

Antworten:


41

http://www.alistapart.com/articles/forward-thinking-form-validation/

Da wir nur anzeigen möchten, dass ein Feld ungültig ist, wenn es den Fokus hat, verwenden wir die Fokus-Pseudoklasse, um das ungültige Styling auszulösen. (Natürlich wäre es eine schlechte Wahl, alle erforderlichen Felder von Anfang an als ungültig zu kennzeichnen.)

Nach dieser Logik würde Ihr Code ungefähr so ​​aussehen ...

<style>
    input:focus:required:invalid {background-color: pink; color: white;}
    input:required:valid {background-color: white; color: black; }
<style>

Hat hier eine Geige erstellt: http://jsfiddle.net/tbERP/

Wie Sie sich vorstellen können und wie Sie anhand der Geige sehen werden, zeigt diese Technik das Validierungsstil nur, wenn das Element den Fokus hat. Sobald Sie den Fokus entfernen, wird das Styling gelöscht, unabhängig davon, ob es gültig ist oder nicht. Auf keinen Fall ideal.


18
"Auf keinen Fall ideal." Tatsächlich. Gibt es eine Möglichkeit, das Styling auf gültige, aber nicht erforderliche Inhalte anzuwenden , nachdem das Element den Fokus verloren hat? Ich habe keinen Weg gefunden, dies zu tun.
Donald Jenkins

1
Ich könnte mir eine (derzeit nicht existierende) Pseduo-Klasse für Formulare wie "eingereicht" vorstellen, so dass dies als übergeordneter Selektor für alle enthaltenen Eingaben wie "fungieren" dient #myform:submitted input:required:invalid. Denn obwohl dieses aktuelle Szenario in der Tat nicht intuitiv ist, ist es nicht unbedingt realistisch zu erwarten, dass das CSS weiß, dass ein Feld unter bestimmten Umständen ungültig ist (warum sollte es dies nicht sofort tun, soweit es weiß?) Sie möchten den Eingabestil wirklich an den Status des Formulars binden, nicht an die Eingabe selbst (z. B. wenn das erforderliche Feld leer ist UND das übergeordnete Formular gesendet wird).
Anthony

Diese Antwort: stackoverflow.com/questions/41619497/… befasst sich tatsächlich gut damit, denke ich, auch wenn es ein bisschen Javascript erfordert. Es wird nur eine Klasse "eingereicht" zum Formular hinzugefügt (genau wie ich vorgeschlagen habe!), Damit die Stilregeln lauten könnenform.submitted input:required:invalid
Anthony

Um diesen Punkt vollständig auszuschöpfen, sollte dasselbe Problem auch bei anderen :validoder :invalidEingabetypen auftreten. Wenn eine Eingabe vom Typ ist integerund nichts ausgefüllt ist, sollte sie als ungültig dargestellt werden, da leer kein gültiger numerischer Wert ist. Der einzige Grund, warum dies kein Problem ist, ist, dass außerhalb der requiredEigenschaft ein leerer Wert als gültiger Wert betrachtet wird.
Anthony

Wenn Sie auf Senden klicken, wird jeweils nur 1 ungültiges Feld hervorgehoben. Im Allgemeinen ist es praktisch, wenn alle Invaliden hervorgehoben sind, damit Benutzer sie alle einmal korrigieren können, bevor sie auf Senden klicken. ist es besser, das erforderliche Tag aus allen Feldern zu entfernen und dann eine benutzerdefinierte js-Funktion für onsubmit zu schreiben
Aseem

31

Diese Antworten sind veraltet. Jetzt können Sie dies tun, indem Sie mit CSS nach einer Platzhalter-Pseudoklasse suchen.

input:not(:placeholder-shown):invalid {
    background-color: salmon;
}
form:invalid button {
    background-color: salmon;
    pointer-events: none;
}
<form>
    <input type="email" placeholder="me@example.com" required>
    <button type="submit">Submit</button>
</form>

Es beginnt mit einem normalen Hintergrund und wird rosa, wenn Sie Ihre unvollständige E-Mail-Adresse eingeben.


4
Es ist erwähnenswert, dass die :placeholder-shownPseudoklasse überhaupt nicht unterstützt wird, wenn Sie sich für die IE- oder Edge-Unterstützung interessieren . caniuse.com/#feat=css-placeholder-shown
Leo Napoleon

5
Leider funktioniert es nicht, wenn Ihre einzige Validierung erforderlich ist. Es sollte ein Fehler angezeigt werden, wenn Sie ein erforderliches Feld berührt oder versucht haben, ein Formular mit erforderlichen Feldern zu senden. Ein leeres Pflichtfeld zeigt weiterhin den Platzhalter.
Björn Tantau

Ich habe ein Beispiel für das Umschalten der Schaltfläche "Senden" basierend auf dem Formular hinzugefügt.
Carl

Wow das ist toll!
Ege

Wenn Sie eine Teil-E-Mail eingeben, wird diese wieder weiß. Sagen Sie, jon @ doe ist gültig
S. Redrum

25

Dies ist in reinem CSS nicht möglich, kann aber mit JavaScript erfolgen. Dies ist ein jQuery-Beispiel :

// use $.fn.one here to fire the event only once.
$(':required').one('blur keydown', function() {
  console.log('touched', this);
  $(this).addClass('touched');
});
/**
 * All required inputs initially are yellow.
 */
:required {
  background-color: lightyellow;
}

/**
 * If a required input has been touched and is valid, it should be white.
 */
.touched:required:valid {
  background-color: white;
}

/**
 * If a required input has been touched and is invalid, it should be pink.
 */
.touched:required:invalid {
  background-color: pink;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>
  <label>
    Name:
    <input type="text" required> *required
  </label>
</p>
<p>
  <label>Age:
    <input type="text">
  </label>
</p>


Das ist eine einfache Lösung;)
Fegemo

1
Dies ist die Lösung, die ich bevorzuge, aber Sie benötigen jQuery nicht mehr. Dies kann mit einfachem Javascript erfolgen.
Micah

3

Ich habe eine kleine Unterlegscheibe erstellt, um dies in meiner Codebasis zu behandeln. Ich beginne einfach damit, dass mein <form/>Element die novalidateEigenschaft zusammen mit einem data-validate-on="blur"Attribut hat. Dies überwacht das erste Ereignis dieses Typs. Auf diese Weise können Sie weiterhin die nativen :invalidCSS-Selektoren für das Formular-Styling verwenden.

$(function () {
    $('[data-validate-on]').each(function () {
        var $form = $(this);
        var event_name = $form.data('validate-on');

        $form.one(event_name, ':input', function (event) {
            $form.removeAttr('novalidate');
        });
    });
});

Das war die Lösung für mich.
Robrecord

3

Mozilla kümmert sich mit ihrem eigenen : -moz-ui-invalid darum Pseudoklasse, die nur für Formulare gilt, nachdem sie interagiert wurden. MDN empfiehlt die Verwendung aufgrund mangelnder Unterstützung nicht. Sie können es jedoch für Firefox ändern.

Es gibt eine Level 4-Spezifikation für eine : Benutzer-ungültige Spezifikation am Horizont, die ein ähnliches Verhalten bietet.

Tut mir leid, wenn dies nicht hilft, aber ich hoffe, es bietet einen gewissen Kontext.


2

Versuchen Sie bei der Verwendung der HTML5-Formularüberprüfung, den Browser zu verwenden, um ungültige Übermittlungen / Felder zu erkennen, anstatt das Rad neu zu erfinden.

Warten Sie auf das invalidEreignis, um Ihrem Formular eine Klasse von "ungültig" hinzuzufügen. Wenn die Klasse 'ungültig' hinzugefügt wurde, können Sie mit der Gestaltung Ihres Formulars mithilfe von CSS3 in die Stadt gehen:pseudo Selektoren .

Zum Beispiel:

// where myformid is the ID of your form
var myForm = document.forms.myformid;

var checkCustomValidity = function(field, msg) {
    if('setCustomValidity' in field) {
        field.setCustomValidity(msg);
    } else {
        field.validationMessage = msg;
    }
};

var validateForm = function() {

    // here, we're testing the field with an ID of 'name'
    checkCustomValidity(myForm.name, '');

    if(myForm.name.value.length < 4) {
        checkCustomValidity(
            // alerts fields error message response
            myForm.name, 'Please enter a valid Full Name, here.'
        );
    }
};

/* here, we are handling your question above, by adding an invalid
   class to the form if it returns invalid.  Below, you'll notice
   our attached listener for a form state of invalid */
var styleInvalidForm = function() {
    myForm.className = myForm.className += ' invalid';
}

myForm.addEventListener('input', validateForm, false);
myForm.addEventListener('keyup', validateForm, false);
myForm.addEventListener('invalid', styleInvalidForm, true);

Gestalten Sie Ihr Formular jetzt einfach nach Ihren Wünschen basierend auf der angehängten 'ungültigen' Klasse.

Zum Beispiel:

form.invalid input:invalid,
form.invalid textarea:invalid {
    background: rgba(255, 0, 0, .05);
    border-color: #ff6d6d;
    -webkit-box-shadow: 0 0 6px rgba(255, 0, 0, .35);
    box-shadow: 0 0 6px rgba(255, 0, 0, .35);
}

5
Ähm, ist das nicht viel mehr als die Frage, das Rad neu zu erfinden?
Ry-

2

Es gibt ein HTML5- invalidEreignis, das für Formularelemente ausgelöst wird , bevor das submitEreignis für jedes Element auftritt, das checkValidity nicht besteht. Mit diesem Ereignis können Sie beispielsweise eine Klasse auf das umgebende Formular anwenden und ungültige Stile erst anzeigen, nachdem dieses Ereignis aufgetreten ist.

 $("form input, form select, form textarea").on("invalid", function() {
     $(this).closest('form').addClass('invalid');
 });

Ihr CSS würde dann ungefähr so ​​aussehen:

:invalid { box-shadow: none; }
.invalid input:invalid,
.invalid textarea:invalid,
.invalid select:invalid { border: 1px solid #A90909 !important; background-color: #EEC2C2; }

In der ersten Zeile wird das Standard-Styling entfernt, sodass Formularelemente beim Laden der Seite neutral aussehen. Sobald das ungültige Ereignis ausgelöst wird (wenn ein Benutzer versucht, das Formular zu senden), werden die Elemente sichtbar ungültig.


2

Dies ist ein VanillaJS (kein jQuery) Version von KZH ‚s Antwort

{
  let f = function() {
    this.classList.add('touched')
  }
  document
    .querySelectorAll('input')
    .forEach((e) => {
      e.addEventListener('blur', f, false)
      e.addEventListener('keydown', f, false)
    })
}
/**
 * All required inputs initially are yellow.
 */
:required {
  background-color: lightyellow;
}

/**
 * If a required input has been touched and is valid, it should be white.
 */
.touched:required:valid {
  background-color: white;
}

/**
 * If a required input has been touched and is invalid, it should be pink.
 */
.touched:required:invalid {
  background-color: pink;
}
<p><label>
  Name:
  <input type="text" required> *required
</label></p>
<p><label>Age:
  <input type="text">
</label></p>


1
Zwar ist dies eine gute Lösung ist, können Sie tauschen wollen querySelectorAllfür getElementsByTagName, wie es etwa 17000 - mal (!) Schneller auf meinem Rechner ist. Testen Sie es selbst: jsperf.com/queryselectorall-vs-getelementsbytagname
Boltgolt

1

Sie können es so gestalten, dass nur Elemente, die eine bestimmte Klasse haben und erforderlich sind, pink sind. Fügen Sie jedem erforderlichen Element einen Ereignishandler hinzu, der diese Klasse hinzufügt, wenn Sie das Element verlassen.

Etwas wie:

<style>
  input.touched:invalid { background-color: pink; color: white; }
  input.touched:valid { background-color: white; color: black; }
</style>
<script>
  document.addEventListener('DOMContentLoaded', function() {
    var required = document.querySelectorAll('input:required');
    for (var i = 0; i < required.length; ++i) {
      (function(elem) {
        function removeClass(name) {
          if (elem.classList) elem.classList.remove(name);
          else
            elem.className = elem.className.replace(
              RegExp('(^|\\s)\\s*' + name + '(?:\\s+|$)'),
              function (match, leading) {return leading;}
          );
        }

        function addClass(name) {
          removeClass(name);
          if (elem.classList) elem.classList.add(name);
          else elem.className += ' ' + name;
        }

        // If you require a class, and you use JS to add it, you end up
        // not showing pink at all if JS is disabled.
        // One workaround is to have the class on all your elements anyway,
        // and remove it when you set up proper validation.
        // The main problem with that is that without JS, you see what you're
        // already seeing, and stuff looks hideous.
        // Unfortunately, you kinda have to pick one or the other.


        // Let non-blank elements stay "touched", if they are already,
        // so other stuff can make the element :invalid if need be
        if (elem.value == '') addClass('touched');

        elem.addEventListener('blur', function() {
          addClass('touched');
        });

        // Oh, and when the form submits, they need to know about everything
        if (elem.form) {
          elem.form.addEventListener('submit', function() {
            addClass('touched');
          });
        };
      })(required[i]);
    }
  });
</script>

Und natürlich funktioniert es nicht wie in IE8 oder darunter, da (a) DOMContentLoadedrelativ neu ist und zum Zeitpunkt der Veröffentlichung von IE8 nicht Standard war, (b) IE8 attachEventanstelle des DOM-Standards verwendet addEventListenerwird und (c) IE8 wird sich :requiredsowieso nicht darum kümmern , da es HTML 5 technisch nicht unterstützt.


1

Eine gute Möglichkeit besteht darin, :invalid, :validmit einer CSS-Klasse und anschließend mit etwas JavaScript zu abstrahieren , um zu überprüfen, ob das Eingabefeld fokussiert war oder nicht.

CSS:

input.dirty:invalid{ color: red; }
input.dirty:valid{ color: green; }

JS:

// Function to add class to target element
function makeDirty(e){
  e.target.classList.toggle('dirty');
}

// get form inputs
var inputs = document.forms[0].elements;

// bind events to all inputs
for(let input of inputs){
  input.addEventListener('invalid', makeDirty);
  input.addEventListener('blur', makeDirty);
  input.addEventListener('valid', makeDirty);
}

DEMO


1

In Anlehnung an die Idee von agouseh können Sie ein bisschen Javascript verwenden, um festzustellen , wann der Senden-Button fokussiert wurde, und zu diesem Zeitpunkt wird eine Validierung angezeigt .

Das Javascript fügt submit-focusseddem Formularfeld eine Klasse (z. B. ) hinzu, wenn die Senden-Schaltfläche fokussiert oder angeklickt wird, wodurch das CSS ungültige Eingaben formatieren kann.

Dies folgt der bewährten Methode, Validierungsfeedback anzuzeigen, nachdem der Benutzer die Felder ausgefüllt hat, da es laut Untersuchungen keinen zusätzlichen Vorteil hat, es während des Prozesses anzuzeigen.

document
  .querySelector('input[type=submit]')
  .onfocus = function() {
    this
      .closest('form')
      .classList
      .add('submit-focussed');
  };
form.submit-focussed input:invalid {
  border: thin solid red;
}
<form>
  <label>Email <input type="email" required="" /></label>
  <input type="submit" />
</form>

jQuery-Alternative

(function($) {
  $('input[type=submit]').on('focus', function() {
    $(this)
      .parent('form')
      .addClass('submit-focussed');
  });
})(jQuery); /* WordPress compatible */

0

Hier ist meine Methode, um das Standard-Styling einer nicht fokussierten Eingabe als ungültig zu vermeiden. Sie müssen nur einen einfachen js-Befehl hinzufügen onFocus, damit die Webseite identifiziert focusedund unfocusedeingegeben werden kann, damit nicht alle Eingaben im ungültigen Stil angezeigt werden .

<style>
input.focused:required:invalid { background-color: pink; color: white; }
input:valid { background-color: white; color: black; }
</style><input name="foo" class="notfocused" onFocus="document.activeElement.className='focused';" required />

Probieren Sie es unten aus:

input.focused:required:invalid {
  background-color: pink;
  color: white;
}

input:required:valid {
  background-color: darkseagreen;
  color: black;
}
<label>At least 1 charater:</label><br />
<input type="text" name="foo" class="notfocused" onFocus="document.activeElement.className='focused';" required />


0

Ich kann nichts dazu sagen, aber zu @ Carls sehr nützlicher Antwort bezüglich der Verwendung von: not (: Platzhalter angezeigt). Wie in einem anderen Kommentar erwähnt, wird der ungültige Status weiterhin angezeigt, wenn Sie KEINEN Platzhalter haben (wie dies bei einigen Formularentwürfen erforderlich ist).

Um dies zu lösen, fügen Sie einfach einen leeren Platzhalter wie folgt hinzu

<input type="text" name="username" placeholder=" " required>

Dann dein CSS, so etwas wie

:not(:placeholder-shown):invalid{ background-color: #ff000038; }

Hat für mich gearbeitet!

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.