Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Para crear un sitio con páginas de Inicio, Nosotros, Servicios, Blog y Contacto en Angular, configura varias rutas y muestra cada vista en un <router-outlet>, con una cabecera y un pie compartidos. En un proyecto nuevo, lo más práctico es usar componentes standalone y cargar las páginas de forma diferida. Eso suele producir una aplicación de una sola página (SPA) con varias URL, no un conjunto tradicional de archivos HTML independientes.

Si por «páginas completas» te refieres a secciones que ocupan toda la pantalla, también puedes darles una altura mínima de 100dvh. Este tutorial cubre ambas interpretaciones y explica cuándo elegir renderizado en el navegador, prerenderizado o renderizado en servidor.

Qué vas a construir

El resultado será un sitio organizado con rutas para Inicio, Nosotros, Servicios, Blog, Contacto y una página 404. El menú y el pie de página se mantienen mientras Angular cambia el componente dentro del área principal.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<header>...</header>
<main>
  <router-outlet />
</main>
<footer>...</footer>

En una web multipágina tradicional, cada navegación suele solicitar otro documento HTML al servidor. En la configuración habitual de Angular, el navegador carga la aplicación y el router cambia las vistas. Las URL siguen siendo distintas y pueden compartirse, pero el servidor debe estar preparado para responder correctamente cuando alguien abre o actualiza una ruta directamente.

1. Comprueba los requisitos y crea el proyecto

Necesitas Node.js compatible con la versión de Angular que vayas a usar, npm y Angular CLI. Como las versiones compatibles cambian, consulta la documentación oficial de Angular antes de instalar. Comprueba tus herramientas con:

node --version
npm --version
ng version

Crea y ejecuta el proyecto:

npm install -g @angular/cli
ng new sitio-angular
cd sitio-angular
ng serve --open

El CLI puede presentar preguntas interactivas y sus opciones pueden variar entre versiones. Para empezar directamente con soporte de renderizado en servidor y prerenderizado, Angular permite crear un proyecto con:

ng new sitio-angular --ssr

También es posible añadir SSR a un proyecto existente con ng add @angular/ssr. No es un requisito para configurar rutas; elige esta opción si el sitio necesita HTML generado antes de llegar al navegador. Consulta las guías de prerenderizado y SSR de Angular para el flujo correspondiente a tu versión.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

2. Organiza páginas y elementos compartidos

Para un proyecto pequeño, una estructura como esta separa las vistas de la presentación común y la lógica reutilizable:

src/app/
├── core/       # servicios singleton, guards e interceptores
├── layout/     # cabecera, pie y estructura del sitio
├── pages/      # componentes vinculados a rutas
├── shared/     # piezas reutilizables
├── app.component.ts
├── app.config.ts
└── app.routes.ts

Los proyectos nuevos de Angular suelen usar componentes standalone: cada componente declara directamente las dependencias que utiliza. Los NgModule siguen siendo relevantes en aplicaciones existentes; no hace falta migrar todo un proyecto solo para añadir páginas. Angular ofrece una migración a standalone para quienes decidan hacerlo gradualmente.

Genera las vistas que utilizarás:

ng generate component pages/home
ng generate component pages/about
ng generate component pages/services
ng generate component pages/blog
ng generate component pages/contact
ng generate component pages/not-found

Un componente de página debería tener un título principal, contenido con estructura semántica y, si carga datos, estados claros de carga y error. Por ejemplo:

import { Component } from '@angular/core';
import { RouterLink } from '@angular/router';

@Component({
  selector: 'app-home',
  standalone: true,
  imports: [RouterLink],
  template: `
    <section class="hero">
      <p>Sitio Angular</p>
      <h1>Construye una web clara y mantenible</h1>
      <p>Presenta tus servicios, contenido y formas de contacto.</p>
      <a routerLink="/contacto">Contactar</a>
    </section>
  `,
})
export class HomeComponent {}

3. Configura las rutas

En src/app/app.routes.ts, declara una ruta para cada página. loadComponent importa el componente cuando se necesita y permite cargar las páginas standalone de forma diferida:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option
import { Routes } from '@angular/router';

export const routes: Routes = [
  {
    path: '',
    title: 'Inicio | Mi sitio',
    loadComponent: () => import('./pages/home/home.component')
      .then(m => m.HomeComponent),
  },
  {
    path: 'nosotros',
    title: 'Nosotros | Mi sitio',
    loadComponent: () => import('./pages/about/about.component')
      .then(m => m.AboutComponent),
  },
  {
    path: 'servicios',
    title: 'Servicios | Mi sitio',
    loadComponent: () => import('./pages/services/services.component')
      .then(m => m.ServicesComponent),
  },
  {
    path: 'blog',
    title: 'Blog | Mi sitio',
    loadComponent: () => import('./pages/blog/blog.component')
      .then(m => m.BlogComponent),
  },
  {
    path: 'contacto',
    title: 'Contacto | Mi sitio',
    loadComponent: () => import('./pages/contact/contact.component')
      .then(m => m.ContactComponent),
  },
  {
    path: '**',
    loadComponent: () => import('./pages/not-found/not-found.component')
      .then(m => m.NotFoundComponent),
  },
];

