Tutorial WordPress: Estilizar formularios de Contact Form 7 solo con CSS

·

·

Introducción

Contact Form 7 (CF7) es uno de los formularios más usados en WordPress. Por defecto su estética depende del tema y de estilos básicos del plugin, por lo que casi siempre conviene personalizarlo con CSS para integrarlo visualmente con el resto del sitio. Este artículo explica, con todo lujo de detalles, cómo estilizar formularios creados con Contact Form 7 solo con CSS. No se requieren modificaciones en PHP ni plugins adicionales: solo CSS y conocimiento de la estructura HTML que CF7 genera.

Requisitos y buenas prácticas previas

Entendiendo la estructura HTML que genera CF7

CF7 genera estructuras como estas (simplificado):

Las clases principales a recordar: .wpcf7-form, .wpcf7-form-control, .wpcf7-text, .wpcf7-textarea, .wpcf7-submit, .wpcf7-form-control-wrap, .wpcf7-list-item y .wpcf7-response-output. Además hay clases que CF7 añade cuando hay errores: .wpcf7-not-valid, y para los mensajes .wpcf7-mail-sent-ok, .wpcf7-validation-errors.

Variables CSS y reset base

Empezar con variables facilita cambiar rápidamente colores y radios. Incluye un pequeño reset para inputs y textareas.

:root{
  --cf7-bg:#ffffff
  --cf7-border:#d0d5da
  --cf7-accent:#1366d6
  --cf7-accent-600:#0f53b0
  --cf7-text:#1f2630
  --cf7-radius:8px
  --cf7-transition:.18s ease
}

/ Scope recommended: si usas la clase html_class en el shortcode, reemplaza .mi-formulario por tu clase /
.mi-formulario .wpcf7-form,
.wpcf7-form {
  font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica Neue, Arial
  color:var(--cf7-text)
}

/ Reset visual básico /
.mi-formulario .wpcf7-form-control,
.wpcf7-form .wpcf7-form-control {
  box-sizing:border-box
  width:100%
  margin:0
  padding:0
  border:0
  background:transparent
}

Estilizar inputs, textarea y select

Crear inputs coherentes: fondo, borde, radio, padding y focus. Controla placeholder y estados deshabilitados.

/ Inputs y textarea /
.mi-formulario .wpcf7-form-control-wrap input[type=text],
.mi-formulario .wpcf7-form-control-wrap input[type=email],
.mi-formulario .wpcf7-form-control-wrap input[type=tel],
.mi-formulario .wpcf7-form-control-wrap input[type=url],
.mi-formulario .wpcf7-form-control-wrap textarea,
.mi-formulario .wpcf7-form-control-wrap select {
  background:var(--cf7-bg)
  border:1px solid var(--cf7-border)
  border-radius:var(--cf7-radius)
  padding:12px 14px
  font-size:15px
  color:var(--cf7-text)
  transition:border-color var(--cf7-transition), box-shadow var(--cf7-transition), transform var(--cf7-transition)
  min-height:44px
}

/ Textarea específico /
.mi-formulario .wpcf7-textarea {
  min-height:120px
  resize:vertical
  padding-top:12px
}

/ Placeholder /
.mi-formulario .wpcf7-form-control::placeholder {
  color: #9aa3b2
}

/ Disabled /
.mi-formulario .wpcf7-form-control[disabled],
.mi-formulario .wpcf7-form-control[readonly] {
  opacity:.6
  cursor:not-allowed
}

Focus, validación visual y mensajes de error

Señala el foco para accesibilidad y mejora las validaciones que CF7 expone con clases.

/ Focus accesible /
.mi-formulario .wpcf7-form-control:focus {
  outline:none
  border-color:var(--cf7-accent)
  box-shadow:0 0 0 4px rgba(19,102,214,0.12)
}

/ Estado inválido marcado por CF7 /
.mi-formulario .wpcf7-not-valid,
.mi-formulario .wpcf7-not-valid .wpcf7-form-control,
.mi-formulario .wpcf7-form-control.wpcf7-not-valid {
  border-color:#e24b4b !important
  box-shadow:0 0 0 4px rgba(226,75,75,0.10)
}

