Cómo crear una landing page con Python y Tailwind CSS

Publicado el: 11/07/2026
Tempo de leitura: 4 minutos
Landing page simples criada com Python e Tailwind CSS

Una landing page es una página enfocada en una acción concreta: registrar usuarios, presentar un producto, captar contactos o promocionar un servicio. Python puede encargarse del servidor, la validación y el procesamiento del formulario, mientras Tailwind CSS facilita construir una interfaz moderna y adaptable. Con Flask, el proyecto puede empezar pequeño y crecer después con base de datos, correo, pruebas y despliegue.

Para seguir esta guía conviene conocer los fundamentos de Flask en Python, la creación de entornos virtuales con venv, el uso de variables de entorno y el manejo de errores con try y except. La página será sencilla, pero tendrá una estructura adecuada para continuar desarrollándola.

Crear el proyecto

mkdir landing-python
cd landing-python
python -m venv .venv

# Windows
.venv\Scripts\activate
# Linux o macOS
source .venv/bin/activate

python -m pip install Flask python-dotenv

La estructura inicial puede ser:

landing-python/
├── app.py
├── .env
├── templates/
│   ├── base.html
│   └── index.html
└── static/
    └── app.js

La documentación oficial de Flask explica plantillas, rutas, formularios, configuración y despliegue.

Crear la aplicación Flask

import os
from flask import Flask, render_template, request, redirect, url_for, flash
from dotenv import load_dotenv

load_dotenv()

app = Flask(__name__)
app.config["SECRET_KEY"] = os.getenv("SECRET_KEY", "cambiar-en-desarrollo")

@app.get("/")
def inicio():
    return render_template("index.html")

if __name__ == "__main__":
    app.run(debug=True)

En producción, SECRET_KEY debe ser larga, aleatoria y almacenada fuera del código. El modo debug tampoco debe permanecer activado públicamente.

Crear la plantilla base

<!doctype html>
<html lang="es">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Producto Simple</title>
  <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-slate-950 text-white">
  {% block contenido %}{% endblock %}
</body>
</html>

El CDN de Tailwind es conveniente para prototipos. La documentación oficial del Play CDN advierte que no es la opción recomendada para producción. Para un sitio publicado, instala Tailwind mediante su proceso de compilación y genera un CSS optimizado.

Construir la sección principal

{% extends "base.html" %}
{% block contenido %}
<main class="min-h-screen">
  <section class="mx-auto grid max-w-6xl gap-12 px-6 py-24 lg:grid-cols-2 lg:items-center">
    <div>
      <span class="rounded-full bg-cyan-400/10 px-3 py-1 text-sm text-cyan-300">
        Automatiza tu trabajo
      </span>
      <h1 class="mt-6 text-4xl font-bold tracking-tight sm:text-6xl">
        Convierte tareas repetitivas en procesos simples
      </h1>
      <p class="mt-6 text-lg text-slate-300">
        Una herramienta creada con Python para organizar datos y ahorrar tiempo.
      </p>
      <a href="#contacto" class="mt-8 inline-block rounded-lg bg-cyan-400 px-6 py-3 font-semibold text-slate-950">
        Solicitar acceso
      </a>
    </div>
    <div class="rounded-3xl border border-white/10 bg-white/5 p-8 shadow-2xl">
      <p class="text-sm text-slate-400">Resultado semanal</p>
      <p class="mt-2 text-5xl font-bold">12 horas</p>
      <p class="mt-3 text-slate-300">de trabajo manual ahorradas</p>
    </div>
  </section>
</main>
{% endblock %}

Las clases responsivas como lg:grid-cols-2 cambian el diseño en pantallas grandes. Mantén un orden visual claro y un único llamado principal a la acción.

Añadir una sección de beneficios

<section class="mx-auto max-w-6xl px-6 py-16">
  <h2 class="text-3xl font-bold">Qué puedes conseguir</h2>
  <div class="mt-10 grid gap-6 md:grid-cols-3">
    {% for beneficio in beneficios %}
      <article class="rounded-2xl border border-white/10 bg-slate-900 p-6">
        <h3 class="text-xl font-semibold">{{ beneficio.titulo }}</h3>
        <p class="mt-3 text-slate-400">{{ beneficio.texto }}</p>
      </article>
    {% endfor %}
  </div>
</section>

En la ruta, envía los datos:

@app.get("/")
def inicio():
    beneficios = [
        {"titulo": "Menos errores", "texto": "Procesos repetibles y verificables."},
        {"titulo": "Más tiempo", "texto": "Automatiza tareas operativas."},
        {"titulo": "Datos claros", "texto": "Genera resultados listos para analizar."},
    ]
    return render_template("index.html", beneficios=beneficios)

Jinja escapa el texto por defecto, lo que ayuda a evitar inyección de HTML. No marques contenido externo como seguro sin validarlo.

Crear un formulario de contacto

<section id="contacto" class="mx-auto max-w-3xl px-6 py-20">
  <form method="post" action="{{ url_for('contacto') }}" class="space-y-5 rounded-3xl bg-white p-8 text-slate-900">
    <div>
      <label for="nombre" class="font-medium">Nombre</label>
      <input id="nombre" name="nombre" required maxlength="100"
             class="mt-2 w-full rounded-lg border px-4 py-3">
    </div>
    <div>
      <label for="email" class="font-medium">Correo</label>
      <input id="email" name="email" type="email" required maxlength="254"
             class="mt-2 w-full rounded-lg border px-4 py-3">
    </div>
    <button class="w-full rounded-lg bg-slate-950 px-6 py-3 font-semibold text-white">
      Enviar solicitud
    </button>
  </form>
