Skip to content
Learni
Voir tous les tutoriels
Développement Frontend

Comment créer une landing page optimisée en 2026

Read in English

Introduction

En 2026, une landing page n'est plus un simple site vitrine : c'est une machine à conversions mesurable, avec un LCP sous 1 seconde, un CLS à zéro et une accessibilité WCAG 2.2 AA. Imaginez une page qui charge instantanément, anime ses éléments avec fluidité comme un mentor qui guide l'utilisateur vers le CTA principal, tout en capturant des leads qualifiés via un formulaire blindé contre les bots.

Ce tutoriel expert vous guide pas à pas pour créer une landing page SaaS fictive ('DevBoost AI') avec Next.js 15 (App Router), Tailwind CSS v4, animations CSS natives et un formulaire React Hook Form + Zod. On optimise pour le SEO (schema.org, OpenGraph), la performance (Image Next.js, lazy loading) et l'A/B testing prêt. Résultat : une page bookmarkable par tout lead dev, déployable en 5 min sur Vercel. Prêt à booster vos taux de conversion de 30% ? (132 mots)

Prérequis

  • Node.js 20+ et npm/yarn/pnpm
  • Connaissances avancées en React, TypeScript et Tailwind CSS
  • VS Code avec extensions Tailwind IntelliSense et ESLint
  • Compte Vercel pour déploiement (gratuit)
  • Outils Figma ou similaire pour mockups (optionnel)

Initialiser le projet Next.js

terminal
npx create-next-app@15 devboost-landing --typescript --tailwind --eslint --app --src-dir --import-alias "@/*"
cd devboost-landing
npm install react-hook-form @hookform/resolvers zod lucide-react
npm install -D @types/node

Cette commande crée un projet Next.js 15 minimal avec TypeScript, Tailwind et App Router. On ajoute React Hook Form pour les formulaires robustes, Zod pour la validation schema, et Lucide pour des icônes SVG légères. Évitez les templates turbopack si vous ciblez la stabilité prod.

Configurer Tailwind et globals

Tailwind v4 est maintenant recommandé pour sa compilation JIT ultra-rapide. On étend la config pour supporter les animations fluides et les breakpoints customisés adaptés aux landing pages (mobile-first). Les globals.css injectent des resets et variables CSS pour un thème sombre/clair toggleable.

tailwind.config.ts

tailwind.config.ts
import type { Config } from 'tailwindcss'

const config: Config = {
  content: [
    './src/pages/**/*.{js,ts,jsx,tsx,mdx}',
    './src/components/**/*.{js,ts,jsx,tsx,mdx}',
    './src/app/**/*.{js,ts,jsx,tsx,mdx}',
  ],
  theme: {
    extend: {
      animation: {
        'fade-in': 'fadeIn 1s ease-out forwards',
        'slide-up': 'slideUp 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards',
      },
      keyframes: {
        fadeIn: {
          '0%': { opacity: '0', transform: 'translateY(20px)' },
          '100%': { opacity: '1', transform: 'translateY(0)' },
        },
        slideUp: {
          '0%': { transform: 'translateY(50px)', opacity: '0' },
          '100%': { transform: 'translateY(0)', opacity: '1' },
        },
      },
      colors: {
        primary: {
          50: '#eff6ff',
          500: '#3b82f6',
          600: '#2563eb',
          900: '#1e3a8a',
        },
      },
    },
  },
  plugins: [],
}

export default config

Cette config étend Tailwind avec des animations keyframes custom pour un hero engageant sans JS lourd. Les couleurs primary sont brandables ; copiez-collez et adaptez. Piège : oubliez content paths, Tailwind ne purge pas vos classes.

globals.css et animations

src/app/globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  html {
    scroll-behavior: smooth;
  }
  body {
    @apply bg-gradient-to-br from-slate-50 to-blue-50 dark:from-slate-900 dark:to-slate-800;
  }
}

@layer components {
  .hero-gradient {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  }
  .glass {
    @apply backdrop-blur-md bg-white/80 dark:bg-slate-800/80 border border-white/20;
  }
}

[data-theme='dark'] {
  color-scheme: dark;
}

Les globals ajoutent un gradient hero pro, glassmorphism pour modernité 2026, et support thème sombre. Scroll smooth améliore l'UX navigation. Attention : testez sur mobile, backdrop-blur peut lag sur bas de gamme.

Layout principal avec SEO avancé

Le layout root gère les métadonnées dynamiques, fonts Google optimisées et providers pour thèmes/hydratation. On intègre Schema.org JSON-LD pour rich snippets Google, boostant CTR de 20%. Priorité : preload critical resources pour LCP optimal.

app/layout.tsx

src/app/layout.tsx
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import './globals.css'
import ThemeProvider from '@/components/ThemeProvider'

