CSS

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

Estilizació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:

  1. Ocultar el elemento original
  2. Crear un elemento visual personalizado
  3. 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.

CONSTRUYE TU CARRERA EN IA Y PROGRAMACIÓN SOFTWARE

Accede a +1000 lecciones y cursos con certificado. Mejora tu portfolio con certificados de superación para tu CV.

Plan mensual

19.00 € /mes

Precio normal mensual: 19 €
47 % DE DESCUENTO

Plan anual

10.00 € /mes

Ahorras 108 € al año
Precio normal anual: 120 €
Aprende CSS online

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.

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

CSS

Introducción Y Entorno

Entorno Para Desarrollar Css

CSS

Introducción Y Entorno

Sintaxis

CSS

Sintaxis De Selectores Y Propiedades

Selectores Básicos

CSS

Sintaxis De Selectores Y Propiedades

Herencia Y Cascada

CSS

Sintaxis De Selectores Y Propiedades

Pseudo-clases Y Pseudo-elementos

CSS

Sintaxis De Selectores Y Propiedades

Colores En Css

CSS

Sintaxis De Selectores Y Propiedades

Unidades De Medida

CSS

Sintaxis De Selectores Y Propiedades

Especificidad

CSS

Sintaxis De Selectores Y Propiedades

Estilos De Fuente

CSS

Estilización De Texto Y Fondo

Propiedades De Texto

CSS

Estilización De Texto Y Fondo

Sombras En Texto Y Cajas

CSS

Estilización De Texto Y Fondo

Propiedades De Fondo

CSS

Estilización De Texto Y Fondo

Fuentes Web

CSS

Estilización De Texto Y Fondo

Efectos De Texto: Gradientes, Recortes

CSS

Estilización De Texto Y Fondo

Tipografía Avanzada

CSS

Estilización De Texto Y Fondo

Modelo De Caja

CSS

Modelo Caja

Propiedades De Posicionamiento

CSS

Modelo Caja

Propiedad 'Display'

CSS

Modelo Caja

Elementos 'Float' Y 'Clear'

CSS

Modelo Caja

Rellenos Y Márgenes

CSS

Modelo Caja

Bordes Y Contornos

CSS

Modelo Caja

Absolute, Fixed, Sticky Y Z-index

CSS

Posicionamiento

Flexbox Para Crear Layouts Y Estructuras

CSS

Flexbox

Css Grid Para Crear Layouts Y Estructuras

CSS

Flexbox

Propiedades Del Contenedor Flex

CSS

Flexbox

Propiedades De Los Items Flex

CSS

Flexbox

Columnas Y Filas En Grid

CSS

Css Grid

Espaciado Y Alineación

CSS

Css Grid

Tipografía Responsive

CSS

Diseño Responsive

Fundamentos Del Diseño Responsive

CSS

Diseño Responsive

Imágenes Responsive

CSS

Diseño Responsive

Funciones Matemáticas

CSS

Variables Y Funciones Css

Transformaciones 2d

CSS

Transformación, Transición, Animación

Transformaciones 3d

CSS

Transformación, Transición, Animación

Animaciones

CSS

Transformación, Transición, Animación

Transiciones

CSS

Transformación, Transición, Animación

Css Para Formularios

CSS

Css Avanzado

Accesibilidad Web Con Css

CSS

Css Avanzado

Container Queries

CSS

Css Avanzado

Selectores Avanzados

CSS

Css Avanzado

Animaciones Y Transiciones

CSS

Técnicas Modernas Y Metodologías

Variables En Css

CSS

Técnicas Modernas Y Metodologías

Diseño Responsive Con Media Queries

CSS

Técnicas Modernas Y Metodologías

Metodologías De Escritura En Css

CSS

Técnicas Modernas Y Metodologías

Accede GRATIS a CSS y certifícate

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.