La ruta comodín ** debe ir al final: captura las URL que no coinciden con las anteriores. Registra las rutas en src/app/app.config.ts:

import { ApplicationConfig } from '@angular/core';
import { provideRouter, withInMemoryScrolling } from '@angular/router';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(
      routes,
      withInMemoryScrolling({
        scrollPositionRestoration: 'enabled',
        anchorScrolling: 'enabled',
      }),
    ),
  ],
};

La ruta de inicio usa una cadena vacía (''); por eso, en una navegación, conviene marcarla como activa solo cuando la coincidencia sea exacta.

4. Añade el layout y la navegación

La plantilla raíz aloja el contenido compartido y el punto donde aparece la página seleccionada:

<!-- app.component.html -->
<a class="skip-link" href="#main-content">Saltar al contenido</a>
<app-header />
<main id="main-content" tabindex="-1">
  <router-outlet />
</main>
<app-footer />

La clase del componente raíz debe importar RouterOutlet, además de los componentes de cabecera y pie:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { HeaderComponent } from './layout/header/header.component';
import { FooterComponent } from './layout/footer/footer.component';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet, HeaderComponent, FooterComponent],
  templateUrl: './app.component.html',
})
export class AppComponent {}

En la cabecera usa routerLink para navegación interna, no un href que provoque una navegación de documento. Importa también RouterLinkActive para resaltar la ruta actual:

<header class="site-header">
  <a class="logo" routerLink="/">Mi sitio</a>
  <nav aria-label="Navegación principal">
    <a routerLink="/" routerLinkActive="active"
       [routerLinkActiveOptions]="{ exact: true }">Inicio</a>
    <a routerLink="/nosotros" routerLinkActive="active">Nosotros</a>
    <a routerLink="/servicios" routerLinkActive="active">Servicios</a>
    <a routerLink="/blog" routerLinkActive="active">Blog</a>
    <a routerLink="/contacto" routerLinkActive="active">Contacto</a>
  </nav>
</header>

El componente de cabecera debe importar RouterLink y RouterLinkActive. Usa elementos semánticos, un foco visible y no señales la ruta activa solo con color. Si el menú se convierte en un control móvil desplegable, constrúyelo con un botón de verdad y comprueba navegación por teclado, estado aria-expanded y cierre con Escape cuando corresponda.

5. Aplica una base responsive

Los estilos globales van en src/styles.css; las reglas propias de una vista pueden vivir en los estilos de su componente. Una base sencilla:

Rank #3
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • Brand: Wiley
  • Set of 2 Volumes
  • A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
:root {
  --color-text: #172033;
  --color-primary: #2563eb;
  --content-width: 72rem;
}

* { box-sizing: border-box; }
body {
  margin: 0;
  color: var(--color-text);
  font-family: system-ui, sans-serif;
}
img { display: block; max-width: 100%; height: auto; }
.container {
  width: min(calc(100% - 2rem), var(--content-width));
  margin-inline: auto;
}
.skip-link {
  position: absolute;
  transform: translateY(-200%);
}
.skip-link:focus { transform: translateY(0); }

Optimiza imágenes y comprueba el sitio en pantallas estrechas. Para una sección que ocupe al menos la altura visible, puedes usar:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
.full-page {
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  place-items: center;
}

La segunda declaración aprovecha las unidades dinámicas de viewport, que pueden adaptarse mejor a las barras del navegador móvil; la primera queda como alternativa. Una página de pantalla completa es una decisión de diseño CSS: no es lo mismo que tener múltiples rutas.

6. Valida un formulario de contacto

Los formularios reactivos facilitan declarar reglas de validación y mostrar errores asociados a cada campo:

import { Component, inject } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';

@Component({
  selector: 'app-contact',
  standalone: true,
  imports: [ReactiveFormsModule],
  templateUrl: './contact.component.html',
})
export class ContactComponent {
  private readonly fb = inject(FormBuilder);

  readonly contactForm = this.fb.nonNullable.group({
    name: ['', [Validators.required, Validators.minLength(2)]],
    email: ['', [Validators.required, Validators.email]],
    message: ['', [Validators.required, Validators.minLength(20)]],
  });