const inter = Inter({ subsets: ['latin'], display: 'swap', variable: '--font-inter' })

export const metadata: Metadata = {
  title: {
    default: 'DevBoost AI - Accélérez votre dev avec l\'IA',
    template: '%s | DevBoost AI',
  },
  description: 'Plateforme IA pour booster votre productivité dev. Créez des apps 10x plus vite en 2026.',
  keywords: 'landing page, IA dev, Next.js, Tailwind, SaaS',
  authors: [{ name: 'Learni Dev' }],
  creator: 'Learni Dev',
  openGraph: {
    type: 'website',
    locale: 'fr_FR',
    url: 'https://devboost.ai',
    siteName: 'DevBoost AI',
    title: 'DevBoost AI - Landing Page 2026',
    description: 'Boostez votre dev avec IA',
    images: [
      {
        url: 'https://devboost.ai/og-image.jpg',
        width: 1200,
        height: 630,
        alt: 'DevBoost AI',
      },
    ],
  },
  twitter: {
    card: 'summary_large_image',
    title: 'DevBoost AI',
    description: 'IA pour devs',
    images: ['https://devboost.ai/og-twitter.jpg'],
  },
  robots: {
    index: true,
    follow: true,
    googleBot: {
      index: true,
      follow: true,
      'max-video-preview': -1,
      'max-image-preview': 'large',
      'max-snippet': -1,
    },
  },
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="fr" suppressHydrationWarning>
      <head>
        <script
          type="application/ld+json"
          dangerouslySetInnerHTML={{
            __html: JSON.stringify({
              '@context': 'https://schema.org',
              '@type': 'WebSite',
              name: 'DevBoost AI',
              url: 'https://devboost.ai',
              potentialAction: {
                '@type': 'SearchAction',
                target: 'https://devboost.ai/search?q={search_term_string}',
                'query-input': 'required name=search_term_string',
              },
            }),
          }}
        />
      </head>
      <body className={`${inter.variable} font-sans antialiased`}>
        <ThemeProvider>{children}</ThemeProvider>
      </body>
    </html>
  )
}

Ce layout injecte metadata complètes pour SEO 2026 (OG2, robots avancés) et Schema.org. Inter font preloadée évite layout shift. Créez ThemeProvider séparé pour dark mode ; piège : suppressHydrationWarning pour thèmes toggle.

Hero section animée

src/components/Hero.tsx
import { Button } from '@/components/ui/button'
import { ArrowRight, Sparkles } from 'lucide-react'

export default function Hero() {
  return (
    <section className="min-h-screen flex flex-col justify-center items-center text-center px-4 py-20 hero-gradient text-white overflow-hidden">
      <div className="animate-fade-in">
        <div className="inline-flex items-center gap-2 mb-6 p-3 glass rounded-2xl shadow-2xl">
          <Sparkles className="w-6 h-6" />
          <span className="text-sm font-medium">Nouveau : IA Générative 2026</span>
        </div>
        <h1 className="text-6xl md:text-7xl lg:text-8xl font-black leading-tight mb-8 bg-gradient-to-r from-white to-blue-200 bg-clip-text text-transparent drop-shadow-2xl">
          Accélérez votre<br />
          <span className="text-transparent bg-gradient-to-r from-yellow-300 to-orange-400 bg-clip-text">dev x10</span>
        </h1>
        <p className="text-xl md:text-2xl text-blue-100 max-w-3xl mx-auto mb-12 leading-relaxed animate-slide-up animation-delay-300">
          DevBoost AI transforme vos idées en code production-ready. Zéro boilerplate, 100% TypeScript.
        </p>
        <div className="flex flex-col sm:flex-row gap-4 justify-center items-center animate-slide-up animation-delay-600">
          <Button size="lg" className="group bg-white text-slate-900 font-bold px-12 py-6 text-lg shadow-2xl hover:shadow-3xl transition-all duration-300 transform hover:-translate-y-1 hover:scale-105">
            Démarrer gratuitement
            <ArrowRight className="ml-2 w-5 h-5 group-hover:translate-x-1 transition-transform" />
          </Button>
          <Button variant="ghost" size="lg" className="border-white/50 text-white hover:bg-white/10 px-12 py-6 text-lg">
            Voir la démo
          </Button>
        </div>
      </div>
      <div className="absolute bottom-10 left-1/2 -translate-x-1/2 animate-pulse">
        <svg className="w-8 h-8 text-white/70" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 14l-7 7m0 0l-7-7m7 7V3" />
        </svg>
      </div>
    </section>
  )
}

Hero full-screen avec gradient 135°, animations staggered (fade-in/slide-up via CSS). Glass badge pour modernité. CTA sticky hover 3D ; optimisé mobile. Piège : overflow-hidden évite clip gradient sur petits écrans.

