2011-10-27 20 views
42

Recientemente descubrí que la pseudoclase :invalid se aplica a los elementos de formulario required tan pronto como se carga la página. Por ejemplo, si tiene este código:Retraso HTML5: pseudoclase no válida hasta el primer evento

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

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

Respuesta

27

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

Ya que sólo quiere denotar que un campo no es válido una vez que se tiene enfoque, se utiliza el enfoque de pseudo-clase para activar el estilo no válido. (Naturalmente, marcar todos los campos requeridos como no válida desde el inicio sería una mala elección de diseño.)

Siguiendo esta lógica, el código sería algo como esto ...

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

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

Como supondrás, 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 alejas el foco, el estilo se elimina, independientemente de si es válido o no. No es ideal de ninguna manera.

+10

"No es ideal de ninguna manera". En efecto. ¿Hay alguna forma de aplicar el estilo a contenido válido, pero no obligatorio, una vez que el elemento ha perdido el enfoque? No he encontrado una manera de hacer esto. –

+0

Podría imaginar una clase pseduo (no existente actualmente) para formularios como "enviado" para que esto actúe como un selector principal para cualquier entrada contenida, como '#myform: entrada enviada: requerida: inválida'. Porque a pesar de que este escenario actual no es intuitivo, no es necesariamente realista esperar que el CSS sepa que un campo no es válido bajo circunstancias específicas (¿por qué no debería hacerlo de inmediato, por lo que sabe?), Entonces realmente desea vincular el estilo de entrada con el estado del formulario, no la entrada en sí (por ejemplo, cuando el campo obligatorio está vacío Y se envía el formulario principal). – Anthony

+0

Esta respuesta: https: // stackoverflow.com/questions/41619497/how-to-make-pseudo-class-invalid-apply-to-a-input-after-submitting-a-form en realidad trata esto bien, creo, incluso si requiere un poco de javascript . Simplemente agrega una clase "enviada" al formulario (¡tal como lo sugería!) Para que las reglas de estilo puedan ser 'form.submitted input: required: invalid' – Anthony

1

Puede hacer que solo los elementos que tienen una determinada clase en ellos y son obligatorios, son de color rosa. Agregue un controlador de eventos a cada elemento requerido que agregue esa clase cuando abandone el elemento.

Algo así 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 va a funcionar como tal en IE8 o por debajo, como (a) DOMContentLoaded es relativamente nuevo y no era estándar cuando IE8 salió, (b) IE8 utiliza attachEvent en lugar de la estándar DOM-addEventListener, y (c) IE8 no va a preocuparse por :required de todos modos, ya que técnicamente no es compatible con HTML 5.

17

Esto no es posible en el CSS puro, pero se puede hacer con JavaScript. Se trata de un jQuery example:

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

+0

Esa es una solución simple;) – fegemo

+0

Esta es la solución que prefiero pero ya no necesita jQuery. Esto se puede hacer con un simple Javascript. – micah

2

Durante el uso de la validación de formularios HTML5, tratar de utilizar el navegador para detectar válidos para sumisiones/campos, en lugar de volver a inventar la rueda.

Escuche el evento invalid para agregar una clase de 'no válido' a su formulario. Con la clase 'inválida' agregada, puede ir a la ciudad con el estilo de su 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, sólo el estilo de su forma como mejor le parezca basado en la clase 'no válido' adjuntamos.

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); 
} 
+1

Er, ¿no es esto reinventar la rueda muchísimo más que la pregunta? – Ryan

+0

¿Reinventando la rueda? Esta es la rueda ... Arriba es una forma efectiva de manejar estilos de validación de formularios HTML5 al combinar CSS y JS para abordar el problema que estaba teniendo. Esto le permite diseñar sus elementos de formulario no válidos y evitar el pseudo-estilo en la carga de la página. Corrígeme si me equivoco, pero diría que es una forma sólida de abordar su problema. –

2

Hay una invalid evento html5 que los incendios en los elementos de formulario antes de que ocurra 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 invá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 sería entonces 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 por defecto, por lo que buscan formar elementos neutros en carga de la página. Tan pronto como se activa el evento no válido (cuando un usuario intenta enviar el formulario), los elementos se vuelven visiblemente inválidos.

1

Creé una pequeña cuña para tratar esto en mi código base. Acabo de comenzar con mi elemento <form/> que tiene la propiedad novalidate junto con un atributo data-validate-on="blur". Esto mira para el primer evento de ese tipo. De esta forma, aún puede usar los selectores nativos :invalid css para el diseño 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'); 
     }); 
    }); 
}); 
0

Una buena manera es abstraer :invalid, :valid con unas clases CSS y algo de JavaScript para comprobar si el campo de entrada se enfocó 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

1

Estas respuestas están fuera de fecha. Ahora puede hacer esto al buscar una pseudoclase de marcador de posición con CSS.

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

Se inicia con un fondo normal y se vuelve rosa a medida que se introduce la dirección de correo electrónico incompleta en ella.

Cuestiones relacionadas