/ Mensajes de respuesta (éxito / error) /
.mi-formulario .wpcf7-response-output {
  margin-top:12px
  padding:12px 14px
  border-radius:6px
  font-size:14px
  display:none / CF7 muestra/oculta con inline styles esto asegura el estilo base /
}
.mi-formulario .wpcf7-mail-sent-ok.wpcf7-response-output {
  background:#e6f4ea
  border:1px solid #c6ecd3
  color:#116629
  display:block
}
.mi-formulario .wpcf7-validation-errors.wpcf7-response-output {
  background:#fff0f0
  border:1px solid #f3c2c2
  color:#8a1f1f
  display:block
}

Botón de envío (submit)

Diseña un botón coherente con microinteracciones (hover, active) y variaciones con icono.

.mi-formulario .wpcf7-submit {
  display:inline-block
  background:var(--cf7-accent)
  color:#fff
  border:0
  padding:12px 20px
  border-radius:999px
  font-weight:600
  cursor:pointer
  transition:transform var(--cf7-transition), background-color var(--cf7-transition), box-shadow var(--cf7-transition)
  box-shadow:0 6px 18px rgba(13,40,90,0.08)
}

/ Hover / Active /
.mi-formulario .wpcf7-submit:hover {
  background:var(--cf7-accent-600)
  transform:translateY(-2px)
}
.mi-formulario .wpcf7-submit:active {
  transform:translateY(0)
  box-shadow:none
}

/ Envío deshabilitado /
.mi-formulario .wpcf7-submit[disabled] {
  opacity:.6
  cursor:not-allowed
  transform:none
  box-shadow:none
}

Checkboxes y radios personalizados

CF7 suele envolver checkboxes/radios en etiquetas. La técnica consiste en ocultar el input y dibujar un indicador con pseudo-elementos.

/ Estilos base para la lista /
.mi-formulario .wpcf7-list-item {
  display:flex
  align-items:center
  margin-bottom:8px
}

/ Ocultar control nativo pero mantener accesibilidad /
.mi-formulario .wpcf7-list-item input[type=checkbox],
.mi-formulario .wpcf7-list-item input[type=radio] {
  position:absolute
  opacity:0
  width:1px
  height:1px
  margin:-1px
  clip:rect(0 0 0 0)
  overflow:hidden
}

/ Indicador visual /
.mi-formulario .wpcf7-list-item .wpcf7-list-item-label {
  position:relative
  padding-left:34px
  cursor:pointer
  display:inline-block
  line-height:1.2
}

/ Caja visible para checkbox/radio /
.mi-formulario .wpcf7-list-item .wpcf7-list-item-label::before{
  content:
  position:absolute
  left:0
  top:50%
  transform:translateY(-50%)
  width:20px
  height:20px
  border:1px solid var(--cf7-border)
  border-radius:6px
  background:#fff
  box-sizing:border-box
}

/ Marca interna para checked /
.mi-formulario .wpcf7-list-item input[type=checkbox]:checked   .wpcf7-list-item-label::after {
  content:
  position:absolute
  left:5px
  top:50%
  transform:translateY(-50%) rotate(45deg)
  width:6px
  height:10px
  border:solid var(--cf7-accent)
  border-width:0 2px 2px 0
  border-radius:1px
}

/ Radio: forma circular /
.mi-formulario .wpcf7-list-item input[type=radio]   .wpcf7-list-item-label::before{
  border-radius:50%
}
.mi-formulario .wpcf7-list-item input[type=radio]:checked   .wpcf7-list-item-label::after{
  content:
  position:absolute
  left:6px
  top:50%
  transform:translateY(-50%)
  width:8px
  height:8px
  background:var(--cf7-accent)
  border-radius:50%
}

Iconos dentro del input (sin JS)

Usa pseudo-elementos en el contenedor para añadir iconos (fonts o SVG en background). Ejemplo: icono de correo en campo email.