Sections Features et Testimonials

Les features utilisent grid responsive avec icônes Lucide pour scanabilité. Testimonials en carousel CSS-only (pas de JS pour perf). Lazy loading natif Next.js pour images.

Features section

src/components/Features.tsx
import { Code, Zap, Shield, Rocket } from 'lucide-react'

export default function Features() {
  return (
    <section id="features" className="py-32 px-4 max-w-7xl mx-auto">
      <div className="text-center mb-24 animate-fade-in">
        <h2 className="text-5xl font-black bg-gradient-to-r from-slate-900 to-slate-700 bg-clip-text text-transparent mb-6">
          Pourquoi DevBoost ?
        </h2>
        <p className="text-xl text-slate-600 max-w-2xl mx-auto">
          Fonctionnalités qui font la différence pour les devs pros.
        </p>
      </div>
      <div className="grid md:grid-cols-2 lg:grid-cols-4 gap-8">
        {[
          { icon: Code, title: 'Code IA Instantané', desc: 'Générez des composants React/Next complets en 3s.' },
          { icon: Zap, title: 'Perf Maximale', desc: 'Optimisations Core Web Vitals automatiques.' },
          { icon: Shield, title: 'Sécurité Intégrée', desc: 'Zod validation + OWASP top10 compliance.' },
          { icon: Rocket, title: 'Déploiement 1-Click', desc: 'Vercel/Netlify ready out-of-box.' },
        ].map((feature, i) => (
          <div key={i} className="group p-8 glass rounded-3xl hover:shadow-2xl transition-all duration-500 hover:-translate-y-4 animate-slide-up" style={{ animationDelay: `${i * 100}ms` }}>
            <feature.icon className="w-16 h-16 text-primary-500 mb-6 group-hover:scale-110 transition-transform" />
            <h3 className="text-2xl font-bold text-slate-900 mb-4 group-hover:text-primary-600 transition-colors">
              {feature.title}
            </h3>
            <p className="text-slate-600 leading-relaxed">
              {feature.desc}
            </p>
          </div>
        ))}
      </div>
    </section>
  )
}

Grid 4-cols responsive avec hover lift 3D et stagger delay CSS. Icônes scalables pour focus. Glass effet pour profondeur ; testez hover mobile (tap feedback). Piège : style inline pour delay unique par élément.

Testimonials carousel

src/components/Testimonials.tsx
import { Star } from 'lucide-react'

export default function Testimonials() {
  return (
    <section id="testimonials" className="py-32 px-4 bg-gradient-to-r from-blue-50 to-indigo-50 dark:from-slate-800 dark:to-slate-900">
      <div className="max-w-4xl mx-auto text-center mb-24 animate-fade-in">
        <h2 className="text-5xl font-black text-slate-900 mb-6">Ce que disent nos users</h2>
        <p className="text-xl text-slate-600">+10k devs boostés</p>
      </div>
      <div className="relative max-w-2xl mx-auto">
        <div className="overflow-hidden rounded-3xl glass shadow-2xl">
          <div className="flex transition-transform duration-500 ease-in-out snap-x snap-mandatory scrollbar-none" style={{ scrollSnapType: 'x mandatory' }}>
            {[
              { name: 'Marie D., CTO @TechCorp', text: 'Réduit mon time-to-market de 70%. Indispensable !', rating: 5 },
              { name: 'Pierre L., Freelance Dev', text: 'IA qui comprend mes specs TS. Magique en 2026.', rating: 5 },
              { name: 'Lucie R., Lead Frontend', text: 'Tailwind + Next perf parfaite. Zéro lag.', rating: 5 },
            ].map((t, i) => (
              <div key={i} className="w-full p-12 flex-shrink-0 snap-center">
                <div className="flex gap-1 mb-6 justify-center">
                  {Array.from({ length: t.rating }).map((_, j) => (
                    <Star key={j} className="w-6 h-6 fill-yellow-400 text-yellow-400" />
                  ))}
                </div>
                <p className="text-2xl italic text-slate-700 mb-8">“{t.text}”</p>
                <p className="font-semibold text-slate-900">{t.name}</p>
              </div>
            ))}
          </div>
        </div>
        <button className="absolute -left-4 top-1/2 -translate-y-1/2 w-12 h-12 glass rounded-full flex items-center justify-center shadow-lg hover:shadow-xl transition-all">
          ‹
        </button>
        <button className="absolute -right-4 top-1/2 -translate-y-1/2 w-12 h-12 glass rounded-full flex items-center justify-center shadow-lg hover:shadow-xl transition-all">
          ›
        </button>
      </div>
    </section>
  )
}

Carousel CSS-only avec snap-scroll pour perf max (pas de IntersectionObserver). Boutons nav glass. Ajoutez JS pour auto-scroll si besoin ; piège : flex-shrink-0 pour full-width slides.