  submit(): void {
    if (this.contactForm.invalid) {
      this.contactForm.markAllAsTouched();
      return;
    }
    const value = this.contactForm.getRawValue();
    // Envía value a una API o función segura.
  }
}
<form [formGroup]="contactForm" (ngSubmit)="submit()">
  <label for="name">Nombre</label>
  <input id="name" type="text" formControlName="name">
  @if (contactForm.controls.name.touched && contactForm.controls.name.invalid) {
    <p role="alert">Escribe un nombre de al menos dos caracteres.</p>
  }

  <label for="email">Correo electrónico</label>
  <input id="email" type="email" formControlName="email">
  @if (contactForm.controls.email.touched && contactForm.controls.email.invalid) {
    <p role="alert">Introduce un correo válido.</p>
  }

  <label for="message">Mensaje</label>
  <textarea id="message" formControlName="message"></textarea>
  <button type="submit">Enviar mensaje</button>
</form>

La validación en el navegador mejora la experiencia, pero no sustituye la validación del servidor. Angular tampoco envía el correo por sí solo: necesitas una API, una función serverless o un proveedor de formularios. No incluyas credenciales privadas en el código que se descarga al navegador.

7. Conecta una API si las páginas usan datos dinámicos

Configura HttpClient como proveedor en app.config.ts:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import { provideHttpClient } from '@angular/common/http';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideHttpClient(),
  ],
};

Centraliza las solicitudes en un servicio en lugar de dispersarlas por las plantillas. Gestiona en la interfaz carga, éxito y error; la URL de la API puede diferir entre desarrollo y producción. Todo valor incluido en el bundle del navegador debe considerarse público: guarda claves privadas y tokens administrativos en el servidor. Si utilizas SSR o prerenderizado, revisa además cómo y cuándo se realizan esas solicitudes.

8. Decide cómo se renderiza cada ruta

Las rutas de Angular pueden entregarse de distintas formas. La elección afecta el HTML inicial, el hosting y la actualización del contenido:

Modelo Cómo funciona Puede encajar en
CSR El navegador carga JavaScript y Angular renderiza la vista. Paneles e interfaces autenticadas donde el SEO no sea prioritario.
SSR El servidor genera HTML para cada solicitud. Páginas que dependen del usuario, la solicitud o datos dinámicos.
SSG o prerenderizado Angular genera archivos HTML durante la compilación. Sitios corporativos, documentación y contenido relativamente estable.
Híbrido Se elige una estrategia por ruta. Sitios donde algunas páginas son estáticas y otras dinámicas.

CSR es el comportamiento habitual si no se configura renderizado adicional. Prerenderizar puede simplificar la entrega de páginas estables mediante hosting estático; SSR puede servir cuando cada respuesta debe depender de la solicitud. Ninguna estrategia garantiza por sí sola buen rendimiento o SEO: también importan el contenido, la caché, el JavaScript, los metadatos y la configuración del servidor. Angular describe estas opciones en sus guías de estrategias de renderizado y prerenderizado.

Para un sitio estático, Angular documenta outputMode: "static": produce archivos prerenderizados y no requiere un servidor Node para servir la aplicación. Eso no elimina la posible necesidad de servicios externos para formularios, APIs o analítica. SSR, en cambio, requiere que el entorno de despliegue pueda ejecutar el servidor o runtime correspondiente.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Rutas de blog con parámetros

Una entrada de blog puede tener una URL como /blog/mi-primer-articulo. Declara una ruta con parámetro:

{
  path: 'blog/:slug',
  loadComponent: () => import('./pages/blog-post/blog-post.component')
    .then(m => m.BlogPostComponent),
}

El componente debe leer slug y cargar la entrada correspondiente. Para prerenderizar estas páginas, los slugs deben conocerse al compilar; si el contenido se crea continuamente o depende de datos por solicitud, evalúa SSR o una estrategia adecuada a tu fuente de contenido. Un blog que deban actualizar personas no técnicas también puede necesitar un CMS: Angular no incluye por sí mismo un panel editorial ni una base de datos.

9. Define títulos y metadatos

El campo title de cada ruta ofrece títulos distintos en el navegador. Para una descripción y metadatos adicionales, usa Meta y Title:

import { Component, inject } from '@angular/core';
import { Meta, Title } from '@angular/platform-browser';

@Component({
  selector: 'app-about',
  standalone: true,
  template: '<h1>Nosotros</h1>',
})
export class AboutComponent {
  private readonly title = inject(Title);
  private readonly meta = inject(Meta);

  constructor() {
    this.title.setTitle('Nosotros | Mi sitio');
    this.meta.updateTag({
      name: 'description',
      content: 'Conoce la historia y el equipo de Mi sitio.',
    });
    this.meta.updateTag({
      property: 'og:title',
      content: 'Nosotros | Mi sitio',
    });
  }
}