.mi-formulario .wpcf7-form-control-wrap.-icon {
  position:relative
}
.mi-formulario .wpcf7-form-control-wrap.-icon input {
  padding-left:44px
}
.mi-formulario .wpcf7-form-control-wrap.-icon::before{
  content:
  position:absolute
  left:14px
  top:50%
  transform:translateY(-50%)
  width:18px
  height:18px
  background-image:url(/wp-content/uploads/mail-icon.svg)
  background-size:18px 18px
  background-repeat:no-repeat
  opacity:.9
  pointer-events:none
}

Layout y campos lado a lado

Para formularios con varias columnas, usa flexbox o grid. Mantén la adaptabilidad para móviles.

/ Contenedor de filas (puedes envolver campos en .form-row en el editor del formulario) /
.mi-formulario .form-row{
  display:flex
  gap:12px
  flex-wrap:wrap
}
.mi-formulario .form-row .wpcf7-form-control-wrap{
  flex:1 1 220px / flexible mín. 220px /
  min-width:0
}

/ Media query para ajustar en móviles /
@media (max-width:720px){
  .mi-formulario .form-row{
    flex-direction:column
  }
}

Estilizar el cargador y estados AJAX

CF7 puede mostrar un loader (ajax-loader.gif) y clases en envío personalízalo así:

/ Ocultar loader original y crear uno con CSS si se desea /
.mi-formulario .wpcf7-spinner {
  display:inline-block
  width:18px
  height:18px
  border-radius:50%
  border:2px solid rgba(0,0,0,0.08)
  border-top-color:var(--cf7-accent)
  animation:spin 1s linear infinite
  vertical-align:middle
}
@keyframes spin{to{transform:rotate(360deg)}}

/ Durante envío se añade clase .wpcf7-mail-sent-ng o similar el botón puede cambiar /
.mi-formulario .wpcf7-form.is-submitting .wpcf7-submit {
  pointer-events:none
  opacity:.8
}

Técnica avanzada: etiquetas flotantes (floating labels) solo CSS

Si tu marcado coloca la etiqueta antes o después del control puedes usar la técnica con :placeholder-shown. Requiere placeholder vacío en inputs para activarse correctamente en algunos navegadores.

/ Estructura esperada: label   input dentro de .floating /
.mi-formulario .floating {
  position:relative
}
.mi-formulario .floating input,
.mi-formulario .floating textarea {
  padding-top:22px
}
.mi-formulario .floating label{
  position:absolute
  left:12px
  top:14px
  font-size:13px
  color:#6b7280
  transition:transform .18s ease, font-size .18s ease, top .18s ease
  pointer-events:none
}

/ Si el input tiene contenido o focus, mueve la etiqueta arriba /
.mi-formulario .floating input:focus   label,
.mi-formulario .floating input:not(:placeholder-shown)   label,
.mi-formulario .floating textarea:focus   label,
.mi-formulario .floating textarea:not(:placeholder-shown)   label {
  top:-8px
  font-size:12px
  transform:translateY(0)
  color:var(--cf7-accent)
}

Depuración y problemas comunes

  1. Si los estilos no se aplican, comprueba la especificidad: prueba prefijar con la clase de wrapper (.mi-formulario .wpcf7-form …).
  2. CF7 a veces añade estilos en línea al mostrar mensajes tu CSS debería apuntar a las clases (.wpcf7-response-output) y no confiar en estilos inline inesperados.
  3. Si tu tema ya aplica estilos agresivos, inspecciona con las herramientas de desarrollador y utiliza selectores más concretos en lugar de !important.
  4. Comprueba la salida HTML real del formulario (puede variar según campos). Adaptar selectores a la estructura real es esencial.

Checklist de accesibilidad (imprescindible)

Ejemplo completo de CSS listo para pegar

Este bloque es un ejemplo funcional y completo que combina muchas de las técnicas anteriores. Pégalo en el CSS adicional y cambia .mi-formulario por la clase de tu formulario si aplicaste html_class en el shortcode.

:root{
  --cf7-bg:#ffffff
  --cf7-border:#e1e6ec
  --cf7-accent:#0066cc
  --cf7-accent-600:#0055aa
  --cf7-text:#0f1720
  --cf7-radius:8px
  --cf7-transition:.18s ease
}