Formulaire CTA avec validation

Le CTA final capture leads avec validation Zod side+server. Intégrez EmailJS ou Supabase pour prod. Honeypot anti-spam inclus.

CTA Form component

src/components/CTAForm.tsx
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
import { Button } from '@/components/ui/button'
import { Mail, Send } from 'lucide-react'

const schema = z.object({
  email: z.string().email('Email invalide').min(1, 'Email requis'),
  name: z.string().min(2, 'Nom trop court'),
  honeypot: z.string().optional(),
}).refine((data) => data.honeypot?.length === 0, {
  message: 'Bot détecté',
  path: ['honeypot'],
})

type FormData = z.infer<typeof schema>

export default function CTAForm() {
  const {
    register,
    handleSubmit,
    formState: { errors, isSubmitting },
    reset,
  } = useForm<FormData>({ resolver: zodResolver(schema) })

  const onSubmit = async (data: FormData) => {
    // Intégrez EmailJS ou API ici
    console.log('Lead:', data)
    reset()
    alert('Inscrit !')
  }

  return (
    <section id="cta" className="py-32 px-4 bg-gradient-to-br from-primary-600 to-primary-900 text-white">
      <div className="max-w-md mx-auto text-center animate-slide-up">
        <h2 className="text-4xl font-black mb-6">Prêt à booster ?</h2>
        <p className="text-xl mb-12 text-blue-100">Inscrivez-vous gratuitement</p>
        <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
          <input
            type="text"
            placeholder="Votre nom"
            className="w-full p-4 rounded-2xl text-lg bg-white/20 backdrop-blur border border-white/30 focus:border-white focus:outline-none transition-all"
            {...register('name')}
          />
          {errors.name && <p className="text-red-300 text-sm">{errors.name.message}</p>}
          <input
            type="email"
            placeholder="votre@email.com"
            className="w-full p-4 rounded-2xl text-lg bg-white/20 backdrop-blur border border-white/30 focus:border-white focus:outline-none transition-all"
            {...register('email')}
          />
          {errors.email && <p className="text-red-300 text-sm">{errors.email.message}</p>}
          <input type="text" tabIndex={-1} autoComplete="off" className="hidden" {...register('honeypot')} />
          <Button
            type="submit"
            disabled={isSubmitting}
            className="w-full bg-white text-primary-900 font-bold py-6 text-xl shadow-2xl hover:shadow-3xl transition-all hover:scale-105"
          >
            {isSubmitting ? 'Envoi...' : 'Commencer gratuitement'}
            <Send className="ml-2 w-6 h-6" />
          </Button>
        </form>
      </div>
    </section>
  )
}

Zod schema strict avec honeypot anti-bot. RHF gère states sans re-renders inutiles. Glass inputs focus states ; intégrez vraie API dans onSubmit. Piège : tabIndex=-1 cache honeypot des screen readers.

Page principale assemblée

src/app/page.tsx
import Hero from '@/components/Hero'
import Features from '@/components/Features'
import Testimonials from '@/components/Testimonials'
import CTAForm from '@/components/CTAForm'

export default function Home() {
  return (
    <>
      <Hero />
      <Features />
      <Testimonials />
      <CTAForm />
    </>
  )
}

Page root assemble components avec fragments pour perf. Ajoutez et

en prod. Zéro wrapper divs = CLS zéro. Lancez npm run dev pour tester.

Déploiement et métriques

Vercel : npm run build && vercel --prod. Vérifiez Lighthouse : visez 100/100 perf/accessibilité. Ajoutez next/image pour hero bg lazy.

Bonnes pratiques

  • Mobile-first : Testez sur Chrome DevTools throttled 3G + CPU 4x slowdown.
  • A11y : ARIA labels sur icônes, focus-visible custom, skip-to-content link.
  • Perf : Preload fonts/hero image, code-split components avec dynamic imports.
  • SEO : H1 unique, structured data, hreflang pour i18n.
  • Analytics : Intégrez PostHog ou GA4 events sur CTA submit/scroll.

Erreurs courantes à éviter

  • Animations JS-heavy : Préférez CSS @keyframes ; Framer Motion gonfle bundle 50kb+.
  • Hero trop lourd : Pas de vidéo bg sans lazy+muted ; gradient CSS suffit.
  • Form sans server validation : Zod client-only = vulnérable ; doublez avec API.
  • Oubli CLS : Fixez hero height min-h-screen + font-display=swap.

Pour aller plus loin

  • Optimisez avec Partytown pour 3rd-party scripts.
  • A/B testez via Vercel Edge Config.
  • PWA manifest pour installabilité.
Découvrez nos formations Next.js avancées et formations Tailwind Pro. Suivez @LearniDev pour 2026 trends.