Retrasar HTML5: pseudo-clase inválida hasta el primer evento


Recientemente descubrí que la pseudo-clase :invalid se aplica a los elementos del formulario required tan pronto como se carga la página. Por ejemplo, si tiene este código:

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

Entonces su página se cargará con un elemento de entrada rosa vacío en ella. Tener la validación incorporada en HTML5 es genial, pero no creo que la mayoría de los usuarios esperen que el formulario se valide antes de que hayan tenido la oportunidad de ingresar ningún valor. ¿Hay alguna manera de retrasar la aplicación de la pseudo-clase hasta el primer evento que afecta a elemento (enviar formulario, desenfocar, cambiar, lo que sea apropiado)? Es posible hacer esto sin JavaScript?

Author: kojiro, 2011-10-27

10 answers

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

Ya que solo queremos denotar que un campo es inválido una vez que tiene focus, usamos la pseudo-clase focus para activar el estilo no válido. (Naturalmente, marcar todos los campos obligatorios como no válidos desde el principio sería una mala elección de diseño.)

Siguiendo esta lógica, su código se vería algo como esto...

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

Creó un violín aquí: http://jsfiddle.net/tbERP /

Como adivinarías, y como verás en el violín, esta técnica solo muestra el estilo de validación cuando el elemento tiene foco. Tan pronto como se quita el foco, el estilo se elimina, independientemente de si es válido o no. No es ideal de ninguna manera.

 32
Author: Bart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-27 19:52:37

Esto no es posible en CSS puro, pero se puede hacer con JavaScript. Este es un ejemplo de jQuery :

// 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>
 20
Author: kzh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-19 19:18:41

Estas respuestas están desactualizadas. Ahora puede hacer esto comprobando si hay una pseudo-clase de marcador de posición con CSS.

input:not(:placeholder-shown):invalid {
    background-color: salmon;
}
form:invalid button {
    background-color: salmon;
    pointer-events: none;
}
<form>
    <input type="email" placeholder="[email protected]" required>
    <button type="submit">Submit</button>
</form>

Comienza con un fondo normal y se vuelve rosa a medida que ingresa su dirección de correo electrónico incompleta en él.

 14
Author: Carl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-08 19:45:13

Al usar la validación de formularios HTML5, intente usar el navegador para detectar envíos/campos no válidos, en lugar de reinventar la rueda.

Escucha el evento invalid para agregar una clase de 'invalid' a tu formulario. Con la clase' invalid ' agregada, puedes ir a town con el estilo de tu formulario usando los selectores CSS3 :pseudo.

Por ejemplo:

// 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);

Ahora, simplemente estile su formulario como mejor le parezca basado en la clase 'inválida' que hemos adjuntado.

Por ejemplo:

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);
}
 2
Author: Jonathan Calvin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-26 17:56:54

Hay un evento html5 invalid que se activa en los elementos del formulario antes de que se produzca el evento submit para cada elemento que no pasa checkValidity. Puede usar este evento para aplicar una clase, por ejemplo, a la forma y visualización circundantes :estilos no válidos solo después de que ocurra este evento.

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

Su CSS se vería algo como esto:

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

La primera línea elimina el estilo predeterminado, por lo que los elementos del formulario se ven neutrales al cargar la página. Tan pronto como se inicie el evento no válido (cuando un usuario intenta enviar el formulario), los elementos se vuelven visiblemente inválidos.

 2
Author: Liquinaut,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-29 21:20:06

Se podría hacer de manera que solo los elementos que tienen una cierta clase en ellos y son necesarios, son de color rosa. Agregue un controlador de eventos a cada elemento requerido que agregue esa clase cuando deje el elemento.

Algo como:

<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>

Y por supuesto, no funcionará como está en IE8 o por debajo, como (a) {[1] } es relativamente nuevo y no era estándar cuando IE8 salió, (b) IE8 utiliza attachEvent en lugar del DOM-estándar addEventListener, y (c) IE8 no va a preocuparse por :required de todos modos, ya que no es técnicamente compatible con HTML 5.

 1
Author: cHao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-05 00:30:18

He creado un pequeño shim para lidiar con esto en mi base de código. Acabo de empezar con mi elemento <form/> que tiene la propiedad novalidate junto con un atributo data-validate-on="blur". Este reloj para el primer evento de ese tipo. De esta manera, todavía puede usar los selectores css nativos :invalid para el estilo del formulario.

$(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');
        });
    });
});
 1
Author: aghouseh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-17 19:53:50

Mozilla se encarga de esto con su propia :-moz-ui-invalid pseudoclase que solo se aplica a los formularios después de haber interactuado con ellos. MDN no recomienda usar esto debido a la falta de soporte. Sin embargo, puedes modificarlo para Firefox.

Hay una especificación de nivel 4 para una especificación :user-invalid en el horizonte que ofrecerá un comportamiento similar.

Lo siento si esto no ayuda, pero espero que ofrezca algún contexto.

 1
Author: Aaron Benjamin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-29 22:51:17

Una buena manera es abstraer :invalid, :valid con clases CSS y luego un poco de JavaScript para comprobar si el campo de entrada estaba enfocado o no.

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

 0
Author: user3284463,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-28 14:20:23

Aquí está mi método para evitar el estilo predeterminado de cualquier entrada desenfocada como no válida, solo tiene que agregar un simple comando js onFocus para permitir que la página web identifique focused y unfocused entradas, por lo que toda la entrada no aparecerá en el estilo de inválido en primer lugar.

<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 />

Pruébelo usted mismo a continuación:

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
Author: timo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-10 13:59:12