.mi-formulario .wpcf7-form{
  font-family:system-ui, -apple-system, Segoe UI, Roboto, Helvetica Neue, Arial
  color:var(--cf7-text)
  font-size:15px
}

/ Base inputs /
.mi-formulario .wpcf7-form-control {
  box-sizing:border-box
  width:100%
  background:var(--cf7-bg)
  border:1px solid var(--cf7-border)
  border-radius:var(--cf7-radius)
  padding:12px 14px
  transition:border-color var(--cf7-transition), box-shadow var(--cf7-transition), transform var(--cf7-transition)
}

/ Textarea /
.mi-formulario .wpcf7-textarea { min-height:120px resize:vertical }

/ Focus /
.mi-formulario .wpcf7-form-control:focus{
  outline:none
  border-color:var(--cf7-accent)
  box-shadow:0 0 0 6px rgba(0,102,204,0.08)
}

/ Submit /
.mi-formulario .wpcf7-submit{
  background:var(--cf7-accent)
  color:#fff
  border:0
  padding:12px 20px
  border-radius:999px
  cursor:pointer
  font-weight:600
  transition:transform var(--cf7-transition), background-color var(--cf7-transition)
}
.mi-formulario .wpcf7-submit:hover{ background:var(--cf7-accent-600) transform:translateY(-2px) }

/ Validation states /
.mi-formulario .wpcf7-not-valid .wpcf7-form-control,
.mi-formulario .wpcf7-form-control.wpcf7-not-valid {
  border-color:#d9534f !important
  box-shadow:0 0 0 6px rgba(217,83,79,0.06)
}

/ Response output /
.mi-formulario .wpcf7-response-output{ display:none margin-top:12px padding:12px border-radius:6px font-size:14px }
.mi-formulario .wpcf7-mail-sent-ok.wpcf7-response-output{ display:block background:#eaf7ee border:1px solid #c7eed3 color:#0b5b2f }
.mi-formulario .wpcf7-validation-errors.wpcf7-response-output{ display:block background:#fff2f2 border:1px solid #f3cfcf color:#8a1f1f }

/ Custom checkboxes/radios /
.mi-formulario .wpcf7-list-item{ display:flex align-items:flex-start gap:8px margin-bottom:8px }
.mi-formulario .wpcf7-list-item input{ position:absolute opacity:0 width:1px height:1px margin:-1px clip:rect(0 0 0 0) overflow:hidden }
.mi-formulario .wpcf7-list-item .wpcf7-list-item-label{ position:relative padding-left:34px cursor:pointer }
.mi-formulario .wpcf7-list-item .wpcf7-list-item-label::before{ content: position:absolute left:0 top:50% transform:translateY(-50%) width:20px height:20px border:1px solid var(--cf7-border) border-radius:6px background:#fff }
.mi-formulario .wpcf7-list-item input[type=checkbox]:checked   .wpcf7-list-item-label::after{ content: position:absolute left:5px top:50% transform:translateY(-50%) rotate(45deg) width:6px height:10px border:solid var(--cf7-accent) border-width:0 2px 2px 0 }

/ Responsive rows /
.mi-formulario .form-row{ display:flex gap:12px flex-wrap:wrap }
.mi-formulario .form-row .wpcf7-form-control-wrap{ flex:1 1 220px min-width:0 }
@media(max-width:720px){ .mi-formulario .form-row{ flex-direction:column } }

/ Spinner /
.mi-formulario .wpcf7-spinner{ width:18px height:18px border-radius:50% border:2px solid rgba(0,0,0,0.08) border-top-color:var(--cf7-accent) animation:spin 1s linear infinite }
@keyframes spin{ to{ transform:rotate(360deg) } }

Conclusión

Con CSS puedes transformar por completo el aspecto de un formulario de Contact Form 7 y adaptar su experiencia a tu diseño sin tocar PHP. Identifica la estructura del formulario, usa una clase contenedora para scope si es necesario, aplica variables CSS para mantener la coherencia y no olvides las consideraciones de accesibilidad. El ejemplo completo incluido es un buen punto de partida que puedes copiar y ajustar a tu paleta y tipografías.



Leave a Reply

Your email address will not be published. Required fields are marked *