</section>

Procesar el formulario

import re

EMAIL = re.compile(r"^[^@\s]+@[^@\s]+\.[^@\s]+$")

@app.post("/contacto")
def contacto():
    nombre = request.form.get("nombre", "").strip()
    email = request.form.get("email", "").strip().lower()

    if not nombre or len(nombre) > 100:
        flash("Escribe un nombre válido.", "error")
        return redirect(url_for("inicio") + "#contacto")

    if not EMAIL.fullmatch(email):
        flash("Escribe un correo válido.", "error")
        return redirect(url_for("inicio") + "#contacto")

    # guardar en base de datos o enviar a un servicio
    flash("Solicitud recibida.", "success")
    return redirect(url_for("inicio") + "#contacto")

La validación del navegador mejora la experiencia, pero el servidor debe validar nuevamente. Un patrón sencillo detecta errores obvios, aunque no confirma que el correo exista.

Mostrar mensajes flash

{% with mensajes = get_flashed_messages(with_categories=true) %}
  {% for categoria, mensaje in mensajes %}
    <div class="mx-auto mt-4 max-w-3xl rounded-lg px-4 py-3
      {{ 'bg-emerald-100 text-emerald-900' if categoria == 'success' else 'bg-red-100 text-red-900' }}">
      {{ mensaje }}
    </div>
  {% endfor %}
{% endwith %}

Proteger el formulario

Una landing page pública recibe bots. Añade límites de frecuencia, un campo trampa oculto o CAPTCHA cuando sea necesario. Si el formulario modifica datos sensibles o autentica usuarios, implementa protección CSRF mediante una biblioteca como Flask-WTF.

No registres mensajes completos con datos personales sin necesidad. Define una política de retención y explica para qué se utilizará la información.

Guardar contactos en SQLite

import sqlite3

def guardar_contacto(nombre, email):
    with sqlite3.connect("contactos.db") as conexion:
        conexion.execute(
            "INSERT INTO contactos (nombre, email) VALUES (?, ?)",
            (nombre, email)
        )

Utiliza parámetros, nunca concatenes valores dentro del SQL. Crea una restricción única si no quieres correos duplicados y maneja los conflictos.

Mejorar SEO y accesibilidad

Incluye un título descriptivo, una meta descripción, encabezados en orden y texto alternativo en imágenes. Los botones y campos necesitan etiquetas visibles. Comprueba contraste, navegación con teclado y mensajes de error claros. Una página rápida y accesible suele convertir mejor que una página llena de animaciones.

Optimizar Tailwind para producción

En producción, instala Tailwind y configura las rutas de plantillas para eliminar clases no utilizadas. Mantén los estilos repetidos dentro de componentes o plantillas parciales. Evita construir nombres de clases dinámicamente de una forma que el compilador no pueda detectar.

Desplegar la aplicación

No utilices el servidor de desarrollo de Flask en producción. Ejecuta la aplicación con un servidor WSGI como Gunicorn o Waitress detrás de HTTPS. Configura variables de entorno, registros, límites de carga y una página de error. Antes de publicar, prueba el formulario, los mensajes, los enlaces y el diseño en móvil.

Errores frecuentes

Los fallos más comunes son dejar debug activo, confiar solo en la validación del navegador, guardar secretos en Git, usar el CDN de Tailwind como solución definitiva, no proteger el formulario contra bots y no ofrecer una política de privacidad. También debes evitar enviar correos directamente en la solicitud si el proveedor puede tardar; una cola de tareas mejora la respuesta.

Conclusión

Flask y Tailwind CSS permiten construir una landing page limpia con poco código. Flask gestiona rutas, plantillas y formularios, mientras Tailwind organiza el diseño responsivo. Para convertir el prototipo en una página confiable, valida datos en el servidor, protege secretos, controla bots, mejora accesibilidad y utiliza un despliegue apropiado. Con esta base puedes añadir una base de datos, analítica, correos y pruebas sin rehacer todo el proyecto.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Extração de dados de tabelas de sites usando Python e pandas
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo extraer tablas de sitios web con Python y Pandas

    Extrae tablas de sitios web con Pandas, Requests y Beautiful Soup, limpia columnas, pagina resultados y exporta datos de forma

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Integração de bots Discord com Python para automação
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear un bot de Discord con Python

    Crea un bot de Discord con Python y discord.py: comandos, slash commands, permisos, intents, Cogs, tareas, logs y seguridad del

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Conversão de áudio para texto usando Python gratuitamente
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo convertir audio a texto con Python gratis

    Convierte audio a texto con Python usando Whisper y SpeechRecognition, genera TXT y SRT, procesa carpetas y mejora privacidad y

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026
    Sistema de tradução automática desenvolvido com Python
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear un sistema de traducción automática con Python

    Crea un sistema de traducción automática con Python, APIs oficiales, variables de entorno, lotes, caché, reintentos y protección de marcadores.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026
    Gerenciador de senhas simples desenvolvido com Python
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear un gestor de contraseñas sencillo con Python

    Crea un gestor de contraseñas con Python, Fernet, secrets, JSON, getpass, derivación de claves, copias de seguridad y prácticas seguras.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026
    Geração automática de QR Code usando Python
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo generar códigos QR con Python paso a paso

    Genera códigos QR con Python y qrcode: tamaños, corrección de errores, colores, logotipos, lotes CSV, rutas seguras y validación.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026