CSS
Tutorial CSS: CSS para formularios
Aprende a estilizar formularios con CSS, personalizar inputs, validar estados y crear diseños responsive para mejorar la experiencia de usuario.
Aprende CSS y certifícateEstilización de inputs, textareas y select
Los elementos de formulario como inputs, textareas y selects son fundamentales en cualquier interfaz web interactiva. Sin embargo, estos elementos suelen tener apariencias predeterminadas que varían entre navegadores, lo que puede afectar la consistencia visual de nuestro diseño.
Estilos básicos para inputs de texto
Empecemos con la estilización básica de los campos de texto. Podemos modificar propiedades como el borde, el relleno, la fuente y los colores para crear una apariencia personalizada:
input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
textarea {
width: 100%;
padding: 10px 12px;
border: 1px solid #ccc;
border-radius: 4px;
font-family: 'Arial', sans-serif;
font-size: 16px;
color: #333;
background-color: #fff;
transition: border-color 0.3s ease;
}
/* Estilo al enfocar el elemento */
input:focus,
textarea:focus {
outline: none;
border-color: #4a90e2;
box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);
}
En este ejemplo, estamos aplicando estilos a varios tipos de inputs y textareas. La propiedad transition
añade un efecto suave cuando el borde cambia de color al enfocar el elemento.
Personalización de textareas
Las textareas tienen algunas propiedades específicas que podemos ajustar:
textarea {
min-height: 120px;
resize: vertical; /* Permite redimensionar solo verticalmente */
line-height: 1.5;
}
/* Evitar que el usuario redimensione la textarea */
textarea.no-resize {
resize: none;
}
La propiedad resize
controla cómo el usuario puede redimensionar el elemento. Con vertical
, solo permitimos el redimensionamiento en dirección vertical, mientras que con none
lo desactivamos completamente.
Estilización de selects
Los elementos select
son más complicados de estilizar debido a que los navegadores aplican sus propios estilos a las flechas desplegables. Podemos crear un diseño personalizado así:
select {
width: 100%;
padding: 10px 12px;
border: 1px solid #ccc;
border-radius: 4px;
font-family: 'Arial', sans-serif;
font-size: 16px;
color: #333;
background-color: #fff;
appearance: none; /* Elimina los estilos nativos del navegador */
background-image: url("data:image/svg+xml;utf8,<svg fill='black' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path d='M7 10l5 5 5-5z'/></svg>");
background-repeat: no-repeat;
background-position: right 10px center;
padding-right: 30px; /* Espacio para la flecha */
}
select:focus {
outline: none;
border-color: #4a90e2;
box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);
}
La propiedad appearance: none
elimina los estilos nativos del navegador, y luego añadimos nuestra propia flecha utilizando una imagen SVG como fondo. Esto nos da mayor control sobre la apariencia del elemento.
Placeholders personalizados
Los placeholders son textos de ayuda que aparecen dentro de los campos cuando están vacíos. Podemos personalizar su apariencia:
::placeholder {
color: #999;
font-style: italic;
opacity: 0.7;
}
/* Para navegadores específicos */
::-webkit-input-placeholder {
color: #999;
font-style: italic;
}
::-moz-placeholder {
color: #999;
font-style: italic;
}
Inputs con iconos
Podemos añadir iconos a nuestros inputs para mejorar la experiencia de usuario:
.input-icon {
position: relative;
}
.input-icon input {
padding-left: 40px; /* Espacio para el icono */
}
.input-icon i {
position: absolute;
left: 12px;
top: 50%;
transform: translateY(-50%);
color: #999;
}
Este CSS debe usarse con una estructura HTML como esta:
<div class="input-icon">
<i class="fa fa-user"></i>
<input type="text" placeholder="Username">
</div>
Estilos para inputs deshabilitados
Es importante proporcionar feedback visual cuando un campo está deshabilitado:
input:disabled,
textarea:disabled,
select:disabled {
background-color: #f5f5f5;
border-color: #ddd;
color: #999;
cursor: not-allowed;
}
Inputs de tipo file
Los inputs de tipo file son notoriamente difíciles de estilizar. Una técnica común es ocultar el input original y crear un diseño personalizado:
.custom-file-input {
position: relative;
display: inline-block;
}
.custom-file-input input[type="file"] {
position: absolute;
left: 0;
top: 0;
opacity: 0;
width: 100%;
height: 100%;
cursor: pointer;
}
.custom-file-button {
display: inline-block;
padding: 10px 15px;
background-color: #4a90e2;
color: white;
border-radius: 4px;
cursor: pointer;
}
.custom-file-input:hover .custom-file-button {
background-color: #3a80d2;
}
Este CSS se utilizaría con HTML como:
<div class="custom-file-input">
<span class="custom-file-button">Choose File</span>
<input type="file">
</div>
Inputs de tipo range
Los inputs de tipo range (deslizadores) también pueden personalizarse:
input[type="range"] {
-webkit-appearance: none;
width: 100%;
height: 8px;
border-radius: 4px;
background: #ddd;
outline: none;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: #4a90e2;
cursor: pointer;
}
input[type="range"]::-moz-range-thumb {
width: 20px;
height: 20px;
border-radius: 50%;
background: #4a90e2;
cursor: pointer;
}
Agrupación de campos
Para crear formularios bien organizados, podemos estilizar grupos de campos:
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: #333;
}
.form-row {
display: flex;
gap: 15px;
}
.form-row .form-group {
flex: 1;
}
Uso de variables CSS para consistencia
Las variables CSS son excelentes para mantener la consistencia en nuestros formularios:
:root {
--input-border: #ccc;
--input-focus-border: #4a90e2;
--input-bg: #fff;
--input-disabled-bg: #f5f5f5;
--input-color: #333;
--input-placeholder: #999;
--input-padding: 10px 12px;
--input-radius: 4px;
}
input,
textarea,
select {
border: 1px solid var(--input-border);
background-color: var(--input-bg);
color: var(--input-color);
padding: var(--input-padding);
border-radius: var(--input-radius);
}
input:focus,
textarea:focus,
select:focus {
border-color: var(--input-focus-border);
}
Compatibilidad entre navegadores
Es importante tener en cuenta que algunos estilos pueden no funcionar de la misma manera en todos los navegadores. Para garantizar la compatibilidad, podemos usar prefijos específicos:
/* Para Firefox */
input, textarea, select {
-moz-appearance: none;
}
/* Para Chrome y Safari */
input, textarea, select {
-webkit-appearance: none;
}
Con estos estilos básicos, puedes crear formularios atractivos y consistentes que mejoren la experiencia de usuario en tu sitio web. Recuerda que la clave está en mantener un equilibrio entre estética y usabilidad, asegurándote de que los elementos sean fácilmente reconocibles como campos de formulario interactivos.
Personalización de checkboxes y radio buttons con CSS
Los checkboxes y radio buttons son elementos de formulario que, por defecto, tienen una apariencia muy básica y difícil de personalizar directamente. Sin embargo, con técnicas modernas de CSS podemos crear versiones personalizadas que mantengan la funcionalidad original mientras ofrecen una estética más acorde con nuestro diseño.
Enfoque básico: ocultar y reemplazar
La estrategia principal para personalizar estos elementos consiste en:
- Ocultar el elemento original
- Crear un elemento visual personalizado
- Mantener la funcionalidad usando el estado
:checked
Veamos cómo implementarlo:
/* Ocultamos el checkbox/radio original pero mantenemos su funcionalidad */
.custom-control input {
position: absolute;
opacity: 0;
cursor: pointer;
height: 0;
width: 0;
}
/* Contenedor que ayuda con el posicionamiento */
.custom-control {
display: block;
position: relative;
padding-left: 35px;
margin-bottom: 12px;
cursor: pointer;
font-size: 16px;
user-select: none;
}
/* Creamos el elemento visual personalizado */
.custom-control .control-indicator {
position: absolute;
top: 0;
left: 0;
height: 20px;
width: 20px;
background-color: #e6e6e6;
transition: background-color 0.2s ease;
}
Es importante usar opacity: 0
en lugar de display: none
para ocultar el input original, ya que esto permite que el elemento siga siendo accesible para usuarios de teclado y lectores de pantalla.
Personalizando checkboxes
Para los checkboxes, necesitamos crear un indicador visual que muestre cuando están marcados:
/* Forma cuadrada para checkboxes */
.custom-checkbox .control-indicator {
border-radius: 3px;
}
/* Estilo cuando el checkbox está marcado */
.custom-checkbox input:checked ~ .control-indicator {
background-color: #4a90e2;
}
/* Creamos el símbolo de check usando pseudo-elementos */
.custom-checkbox input:checked ~ .control-indicator:after {
content: "";
position: absolute;
display: block;
left: 7px;
top: 3px;
width: 5px;
height: 10px;
border: solid white;
border-width: 0 2px 2px 0;
transform: rotate(45deg);
}
El HTML correspondiente sería:
<label class="custom-control custom-checkbox">
<input type="checkbox">
<span class="control-indicator"></span>
Acepto los términos y condiciones
</label>
Personalizando radio buttons
Los radio buttons son similares, pero con forma circular:
/* Forma circular para radio buttons */
.custom-radio .control-indicator {
border-radius: 50%;
}
/* Estilo cuando el radio está seleccionado */
.custom-radio input:checked ~ .control-indicator {
background-color: #4a90e2;
}
/* Creamos el círculo interior */
.custom-radio input:checked ~ .control-indicator:after {
content: "";
position: absolute;
display: block;
top: 6px;
left: 6px;
width: 8px;
height: 8px;
border-radius: 50%;
background: white;
}
El HTML correspondiente:
<label class="custom-control custom-radio">
<input type="radio" name="radio-group">
<span class="control-indicator"></span>
Opción 1
</label>
Estados adicionales
Es importante estilizar también los diferentes estados de interacción:
/* Estado hover */
.custom-control:hover input ~ .control-indicator {
background-color: #ccc;
}
.custom-control:hover input:checked ~ .control-indicator {
background-color: #3a80d2;
}
/* Estado focus (accesibilidad) */
.custom-control input:focus ~ .control-indicator {
box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.3);
}
/* Estado disabled */
.custom-control input:disabled ~ .control-indicator {
background-color: #e6e6e6;
opacity: 0.6;
cursor: not-allowed;
}
.custom-control input:disabled ~ .control-text {
color: #999;
cursor: not-allowed;
}
Diseños más elaborados
Podemos crear diseños más sofisticados utilizando transiciones y efectos:
/* Checkbox con efecto de rebote */
.checkbox-bounce .control-indicator {
border: 2px solid #999;
background-color: transparent;
}
.checkbox-bounce input:checked ~ .control-indicator {
background-color: transparent;
border-color: #4a90e2;
transform: scale(1.1);
transition: transform 0.2s ease;
}
.checkbox-bounce input:checked ~ .control-indicator:after {
animation: bounce 0.2s ease-out;
}
@keyframes bounce {
0% { transform: scale(0) rotate(45deg); }
70% { transform: scale(1.2) rotate(45deg); }
100% { transform: scale(1) rotate(45deg); }
}
Checkboxes tipo switch (toggle)
Un diseño popular es el estilo "switch" o "toggle", que se asemeja a un interruptor:
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 34px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: .4s;
border-radius: 34px;
}
.slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
transition: .4s;
border-radius: 50%;
}
input:checked + .slider {
background-color: #4a90e2;
}
input:checked + .slider:before {
transform: translateX(26px);
}
El HTML para este switch sería:
<label class="switch">
<input type="checkbox">
<span class="slider"></span>
</label>
Grupos de radio buttons con diseño de pestañas
Podemos crear grupos de radio buttons que parezcan pestañas o botones:
.radio-tabs {
display: flex;
border-radius: 5px;
overflow: hidden;
border: 1px solid #ddd;
}
.radio-tabs label {
flex: 1;
text-align: center;
padding: 10px;
cursor: pointer;
background-color: #f5f5f5;
transition: background-color 0.3s;
}
.radio-tabs input[type="radio"] {
position: absolute;
opacity: 0;
}
.radio-tabs input[type="radio"]:checked + label {
background-color: #4a90e2;
color: white;
}
El HTML correspondiente:
<div class="radio-tabs">
<input type="radio" id="tab1" name="tabs" checked>
<label for="tab1">Opción 1</label>
<input type="radio" id="tab2" name="tabs">
<label for="tab2">Opción 2</label>
<input type="radio" id="tab3" name="tabs">
<label for="tab3">Opción 3</label>
</div>
Consideraciones de accesibilidad
Al personalizar estos elementos, es crucial mantener la accesibilidad:
/* Aseguramos que el foco sea visible */
.custom-control input:focus ~ .control-indicator {
outline: 2px solid #4a90e2;
outline-offset: 2px;
}
/* Soporte para navegación por teclado */
.custom-control input:focus-visible ~ .control-indicator {
box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.5);
}
También es importante mantener un contraste adecuado entre los colores de fondo y primer plano, y asegurarse de que el tamaño de los elementos sea suficientemente grande para facilitar la interacción táctil (mínimo 44×44 píxeles según las pautas WCAG).
Uso de variables CSS para temas
Podemos usar variables CSS para facilitar cambios de tema:
:root {
--checkbox-size: 20px;
--checkbox-color: #4a90e2;
--checkbox-checked-color: #4a90e2;
--checkbox-border-color: #ddd;
--checkbox-border-radius: 3px;
--radio-size: 20px;
--radio-color: #4a90e2;
}
.custom-checkbox .control-indicator {
width: var(--checkbox-size);
height: var(--checkbox-size);
border-radius: var(--checkbox-border-radius);
border: 1px solid var(--checkbox-border-color);
}
.custom-checkbox input:checked ~ .control-indicator {
background-color: var(--checkbox-checked-color);
}
Esta técnica permite cambiar fácilmente el aspecto de todos los checkboxes y radio buttons modificando solo las variables, lo que resulta especialmente útil para implementar modos claro/oscuro o diferentes temas de color.
Estados de validación y feedback visual (:valid, :invalid)
Proporcionar retroalimentación visual sobre la validación de formularios es esencial para mejorar la experiencia del usuario. CSS ofrece pseudo-clases específicas que nos permiten estilizar los campos de formulario según su estado de validación, sin necesidad de JavaScript.
Pseudo-clases de validación en CSS
Las principales pseudo-clases para validación de formularios son:
- :valid - Se aplica cuando el campo cumple con sus restricciones de validación
- :invalid - Se aplica cuando el campo no cumple con sus restricciones
- :required - Se aplica a elementos con el atributo
required
- :optional - Se aplica a elementos sin el atributo
required
- :in-range y :out-of-range - Para inputs numéricos con restricciones min/max
- :user-invalid - Una versión más reciente que se activa después de la interacción del usuario
Veamos cómo implementar estos estados de validación:
/* Estilos básicos para todos los inputs */
input {
border: 2px solid #ccc;
border-radius: 4px;
padding: 8px 12px;
font-size: 16px;
transition: all 0.3s ease;
}
/* Estilo para campos válidos */
input:valid {
border-color: #4CAF50;
}
/* Estilo para campos inválidos */
input:invalid {
border-color: #F44336;
}
Mejorando la experiencia con indicadores visuales
Podemos añadir indicadores visuales más claros utilizando pseudo-elementos:
/* Contenedor para posicionar los iconos */
.form-field {
position: relative;
margin-bottom: 20px;
}
/* Añadir iconos de validación */
.form-field input:valid + .validation-icon::before {
content: "✓";
color: #4CAF50;
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
}
.form-field input:invalid + .validation-icon::before {
content: "✗";
color: #F44336;
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
}
Este código requiere una estructura HTML como esta:
<div class="form-field">
<input type="email" required>
<span class="validation-icon"></span>
</div>
Evitando la validación inmediata
Un problema común es que los campos se muestran como inválidos inmediatamente al cargar la página, antes de que el usuario tenga oportunidad de completarlos. Podemos resolver esto con CSS:
/* Solo mostrar estado inválido después de interactuar con el campo */
input:not(:focus):not(:placeholder-shown):invalid {
border-color: #F44336;
}
/* Solo mostrar estado válido después de interactuar con el campo */
input:not(:focus):not(:placeholder-shown):valid {
border-color: #4CAF50;
}
El selector :not(:placeholder-shown)
asegura que los estilos solo se apliquen cuando el usuario ha comenzado a escribir algo.
Mensajes de error personalizados
Podemos mostrar mensajes de error específicos utilizando el atributo data-error-message
y pseudo-elementos:
.form-field {
position: relative;
margin-bottom: 30px; /* Espacio para el mensaje de error */
}
.form-field input:invalid {
margin-bottom: 5px;
}
/* Mostrar mensaje de error personalizado */
.form-field input:not(:focus):not(:placeholder-shown):invalid ~ .error-message {
display: block;
color: #F44336;
font-size: 12px;
margin-top: 5px;
}
.form-field .error-message {
display: none;
}
Con HTML como:
<div class="form-field">
<input type="email" required placeholder="Email">
<span class="error-message">Por favor, introduce un email válido</span>
</div>
Validación específica por tipo de input
Diferentes tipos de inputs tienen diferentes reglas de validación:
/* Email inválido */
input[type="email"]:invalid {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="%23F44336"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/></svg>');
background-position: right 10px center;
background-repeat: no-repeat;
background-size: 20px;
padding-right: 40px;
}
/* Número fuera de rango */
input[type="number"]:out-of-range {
background-color: rgba(244, 67, 54, 0.1);
}
/* Campo requerido vacío */
input:required:placeholder-shown {
border-color: #FFC107; /* Color de advertencia */
}
Estilizando patrones personalizados
El atributo pattern
permite definir expresiones regulares para validación. Podemos estilizar estos campos:
/* Campo con patrón personalizado */
input[pattern]:valid {
border-color: #4CAF50;
}
input[pattern]:invalid:not(:placeholder-shown) {
border-color: #F44336;
}
Animaciones para feedback más dinámico
Las animaciones pueden hacer que el feedback sea más notorio:
@keyframes shake {
0%, 100% { transform: translateX(0); }
20%, 60% { transform: translateX(-5px); }
40%, 80% { transform: translateX(5px); }
}
input:invalid:focus {
animation: shake 0.5s ease;
}
@keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(76, 175, 80, 0.4); }
70% { box-shadow: 0 0 0 10px rgba(76, 175, 80, 0); }
100% { box-shadow: 0 0 0 0 rgba(76, 175, 80, 0); }
}
input:valid:not(:focus) {
animation: pulse 1s;
}
Validación de formulario completo
Podemos estilizar el botón de envío basándonos en la validez del formulario:
/* Deshabilitar visualmente el botón si hay campos inválidos */
button[type="submit"] {
background-color: #4CAF50;
color: white;
padding: 10px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s;
}
/* Selector que verifica si hay algún campo inválido en el formulario */
form:invalid button[type="submit"] {
background-color: #cccccc;
cursor: not-allowed;
opacity: 0.7;
}
Estilos para diferentes niveles de validación
Podemos crear un sistema visual que indique diferentes niveles de fortaleza, por ejemplo para contraseñas:
/* Estilos base */
.password-field input {
border: 2px solid #ccc;
}
/* Contraseña débil (solo cumple requisito mínimo) */
.password-field input:valid.strength-weak {
border-color: #FFC107;
}
/* Contraseña media */
.password-field input:valid.strength-medium {
border-color: #2196F3;
}
/* Contraseña fuerte */
.password-field input:valid.strength-strong {
border-color: #4CAF50;
}
Este enfoque requiere JavaScript para añadir las clases según la fortaleza de la contraseña.
Usando variables CSS para temas consistentes
Las variables CSS nos permiten mantener un sistema de feedback visual coherente:
:root {
--color-valid: #4CAF50;
--color-invalid: #F44336;
--color-warning: #FFC107;
--color-neutral: #ccc;
--input-border-width: 2px;
--input-border-radius: 4px;
--input-padding: 10px 12px;
--error-font-size: 12px;
--error-margin-top: 5px;
}
input:valid {
border-color: var(--color-valid);
}
input:invalid:not(:placeholder-shown) {
border-color: var(--color-invalid);
}
.error-message {
color: var(--color-invalid);
font-size: var(--error-font-size);
margin-top: var(--error-margin-top);
}
Compatibilidad entre navegadores
Algunos navegadores implementan estas pseudo-clases de manera diferente:
/* Para navegadores que no soportan :placeholder-shown */
@supports not selector(:placeholder-shown) {
input:invalid:not(:focus) {
border-color: var(--color-invalid);
}
}
/* Alternativa para navegadores antiguos */
.js-has-error {
border-color: var(--color-invalid);
}
.js-is-valid {
border-color: var(--color-valid);
}
Las clases con prefijo js-
serían añadidas mediante JavaScript como fallback.
Ejemplo completo de un sistema de validación
Veamos un ejemplo completo que integra varias de estas técnicas:
/* Estilos base para campos de formulario */
.form-control {
position: relative;
margin-bottom: 25px;
}
.form-control input,
.form-control textarea,
.form-control select {
width: 100%;
padding: 12px;
border: 2px solid #ddd;
border-radius: 4px;
font-size: 16px;
transition: all 0.3s;
}
/* Estados de foco */
.form-control input:focus,
.form-control textarea:focus,
.form-control select:focus {
outline: none;
border-color: #2196F3;
box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);
}
/* Estados de validación - solo después de interacción */
.form-control input:not(:focus):not(:placeholder-shown):valid,
.form-control textarea:not(:focus):not(:placeholder-shown):valid,
.form-control select:valid {
border-color: #4CAF50;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="%234CAF50"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"/></svg>');
background-position: right 10px center;
background-repeat: no-repeat;
background-size: 20px;
padding-right: 40px;
}
.form-control input:not(:focus):not(:placeholder-shown):invalid,
.form-control textarea:not(:focus):not(:placeholder-shown):invalid,
.form-control select:invalid:not(:focus) {
border-color: #F44336;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="%23F44336"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/></svg>');
background-position: right 10px center;
background-repeat: no-repeat;
background-size: 20px;
padding-right: 40px;
}
/* Mensajes de error */
.form-control .error-message {
display: none;
color: #F44336;
font-size: 12px;
margin-top: 5px;
}
.form-control input:not(:focus):not(:placeholder-shown):invalid ~ .error-message,
.form-control select:invalid:not(:focus) ~ .error-message {
display: block;
}
Este sistema proporciona feedback visual claro y consistente, mejorando significativamente la experiencia del usuario al completar formularios.
Diseño responsive de formularios y layout adaptable
Crear formularios que funcionen bien en todos los dispositivos es esencial para una experiencia de usuario óptima. Un formulario que se ve y funciona perfectamente en un ordenador de escritorio puede resultar frustrante en un dispositivo móvil si no está correctamente adaptado. Vamos a explorar cómo diseñar formularios responsivos utilizando CSS moderno.
Fundamentos del diseño responsive para formularios
La base de cualquier diseño responsive es utilizar unidades flexibles y media queries para adaptar el contenido a diferentes tamaños de pantalla:
.form-container {
width: 100%;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
/* Ajuste para pantallas pequeñas */
@media (max-width: 480px) {
.form-container {
padding: 15px 10px;
}
}
Este enfoque establece un ancho máximo para el formulario en pantallas grandes, mientras que en dispositivos móviles ocupa el ancho completo disponible con un padding reducido.
Estructuras de layout flexibles
Flexbox y Grid son herramientas poderosas para crear layouts de formularios adaptables:
/* Layout con Flexbox */
.form-row {
display: flex;
flex-wrap: wrap;
gap: 20px;
margin-bottom: 20px;
}
.form-column {
flex: 1 1 200px; /* Grow, shrink, base width */
}
/* Layout con Grid */
.form-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 20px;
}
El layout con Flexbox permite que los elementos se ajusten automáticamente, mientras que Grid crea una estructura más precisa donde las columnas tienen un ancho mínimo de 200px y se ajustan automáticamente según el espacio disponible.
Adaptación de campos de formulario
Los campos de formulario deben adaptarse correctamente a diferentes tamaños de pantalla:
input,
select,
textarea {
width: 100%;
padding: 12px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px; /* Tamaño mínimo recomendado para evitar zoom en iOS */
box-sizing: border-box; /* Importante: incluye padding en el ancho total */
}
/* Ajuste de altura para textareas */
textarea {
min-height: 100px;
resize: vertical;
}
/* Ajuste para pantallas táctiles */
@media (max-width: 768px) {
input,
select,
textarea {
padding: 15px; /* Áreas táctiles más grandes */
}
}
La propiedad box-sizing: border-box
es crucial para que el padding no afecte el ancho total del elemento, lo que podría romper el layout en pantallas pequeñas.
Formularios multi-columna adaptables
Para formularios con múltiples columnas, podemos crear un diseño que se adapte a diferentes tamaños de pantalla:
.form-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 30px;
}
.form-section {
background-color: #f9f9f9;
padding: 20px;
border-radius: 8px;
}
@media (max-width: 768px) {
.form-container {
grid-template-columns: 1fr; /* Una sola columna en móviles */
}
}
Este código crea un formulario con secciones que se organizan en múltiples columnas en pantallas grandes, pero se apilan verticalmente en dispositivos móviles.
Etiquetas adaptables
La posición de las etiquetas puede cambiar según el tamaño de la pantalla:
.form-group {
margin-bottom: 20px;
}
/* Etiquetas al lado del campo en pantallas grandes */
@media (min-width: 768px) {
.form-group {
display: flex;
align-items: center;
}
.form-group label {
flex: 0 0 30%;
padding-right: 15px;
text-align: right;
}
.form-group .input-container {
flex: 0 0 70%;
}
}
/* Etiquetas encima del campo en pantallas pequeñas */
@media (max-width: 767px) {
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 500;
}
}
Este enfoque coloca las etiquetas al lado de los campos en pantallas grandes, pero las mueve encima de los campos en dispositivos móviles para aprovechar mejor el espacio horizontal limitado.
Botones adaptables
Los botones de formulario también deben adaptarse a diferentes tamaños de pantalla:
.form-buttons {
display: flex;
justify-content: space-between;
gap: 15px;
margin-top: 30px;
}
.btn {
padding: 12px 20px;
border: none;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
transition: background-color 0.3s;
}
.btn-primary {
background-color: #4a90e2;
color: white;
}
.btn-secondary {
background-color: #f5f5f5;
color: #333;
}
@media (max-width: 480px) {
.form-buttons {
flex-direction: column;
}
.btn {
width: 100%;
padding: 15px;
margin-bottom: 10px;
}
}
En pantallas grandes, los botones se muestran uno al lado del otro, mientras que en dispositivos móviles se apilan verticalmente y ocupan todo el ancho disponible para facilitar la interacción táctil.
Grupos de campos adaptables
Para grupos de campos relacionados, como información de dirección o datos de tarjeta de crédito:
.field-group {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 15px;
}
/* Campos específicos que necesitan diferentes anchos */
.field-group .field-zip {
grid-column: span 1;
}
.field-group .field-city {
grid-column: span 2;
}
@media (max-width: 480px) {
.field-group {
grid-template-columns: 1fr; /* Una columna en móviles */
}
.field-group .field-city,
.field-group .field-zip {
grid-column: span 1; /* Todos los campos ocupan el ancho completo */
}
}
Este enfoque permite que los campos se organicen de manera eficiente en diferentes tamaños de pantalla, con algunos campos ocupando más espacio que otros cuando es necesario.
Optimización para dispositivos táctiles
En dispositivos táctiles, es importante aumentar el tamaño de los elementos interactivos:
@media (max-width: 768px) {
/* Aumentar el tamaño de los elementos interactivos */
input,
select,
textarea,
button {
min-height: 44px; /* Tamaño mínimo recomendado para áreas táctiles */
}
/* Aumentar el espacio entre elementos */
.form-group {
margin-bottom: 25px;
}
/* Hacer que los checkboxes y radio buttons sean más fáciles de tocar */
.custom-control {
padding-left: 45px; /* Más espacio para el área táctil */
}
.custom-control .control-indicator {
width: 30px;
height: 30px;
}
}
Estos ajustes hacen que los formularios sean más fáciles de usar en dispositivos táctiles, reduciendo errores y frustraciones.
Formularios con pasos (multi-step forms)
Para formularios largos, una técnica común es dividirlos en pasos o secciones:
.form-steps {
display: flex;
margin-bottom: 30px;
border-bottom: 1px solid #eee;
padding-bottom: 15px;
}
.step {
flex: 1;
text-align: center;
padding: 10px;
position: relative;
}
.step.active {
font-weight: bold;
color: #4a90e2;
}
.step-content {
display: none;
}
.step-content.active {
display: block;
}
@media (max-width: 600px) {
.form-steps {
flex-direction: column;
border-bottom: none;
}
.step {
text-align: left;
padding: 10px 15px;
border-left: 3px solid #eee;
margin-bottom: 5px;
}
.step.active {
border-left-color: #4a90e2;
background-color: rgba(74, 144, 226, 0.1);
}
}
Este diseño muestra los pasos horizontalmente en pantallas grandes, pero los apila verticalmente en dispositivos móviles para una mejor legibilidad.
Uso de clamp() para tamaños responsivos
La función clamp()
es perfecta para crear elementos que se ajustan automáticamente:
.form-container {
width: clamp(300px, 90%, 800px);
padding: clamp(15px, 3vw, 30px);
}
input,
select,
textarea {
font-size: clamp(14px, 1vw + 10px, 18px);
padding: clamp(8px, 1.5vw, 15px);
}
Esta técnica establece un valor mínimo, un valor preferido (que cambia según el viewport) y un valor máximo, lo que permite un ajuste fluido sin necesidad de múltiples media queries.
Consideraciones de accesibilidad en diseños responsivos
La accesibilidad debe mantenerse en todos los tamaños de pantalla:
/* Asegurar que el foco sea visible en todos los dispositivos */
input:focus,
select:focus,
textarea:focus,
button:focus {
outline: 3px solid rgba(74, 144, 226, 0.5);
outline-offset: 2px;
}
/* Aumentar contraste en dispositivos móviles (que a menudo se usan en exteriores) */
@media (max-width: 768px) {
label {
color: #000; /* Mayor contraste */
}
.form-group .helper-text {
color: #333; /* Texto de ayuda más oscuro */
}
}
Estas consideraciones ayudan a que el formulario sea utilizable por todos los usuarios, independientemente del dispositivo o sus capacidades.
Ejemplo completo de un formulario responsive
Combinando todas estas técnicas, podemos crear un formulario completamente responsive:
/* Variables para consistencia */
:root {
--form-spacing: clamp(15px, 3vw, 25px);
--input-height: clamp(40px, 5vw + 10px, 50px);
--border-radius: 4px;
--primary-color: #4a90e2;
--error-color: #e74c3c;
--success-color: #2ecc71;
--text-color: #333;
--bg-color: #fff;
--border-color: #ddd;
}
/* Contenedor principal */
.responsive-form {
width: 100%;
max-width: 800px;
margin: 0 auto;
padding: var(--form-spacing);
background-color: var(--bg-color);
}
/* Grupos de campos */
.form-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: var(--form-spacing);
margin-bottom: var(--form-spacing);
}
/* Campos individuales */
.form-field {
margin-bottom: var(--form-spacing);
}
.form-field label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: var(--text-color);
}
.form-field input,
.form-field select,
.form-field textarea {
width: 100%;
height: var(--input-height);
padding: 0 15px;
border: 1px solid var(--border-color);
border-radius: var(--border-radius);
font-size: 16px;
color: var(--text-color);
background-color: var(--bg-color);
box-sizing: border-box;
}
.form-field textarea {
height: auto;
min-height: 120px;
padding: 15px;
}
/* Botones */
.form-actions {
display: flex;
justify-content: flex-end;
gap: 15px;
margin-top: calc(var(--form-spacing) * 1.5);
}
.btn {
height: var(--input-height);
padding: 0 25px;
border: none;
border-radius: var(--border-radius);
font-size: 16px;
cursor: pointer;
transition: background-color 0.3s, transform 0.2s;
}
.btn-primary {
background-color: var(--primary-color);
color: white;
}
.btn-secondary {
background-color: #f5f5f5;
color: var(--text-color);
}
/* Adaptaciones para móviles */
@media (max-width: 600px) {
.form-actions {
flex-direction: column;
gap: 10px;
}
.btn {
width: 100%;
}
/* Campos que deben ocupar todo el ancho */
.full-width-mobile {
grid-column: 1 / -1;
}
}
Este código crea un formulario que se adapta fluidamente a diferentes tamaños de pantalla, manteniendo la usabilidad y la estética en todos los dispositivos.
Optimización del rendimiento
Para garantizar que los formularios responsivos se carguen y funcionen rápidamente:
/* Usar will-change solo cuando sea necesario */
.btn:hover {
will-change: transform;
}
/* Preferir transform sobre propiedades que causan reflow */
.btn:active {
transform: scale(0.98);
}
/* Limitar animaciones en dispositivos que prefieren reducir el movimiento */
@media (prefers-reduced-motion: reduce) {
.btn,
input,
select,
textarea {
transition: none;
}
}
Estas optimizaciones ayudan a que el formulario se sienta más rápido y consuma menos recursos, especialmente en dispositivos móviles con capacidades limitadas.
Ejercicios de esta lección CSS para formularios
Evalúa tus conocimientos de esta lección CSS para formularios con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.
Reto modelo caja CSS
Propiedades de posicionamiento
Modelo de caja
Sombras en texto y cajas
Reto implementación de fuentes web
Sintaxis básica
Estilos de fuente
Diseño responsive con media queries
Animaciones y transiciones
Proyecto CSS Landing page simple
Reto unidades de medida
Propiedades de texto
Metodologías BEM, SMACSS, OOCSS
Herencia y cascada
Sintaxis avanzada
Reto fondos background CSS
Reto sintaxis CSS
Flexbox en diseños modernos
Elementos 'float' y 'clear'
Pseudo-clases y pseudo-elementos
Reto grid de columnas en CSS
Selectores avanzados
Reto componente responsive
Reto formulario estilizado
Proyecto CSS crear una navbar
Proyecto CSS Dashboard Responsive
Reto Flexbox Hero
Propiedades de fondo
Introducción a CSS
Reto selectores básicos CSS
Reto Flexbox Card
Reto propiedades texto
Modelo de caja
Propiedad 'display'
Variables en CSS
Grid en diseños de cuadrícula
Selectores básicos
Reto tema claro/oscuro con variables
Reto especificidad y cascada
Todas las lecciones de CSS
Accede a todas las lecciones de CSS y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A Css
Introducción Y Entorno
Entorno Para Desarrollar Css
Introducción Y Entorno
Sintaxis
Sintaxis De Selectores Y Propiedades
Selectores Básicos
Sintaxis De Selectores Y Propiedades
Herencia Y Cascada
Sintaxis De Selectores Y Propiedades
Pseudo-clases Y Pseudo-elementos
Sintaxis De Selectores Y Propiedades
Colores En Css
Sintaxis De Selectores Y Propiedades
Unidades De Medida
Sintaxis De Selectores Y Propiedades
Especificidad
Sintaxis De Selectores Y Propiedades
Estilos De Fuente
Estilización De Texto Y Fondo
Propiedades De Texto
Estilización De Texto Y Fondo
Sombras En Texto Y Cajas
Estilización De Texto Y Fondo
Propiedades De Fondo
Estilización De Texto Y Fondo
Fuentes Web
Estilización De Texto Y Fondo
Efectos De Texto: Gradientes, Recortes
Estilización De Texto Y Fondo
Tipografía Avanzada
Estilización De Texto Y Fondo
Modelo De Caja
Modelo Caja
Propiedades De Posicionamiento
Modelo Caja
Propiedad 'Display'
Modelo Caja
Elementos 'Float' Y 'Clear'
Modelo Caja
Rellenos Y Márgenes
Modelo Caja
Bordes Y Contornos
Modelo Caja
Absolute, Fixed, Sticky Y Z-index
Posicionamiento
Flexbox Para Crear Layouts Y Estructuras
Flexbox
Css Grid Para Crear Layouts Y Estructuras
Flexbox
Propiedades Del Contenedor Flex
Flexbox
Propiedades De Los Items Flex
Flexbox
Columnas Y Filas En Grid
Css Grid
Espaciado Y Alineación
Css Grid
Tipografía Responsive
Diseño Responsive
Fundamentos Del Diseño Responsive
Diseño Responsive
Imágenes Responsive
Diseño Responsive
Funciones Matemáticas
Variables Y Funciones Css
Transformaciones 2d
Transformación, Transición, Animación
Transformaciones 3d
Transformación, Transición, Animación
Animaciones
Transformación, Transición, Animación
Transiciones
Transformación, Transición, Animación
Css Para Formularios
Css Avanzado
Accesibilidad Web Con Css
Css Avanzado
Container Queries
Css Avanzado
Selectores Avanzados
Css Avanzado
Animaciones Y Transiciones
Técnicas Modernas Y Metodologías
Variables En Css
Técnicas Modernas Y Metodologías
Diseño Responsive Con Media Queries
Técnicas Modernas Y Metodologías
Metodologías De Escritura En Css
Técnicas Modernas Y Metodologías
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender cómo personalizar la apariencia de inputs, textareas y selects para lograr un diseño consistente.
- Aprender técnicas para personalizar checkboxes y radio buttons manteniendo la accesibilidad.
- Implementar estados de validación visual usando pseudo-clases CSS para mejorar la experiencia de usuario.
- Diseñar formularios responsivos que se adapten a diferentes dispositivos y tamaños de pantalla.
- Utilizar variables CSS y técnicas modernas para mantener la consistencia y facilitar el mantenimiento del estilo.