El SEO no se resuelve con una etiqueta aislada. Revisa que cada página tenga un título y una descripción apropiados, un encabezado principal claro, contenido útil, enlaces internos, URLs estables e imágenes con texto alternativo. Para un sitio público considera también las URL canónicas, un sitemap y robots.txt. Si necesitas que motores y otros clientes reciban HTML inicial con contenido, verifica el resultado servido con la estrategia CSR, SSR o prerenderizado que hayas elegido; tener rutas no garantiza por sí solo que el HTML inicial sea suficiente.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

10. Compila y prepara el despliegue

Genera la compilación de producción con:

ng build

Angular CLI compila y optimiza la aplicación según el target y builder configurados. La ubicación exacta de salida depende del proyecto, la versión y si compilas una aplicación solo de navegador o una configuración SSR/prerenderizada. Usa la ruta que informa el CLI, en lugar de asumir que siempre será una carpeta concreta. Para revisar una salida estática en local puedes servir la carpeta generada con una herramienta de servidor estático, por ejemplo:

npx serve dist/sitio-angular/browser

Ajusta esa ruta al directorio real de tu build. Un hosting de SPA debe devolver el documento de entrada para rutas que el router resuelve en el navegador. Si publicas HTML prerenderizado, configura el hosting para servir esos archivos generados. Si usas SSR, despliega también el servidor Angular en una plataforma que pueda ejecutarlo.

Por qué actualizar una ruta puede devolver 404

La navegación desde la página de inicio puede funcionar porque Angular ya está cargado. Pero al refrescar /nosotros, el navegador solicita esa URL al servidor. Si este no encuentra un archivo ni tiene una regla adecuada, responde 404 antes de que Angular pueda intervenir.

  • SPA con CSR: configura un fallback del hosting a index.html.
  • Prerenderizado: publica los HTML generados y configura el proveedor para servir las rutas correspondientes.
  • SSR: asegúrate de que el servidor de la aplicación recibe esas solicitudes.

Un fallback a index.html soluciona la navegación de una SPA, pero no genera un HTML prerenderizado independiente para cada URL. Prueba escribiendo directamente en el navegador cada ruta pública y luego actualizándola.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Publicar en una subcarpeta

Si el sitio se sirve bajo una ruta como /mi-sitio/, el base-href debe reflejarlo al compilar:

ng build --base-href /mi-sitio/

Después comprueba que funcionan enlaces, imágenes, favicon y estilos; revisa también URL canónicas y reglas del servidor. No añadas opciones de rutas de recursos sin una necesidad concreta.

11. Errores habituales y cómo encontrarlos

  • El menú cambia la URL, pero no aparece el componente: comprueba que existe <router-outlet>, que las rutas están registradas y que el nombre exportado coincide con el usado en loadComponent.
  • routerLink o router-outlet aparece como desconocido: en componentes standalone, importa la directiva o componente de @angular/router que la plantilla utiliza.
  • Siempre se muestra la página 404: revisa la ruta solicitada y confirma que el comodín ** está después de las rutas concretas.
  • Una ruta falla al actualizar o abrirse directamente: configura fallback SPA, entrega de archivos prerenderizados o SSR, según corresponda.
  • Una página prerenderizada aparece sin datos: la API quizá no esté disponible durante el build, la ruta dinámica quizá no tenga parámetros conocidos o el código puede depender de window, document o almacenamiento del navegador. El código que se ejecuta en servidor o durante prerenderizado no debe presuponer APIs exclusivas del navegador.
  • Los recursos fallan en producción: comprueba la URL base, las rutas de assets y el destino de compilación, especialmente si publicas en una subcarpeta.
  • Se filtra una clave: cualquier valor enviado al navegador es visible; mueve secretos a un backend o función segura.

¿Cuándo conviene usar Angular?

Angular encaja cuando el sitio necesita muchas vistas reutilizables, formularios complejos, datos dinámicos, autenticación o convenciones consistentes para un equipo. Puede ser más complejidad de la necesaria para una landing estática o una web editorial pequeña: HTML tradicional o un generador estático puede entregar una solución más sencilla y con menos JavaScript. Si el contenido lo mantiene un equipo no técnico, contempla además un CMS; el framework no proporciona por sí solo herramientas editoriales.

Empieza con rutas standalone y layout compartido; luego elige el renderizado por los requisitos reales de cada página. Para contenido estable y hosting estático, evalúa prerenderizado. Para datos personalizados por solicitud, considera SSR. Para una interfaz privada donde la indexación no importa, CSR puede bastar. Angular permite combinar estrategias, pero esa flexibilidad añade decisiones de compilación y despliegue que conviene asumir solo cuando resuelven una necesidad concreta.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.